Spaces:
Running
Running
| // core/agents.js — AGENTS as κ-objects (LibreChat agent semantics, substrate-native). An agent | |
| // bundles identity + instructions + model + parameters + armed tools + conversation starters; | |
| // selecting one shapes every turn (instructions ride the system block, its tool selection arms | |
| // the MCP loop). Field names follow the LibreChat agent schema so exports interoperate; each | |
| // version re-seals to a new κ (history is free, Law L3). | |
| import { normPreset } from "./schema.js"; | |
| const LC = { lc: "https://librechat.ai/ns#" }; | |
| export function normAgent(a = {}) { | |
| return { | |
| id: typeof a.id === "string" ? a.id : null, | |
| name: a.name || "New Agent", | |
| description: a.description || "", | |
| instructions: a.instructions || "", | |
| avatar: a.avatar || null, // { filepath, source } | emoji string | null | |
| provider: a.provider || "holo-q", // the local substrate engine | |
| model: a.model || null, // a MODELS[] name | |
| model_parameters: { | |
| temperature: +(a.model_parameters?.temperature ?? 0) || 0, | |
| max_output_tokens: +(a.model_parameters?.max_output_tokens ?? 900) || 900, | |
| }, | |
| tools: Array.isArray(a.tools) ? a.tools : [], // armed tool names (the MCP loop selection) | |
| mcpServerNames: Array.isArray(a.mcpServerNames) ? a.mcpServerNames : [], | |
| conversation_starters: Array.isArray(a.conversation_starters) ? a.conversation_starters.filter(Boolean).slice(0, 4) : [], | |
| artifacts: a.artifacts || "default", // 'default' | 'custom' (custom: instructions own the format) | |
| recursion_limit: +(a.recursion_limit ?? 4) || 4, // max tool rounds | |
| category: a.category || "general", | |
| version: +(a.version ?? 1) || 1, | |
| }; | |
| } | |
| export function makeAgents(chatStore) { | |
| const { store, getIndex, newId } = chatStore; | |
| const putIndex = async (idx) => { const b = new TextEncoder().encode(JSON.stringify(idx)); return store.backend.putRaw ? store.backend.putRaw("index:org.hologram.HoloQ", b) : store.backend.put("index:org.hologram.HoloQ", b); }; | |
| async function save(a) { | |
| const norm = normAgent(a); | |
| if (!norm.id) norm.id = newId("agent"); | |
| const prevPtr = ((await getIndex()).agents || []).find((x) => x.id === norm.id); | |
| if (prevPtr) norm.version = (prevPtr.version || 1) + 1; | |
| const obj = await store.makeObject({ | |
| type: ["schema:SoftwareAgent", "prov:Entity"], context: [LC], | |
| "schema:identifier": norm.id, "schema:name": norm.name, "schema:description": norm.description, | |
| "lc:agent": norm, | |
| ...(prevPtr ? { links: [{ ...store.contentLink("prov:wasRevisionOf", prevPtr.kappa, "schema:SoftwareAgent"), "schema:name": "previousVersion" }] } : {}), | |
| }); | |
| const idx = await getIndex(); | |
| idx.agents = idx.agents || []; | |
| const ptr = { id: norm.id, kappa: obj.id, name: norm.name, avatar: norm.avatar, category: norm.category, version: norm.version }; | |
| const i = idx.agents.findIndex((x) => x.id === norm.id); | |
| if (i >= 0) idx.agents[i] = ptr; else idx.agents.push(ptr); | |
| await putIndex(idx); | |
| return { ...norm, kappa: obj.id }; | |
| } | |
| async function list() { return (await getIndex()).agents || []; } | |
| async function get(id) { | |
| const ptr = (await list()).find((x) => x.id === id); if (!ptr) return null; | |
| const obj = await store.getObj(ptr.kappa); if (!obj) return null; | |
| if (!(await store.verify(obj))) return null; // Law L5: a tampered agent is refused | |
| return { ...normAgent(obj["lc:agent"]), kappa: ptr.kappa }; | |
| } | |
| async function remove(id) { | |
| const idx = await getIndex(); | |
| idx.agents = (idx.agents || []).filter((x) => x.id !== id); | |
| await putIndex(idx); | |
| } | |
| return { save, list, get, remove, normAgent }; | |
| } | |