feat(frontend): agent resource sections

This commit is contained in:
Shivering Ocelot committed 2026-06-06 21:56:12 -05:00
1 parent a10224d21e
commit 6134c026a6
3 files changed
+82 -80

No files matched your search

+7 -3
View File
@@ -285,9 +285,13 @@ class App(ChatMixin):
# --- Resource Management --- # --- Resource Management ---
async def get_agent_resource(self, agent_id, kind, key): async def get_agent_resources(self, agent_id, kind=None, key=None):
resource = await db.AgentResource.get_or_none(agent_id=agent_id, kind=kind, key=key) filter = {"agent_id": agent_id}
return resource.value if resource else None if kind: filter['kind'] = kind
if key: filter['key'] = key
values = await db.AgentResource.filter(**filter)
return values
async def save_agent_resource(self, agent_id, kind, key, value): async def save_agent_resource(self, agent_id, kind, key, value):
await db.AgentResource.update_or_create( await db.AgentResource.update_or_create(
+8
View File
@@ -223,6 +223,14 @@ async def start_server(app):
elif action == "get-agents": elif action == "get-agents":
await send({'message': "agents retrieved", 'agents': await app.get_agents(user_id), 'nonce': nonce}) await send({'message': "agents retrieved", 'agents': await app.get_agents(user_id), 'nonce': nonce})
elif action == "get-agent-resources":
values = await app.get_agent_resources(body['agentId'], body.get('kind'), body.get('key'))
await send({'resources': [{'kind': r.kind, 'key': r.key, 'value': r.value} for r in values], 'nonce': nonce})
elif action == "save-agent-resource":
await app.save_agent_resource(body['agentId'], body['kind'], body['key'], body['value'])
await send({'message': "resource saved", 'nonce': nonce})
elif action == "get-agent-runs": elif action == "get-agent-runs":
await send({ await send({
'runs': await app.get_agent_runs(agent_id=body.get('agentId'), user_id=user_id), 'runs': await app.get_agent_runs(agent_id=body.get('agentId'), user_id=user_id),
+67 -77
View File
@@ -16,13 +16,17 @@
}, },
}); });
// Data
const agent = ref({}); const agent = ref({});
const kindInfo = ref({}); const kindInfo = ref({});
const configFields = ref([]); const configFields = ref([]);
// Only used for scripted agents. const resources = ref([]);
const actionDefinitions = ref([]); const tools = ref([]);
const modelList = ref([]); const modelList = ref([]);
// UI State
const addingTool = ref(null);
const addingResource = ref(null);
// === State Management === // // === State Management === //
@@ -59,18 +63,12 @@
default: null, default: null,
enabled: field.value != null, enabled: field.value != null,
})); }));
});
if (dataObject.actions) { // Replace with a backend call
actionDefinitions.value = dataObject.actions.map(name => { backend.sendAction('get-agent-resources', {agentId}).then(res => {
const fieldName = 'action_' + name; tools.value = res.resources.filter(r => r.kind == 'tool');
const fieldData = dataObject[fieldName]; resources.value = res.resources.filter(r => !['tool', 'config'].includes(r.kind));
return {
name,
argument: fieldData ? JSON.stringify(fieldData.argument) : "{}",
body: fieldData && fieldData.body || "pass",
}
});
}
}); });
} }
@@ -230,57 +228,34 @@
} }
} }
// == Scripted Agent Actions == // async function saveAddingTool() {
function createAction () { let resource = {
const value = prompt(`Enter an identifier for the new action`); kind: 'tool',
if (value) { key: addingTool.value.name,
const def = { value: JSON.parse(addingTool.value.value),
name: value, };
argument: "{}", addingTool.value = null;
body: "pass",
}; let res = await backend.sendAction("save-agent-resource", {
const actionsField = configFields.value.find(field => field.name == 'actions'); agentId: agent.value.id,
if (actionsField) { ...resource
actionsField.value.push(def.name); });
} else { tools.value.push(resource);
configFields.value.push({
name: def.name,
value: [def.name],
enabled: true,
});
}
saveAction(def);
} else {
ui.alert('Action creation cancelled');
}
} }
// Update the config fields relevant to the action and saves changes automatically. Doesn't update 'actions'.
function saveAction (actionDef) {
let argSchema;
try {
argSchema = JSON.parse(actionDef.argument);
} catch (e) {
ui.alert("Bad Argument JSON: " + e.message);
return;
}
const fieldName = 'action_' + actionDef.name; async function saveAddingResource() {
const actionField = configFields.value.find(field => field.name == fieldName); let resource = {
if (actionField) { kind: addingResource.value.kind,
actionField.arguments = argSchema; key: addingResource.value.key,
actionField.body = actionDef.body; value: JSON.parse(addingResource.value.value),
} else { };
configFields.value.push({ addingResource.value = null;
name: fieldName,
value: {
argument: argSchema,
body: actionDef.body,
},
enabled: true,
});
}
saveChanges(); let res = await backend.sendAction("save-agent-resource", {
agentId: agent.value.id,
...resource
});
resources.value.push(resource);
} }
</script> </script>
@@ -339,22 +314,6 @@
</div> </div>
</section> </section>
<template v-if="actionDefinitions && kindInfo.name == 'scripted'">
<section v-for="(actionDef, index) in actionDefinitions" :key="index">
<h3>Action {{actionDef.name}}</h3>
<span class="label">argument</span>
<br>
<textarea v-model="actionDef.argument" class="config-input"/>
<br>
<span class="label">body</span>
<br>
<textarea v-model="actionDef.body" class="config-input"/>
<button @click="saveAction(actionDef)">Save Action</button>
</section>
<section>
<button @click="createAction()">Create Action</button>
</section>
</template>
<section> <section>
<div v-for="(configField, index) in configFields" :key="index"> <div v-for="(configField, index) in configFields" :key="index">
<span class="label">{{ configField.name }}</span> <span class="label">{{ configField.name }}</span>
@@ -370,6 +329,37 @@
<button type="submit" @click="saveChanges()">Save</button> <button type="submit" @click="saveChanges()">Save</button>
</section> </section>
<section>
<h3>Tools</h3>
<div v-for="(resource, index) in tools">
<div class="label">{{ resource.key }}</div>
<pre>{{ JSON.stringify(resource.value, null, 2) }}</pre>
</div>
<section v-if="addingTool">
<input v-model="addingTool.name" placeholder="name"><br>
<textarea v-model="addingTool.value" placeholder="{}"></textarea>
<br>
<button @click="saveAddingTool()">Save</button>
<button @click="addingTool=null">Cancel</button>
</section>
<div v-else><button @click="addingTool={}">Add Tool</button></div>
</section>
<section>
<h3>Resources</h3>
<div v-for="resource in resources">
<div class="label">{{ resource.kind }}:{{ resource.key }}</div>
<pre>{{ JSON.stringify(resource.value, null, 2) }}</pre>
</div>
<section v-if="addingResource">
<input v-model="addingResource.kind" placeholder="kind/domain"><br>
<input v-model="addingResource.key" placeholder="key"><br>
<textarea v-model="addingResource.value" placeholder="value"></textarea>
<br>
<button @click="saveAddingResource()">Save</button>
<button @click="addingResource=null">Cancel</button>
</section>
<div v-else><button @click="addingResource={}">Add Resource</button></div>
</section>
</main> </main>
</template> </template>