Scripted Agent WIP, only definitions

This commit is contained in:
Shivering Ocelot committed 2025-09-08 13:48:11 -05:00
1 parent 13e7c12e75
commit 5efe4f3325
4 files changed
+121

No files matched your search

+1
View File
@@ -1,2 +1,3 @@
from .character import CharacterAgent
from .expert import ExpertAgent
from .scripted import ScriptedAgent
+31
View File
@@ -0,0 +1,31 @@
import re
import json
import inspect
from string import Template
from inference import LlamaMessage, replicate_llama_completion, Models
from agent import Agent, AgentField
CLASS_DESCRIPTION = """
Scripted agents can be configured with custom Python actions.
The 'actions' config field has a list of action names. Each action is configured in a corresponding "action_name" with the name of the action, and contains: argument (object schema object), and body (python string source).
""".strip()
class ScriptedAgent(Agent):
identifier = "scripted"
description = CLASS_DESCRIPTION
schema_fields = [
AgentField('actions', 'array', default=[]),
]
def __init__(self, app, data):
Agent.__init__(self, app, data)
async def prompt(self, instruction, input=None, **kwargs):
raise Exception("Scripted agent cannot use prompts (Unimplemented)")
async def received_message(self, message):
raise Exception("Scripted agent cannot use chat (Unimplemented)")
async def execute_action(self, name: str, argument: dict):
raise Exception("No actions for this agent")
+1
View File
@@ -39,6 +39,7 @@ class App(ChatMixin):
agent_mod.BasicAgent,
agents_mod.CharacterAgent,
agents_mod.ExpertAgent,
agents_mod.ScriptedAgent,
#agent_mod.LlamaAgent,
#agent_mod.CoderV1Agent,
+88
View File
@@ -19,6 +19,8 @@
const agent = ref({});
const kindInfo = ref({});
const configFields = ref([]);
// Only used for scripted agents.
const actionDefinitions = ref([]);
// === State Management === //
@@ -40,9 +42,14 @@
backend.sendAction("get-agent-kind-info", {kind: _agent.kind}).then(res => {
kindInfo.value.description = res.info.description;
kindInfo.value.name = _agent.kind;
});
backend.sendAction('get-agent-config-fields', {agentId}).then(res => {
const dataObject = Object.fromEntries(res.fields.map(
field => [field.name, field.value]
));
configFields.value = res.fields.map(field => ({
name: field.name,
type: field.type,
@@ -50,6 +57,18 @@
default: null,
enabled: field.value != null,
}));
if (dataObject.actions) {
actionDefinitions.value = dataObject.actions.map(name => {
const fieldName = 'action_' + name;
const fieldData = dataObject[fieldName];
return {
name,
argument: fieldData ? JSON.stringify(fieldData.argument) : "{}",
body: fieldData && fieldData.body || "pass",
}
});
}
});
}
@@ -186,6 +205,59 @@
backend.invalidateCache({agents: true});
}
}
// == Scripted Agent Actions == //
function createAction () {
const value = prompt(`Enter a new identifier for ${agent.value.name}`);
if (value) {
const def = {
name: value,
argument: "{}",
body: "pass",
};
const actionsField = configFields.value.find(field => field.name == 'actions');
if (actionsField) {
actionsField.value.push(def.name);
} else {
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;
const actionField = configFields.value.find(field => field.name == fieldName);
if (actionField) {
actionField.arguments = argSchema;
actionField.body = actionDef.body;
} else {
configFields.value.push({
name: fieldName,
value: {
argument: argSchema,
body: actionDef.body,
},
enabled: true,
});
}
saveChanges();
}
</script>
<template>
@@ -243,6 +315,22 @@
</div>
</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>
<div v-for="(configField, index) in configFields" :key="index">
<span class="label">{{ configField.name }}</span>