@ai-ecoverse/slicc-agent 2.0.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -0
- package/dist/control.js +9 -1
- package/dist/control.js.map +2 -2
- package/dist/index.js.map +2 -2
- package/dist/services.js.map +2 -2
- package/dist/spectrum/agent-port.js +156 -0
- package/dist/spectrum/agent-port.js.map +7 -0
- package/dist/spectrum/emitter.js +20 -0
- package/dist/spectrum/emitter.js.map +7 -0
- package/dist/spectrum/index.js +17 -0
- package/dist/spectrum/index.js.map +7 -0
- package/dist/spectrum/messages.js +161 -0
- package/dist/spectrum/messages.js.map +7 -0
- package/dist/types/index.d.ts +1 -1
- package/dist/types/services.d.ts +9 -0
- package/dist/types/spectrum/agent-port.d.ts +32 -0
- package/dist/types/spectrum/emitter.d.ts +7 -0
- package/dist/types/spectrum/index.d.ts +7 -0
- package/dist/types/spectrum/messages.d.ts +37 -0
- package/package.json +9 -1
package/README.md
CHANGED
|
@@ -31,6 +31,19 @@ await agent.prompt('What is in /home?');
|
|
|
31
31
|
- `hostAgent(agent)` serves the agent with pi's protocol: a pi-server with one session, `agent`, whose Chord services are `slicc.agent.control` (send with `whenBusy` `steer`, `followUp` or `reject`, wait, withdraw, abort, compact) and `slicc.agent.transcript` (the conversation's durable view as replicated state). `serveConnections(self, host)` hands it every `MessagePort` the page sends.
|
|
32
32
|
- `startAgent({ worker })` takes the Web Lock `slicc-agent`, so one tab at a time owns the agent worker, and waits while another tab holds it. `connect()` returns an `AgentConnection` (`control`, `transcript`, `prompt()`), `restart()` replaces the worker (durable resumes from SQLite), and `release()` stops it and lets the next tab take over.
|
|
33
33
|
|
|
34
|
+
### In slicc-spectrum
|
|
35
|
+
|
|
36
|
+
`@ai-ecoverse/slicc-agent/spectrum` turns an `AgentConnection` into slicc-spectrum's `AgentPort`, so `<slicc-app>` shows the real agent:
|
|
37
|
+
|
|
38
|
+
```js
|
|
39
|
+
import { createAgentModel } from '@ai-ecoverse/slicc-agent/spectrum';
|
|
40
|
+
|
|
41
|
+
const agent = await owner.connect();
|
|
42
|
+
app.model = { ...createKernelModel({ kernel, root }), ...createAgentModel(agent) };
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
The adapter keeps the replicated transcript and maps it on every update. User, assistant and compaction entries become messages; tool results fill in the tool calls they answer; the generation in flight shows as a streaming message; retries and running compactions show as system messages. `busy()` and `queue()` read durable's live and inbox documents. A plain send queues a follow-up, and a steer send steers, as slicc-spectrum's composer asks today. There is one cone so far; scoops, the freezer, licks and questions come later. slicc-spectrum is a peer dependency (≥ 1.7.0) used for types only.
|
|
46
|
+
|
|
34
47
|
pi-server 1.0.4 calls `unref()` on a `setTimeout` handle when it accepts a connection, which browsers don't have. `PortListener` wraps that one call so its timers get a no-op `unref`.
|
|
35
48
|
|
|
36
49
|
## Develop
|
package/dist/control.js
CHANGED
|
@@ -51,7 +51,15 @@ function createAgentControl(harness, conversation) {
|
|
|
51
51
|
return { outcome: result === "not_found" ? "not_found" : "already_placed" };
|
|
52
52
|
},
|
|
53
53
|
abort: (context) => conversation.abort(context),
|
|
54
|
-
compact: (instructions, context) => accepted(() => conversation.compact(instructions ?? void 0, context))
|
|
54
|
+
compact: (instructions, context) => accepted(() => conversation.compact(instructions ?? void 0, context)),
|
|
55
|
+
reset: (handoff, context) => conversation.reset(handoff ?? void 0, context),
|
|
56
|
+
configure: (change, context) => conversation.configure(
|
|
57
|
+
{
|
|
58
|
+
...change.model ? { model: change.model } : {},
|
|
59
|
+
...change.thinkingLevel ? { thinkingLevel: change.thinkingLevel } : {}
|
|
60
|
+
},
|
|
61
|
+
context
|
|
62
|
+
)
|
|
55
63
|
};
|
|
56
64
|
}
|
|
57
65
|
export {
|
package/dist/control.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/control.ts"],
|
|
4
|
-
"sourcesContent": ["import {\n AssistantEntry,\n type Conversation,\n ConversationBusy,\n type EntryId,\n type Harness,\n type SubmissionId,\n} from '@earendil-works/pi-durable';\nimport { answerText } from './agent.ts';\nimport type { AgentControl, OperationError, SendResponse } from './services.ts';\n\nexport function submissionId(value: string): SubmissionId | undefined {\n const id = Number(value);\n return /^[1-9][0-9]*$/.test(value) && Number.isSafeInteger(id) ? (id as SubmissionId) : undefined;\n}\n\nfunction operationError(error: unknown): OperationError {\n if (error instanceof ConversationBusy) return { code: 'busy', message: error.message };\n return { code: 'failed', message: error instanceof Error ? error.message : String(error) };\n}\n\nasync function accepted(operation: () => Promise<{ id: number } | number>): Promise<SendResponse> {\n try {\n const result = await operation();\n const id = typeof result === 'number' ? result : result.id;\n return { accepted: true, submissionId: String(id), error: null };\n } catch (error) {\n return { accepted: false, submissionId: null, error: operationError(error) };\n }\n}\n\nexport function createAgentControl(harness: Harness, conversation: Conversation): AgentControl {\n return {\n send: (request, context) =>\n accepted(() =>\n conversation.submit(\n {\n type: 'input',\n content: request.text,\n whenBusy: request.whenBusy,\n ...(request.requestId ? { requestId: request.requestId } : {}),\n },\n context\n )\n ),\n async wait(id, context) {\n const parsed = submissionId(id);\n const submission =\n parsed === undefined ? undefined : await harness.submission(parsed, context);\n if (!submission) throw new Error(`unknown submission ${id}`);\n const settled = await submission.wait(context);\n const { answer, reason } = settled as { answer?: EntryId; reason?: string };\n if (answer === undefined) return { status: 'unanswered', text: null, reason: String(reason) };\n const entry = await harness.commit((tx) => tx.entry(AssistantEntry, answer), context);\n return { status: 'done', text: answerText(entry?.model?.[0]?.content), reason: null };\n },\n async withdraw(id, context) {\n const parsed = submissionId(id);\n if (parsed === undefined) return { outcome: 'not_found' };\n const result = await harness.abortSubmission(parsed, context, conversation.id);\n if (result === 'aborted') return { outcome: 'withdrawn' };\n return { outcome: result === 'not_found' ? 'not_found' : 'already_placed' };\n },\n abort: (context) => conversation.abort(context),\n compact: (instructions, context) =>\n accepted(() => conversation.compact(instructions ?? undefined, context)),\n };\n}\n"],
|
|
5
|
-
"mappings": "AAAA;AAAA,EACE;AAAA,EAEA;AAAA,OAIK;AACP,SAAS,kBAAkB;AAGpB,SAAS,aAAa,OAAyC;AACpE,QAAM,KAAK,OAAO,KAAK;AACvB,SAAO,gBAAgB,KAAK,KAAK,KAAK,OAAO,cAAc,EAAE,IAAK,KAAsB;AAC1F;AAEA,SAAS,eAAe,OAAgC;AACtD,MAAI,iBAAiB,iBAAkB,QAAO,EAAE,MAAM,QAAQ,SAAS,MAAM,QAAQ;AACrF,SAAO,EAAE,MAAM,UAAU,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,EAAE;AAC3F;AAEA,eAAe,SAAS,WAA0E;AAChG,MAAI;AACF,UAAM,SAAS,MAAM,UAAU;AAC/B,UAAM,KAAK,OAAO,WAAW,WAAW,SAAS,OAAO;AACxD,WAAO,EAAE,UAAU,MAAM,cAAc,OAAO,EAAE,GAAG,OAAO,KAAK;AAAA,EACjE,SAAS,OAAO;AACd,WAAO,EAAE,UAAU,OAAO,cAAc,MAAM,OAAO,eAAe,KAAK,EAAE;AAAA,EAC7E;AACF;AAEO,SAAS,mBAAmB,SAAkB,cAA0C;AAC7F,SAAO;AAAA,IACL,MAAM,CAAC,SAAS,YACd;AAAA,MAAS,MACP,aAAa;AAAA,QACX;AAAA,UACE,MAAM;AAAA,UACN,SAAS,QAAQ;AAAA,UACjB,UAAU,QAAQ;AAAA,UAClB,GAAI,QAAQ,YAAY,EAAE,WAAW,QAAQ,UAAU,IAAI,CAAC;AAAA,QAC9D;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,IACF,MAAM,KAAK,IAAI,SAAS;AACtB,YAAM,SAAS,aAAa,EAAE;AAC9B,YAAM,aACJ,WAAW,SAAY,SAAY,MAAM,QAAQ,WAAW,QAAQ,OAAO;AAC7E,UAAI,CAAC,WAAY,OAAM,IAAI,MAAM,sBAAsB,EAAE,EAAE;AAC3D,YAAM,UAAU,MAAM,WAAW,KAAK,OAAO;AAC7C,YAAM,EAAE,QAAQ,OAAO,IAAI;AAC3B,UAAI,WAAW,OAAW,QAAO,EAAE,QAAQ,cAAc,MAAM,MAAM,QAAQ,OAAO,MAAM,EAAE;AAC5F,YAAM,QAAQ,MAAM,QAAQ,OAAO,CAAC,OAAO,GAAG,MAAM,gBAAgB,MAAM,GAAG,OAAO;AACpF,aAAO,EAAE,QAAQ,QAAQ,MAAM,WAAW,OAAO,QAAQ,CAAC,GAAG,OAAO,GAAG,QAAQ,KAAK;AAAA,IACtF;AAAA,IACA,MAAM,SAAS,IAAI,SAAS;AAC1B,YAAM,SAAS,aAAa,EAAE;AAC9B,UAAI,WAAW,OAAW,QAAO,EAAE,SAAS,YAAY;AACxD,YAAM,SAAS,MAAM,QAAQ,gBAAgB,QAAQ,SAAS,aAAa,EAAE;AAC7E,UAAI,WAAW,UAAW,QAAO,EAAE,SAAS,YAAY;AACxD,aAAO,EAAE,SAAS,WAAW,cAAc,cAAc,iBAAiB;AAAA,IAC5E;AAAA,IACA,OAAO,CAAC,YAAY,aAAa,MAAM,OAAO;AAAA,IAC9C,SAAS,CAAC,cAAc,YACtB,SAAS,MAAM,aAAa,QAAQ,gBAAgB,QAAW,OAAO,CAAC;AAAA,
|
|
4
|
+
"sourcesContent": ["import {\n AssistantEntry,\n type Conversation,\n ConversationBusy,\n type EntryId,\n type Harness,\n type SubmissionId,\n} from '@earendil-works/pi-durable';\nimport { answerText } from './agent.ts';\nimport type { AgentControl, OperationError, SendResponse } from './services.ts';\n\nexport function submissionId(value: string): SubmissionId | undefined {\n const id = Number(value);\n return /^[1-9][0-9]*$/.test(value) && Number.isSafeInteger(id) ? (id as SubmissionId) : undefined;\n}\n\nfunction operationError(error: unknown): OperationError {\n if (error instanceof ConversationBusy) return { code: 'busy', message: error.message };\n return { code: 'failed', message: error instanceof Error ? error.message : String(error) };\n}\n\nasync function accepted(operation: () => Promise<{ id: number } | number>): Promise<SendResponse> {\n try {\n const result = await operation();\n const id = typeof result === 'number' ? result : result.id;\n return { accepted: true, submissionId: String(id), error: null };\n } catch (error) {\n return { accepted: false, submissionId: null, error: operationError(error) };\n }\n}\n\nexport function createAgentControl(harness: Harness, conversation: Conversation): AgentControl {\n return {\n send: (request, context) =>\n accepted(() =>\n conversation.submit(\n {\n type: 'input',\n content: request.text,\n whenBusy: request.whenBusy,\n ...(request.requestId ? { requestId: request.requestId } : {}),\n },\n context\n )\n ),\n async wait(id, context) {\n const parsed = submissionId(id);\n const submission =\n parsed === undefined ? undefined : await harness.submission(parsed, context);\n if (!submission) throw new Error(`unknown submission ${id}`);\n const settled = await submission.wait(context);\n const { answer, reason } = settled as { answer?: EntryId; reason?: string };\n if (answer === undefined) return { status: 'unanswered', text: null, reason: String(reason) };\n const entry = await harness.commit((tx) => tx.entry(AssistantEntry, answer), context);\n return { status: 'done', text: answerText(entry?.model?.[0]?.content), reason: null };\n },\n async withdraw(id, context) {\n const parsed = submissionId(id);\n if (parsed === undefined) return { outcome: 'not_found' };\n const result = await harness.abortSubmission(parsed, context, conversation.id);\n if (result === 'aborted') return { outcome: 'withdrawn' };\n return { outcome: result === 'not_found' ? 'not_found' : 'already_placed' };\n },\n abort: (context) => conversation.abort(context),\n compact: (instructions, context) =>\n accepted(() => conversation.compact(instructions ?? undefined, context)),\n reset: (handoff, context) => conversation.reset(handoff ?? undefined, context),\n configure: (change, context) =>\n conversation.configure(\n {\n ...(change.model ? { model: change.model } : {}),\n ...(change.thinkingLevel ? { thinkingLevel: change.thinkingLevel } : {}),\n },\n context\n ),\n };\n}\n"],
|
|
5
|
+
"mappings": "AAAA;AAAA,EACE;AAAA,EAEA;AAAA,OAIK;AACP,SAAS,kBAAkB;AAGpB,SAAS,aAAa,OAAyC;AACpE,QAAM,KAAK,OAAO,KAAK;AACvB,SAAO,gBAAgB,KAAK,KAAK,KAAK,OAAO,cAAc,EAAE,IAAK,KAAsB;AAC1F;AAEA,SAAS,eAAe,OAAgC;AACtD,MAAI,iBAAiB,iBAAkB,QAAO,EAAE,MAAM,QAAQ,SAAS,MAAM,QAAQ;AACrF,SAAO,EAAE,MAAM,UAAU,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,EAAE;AAC3F;AAEA,eAAe,SAAS,WAA0E;AAChG,MAAI;AACF,UAAM,SAAS,MAAM,UAAU;AAC/B,UAAM,KAAK,OAAO,WAAW,WAAW,SAAS,OAAO;AACxD,WAAO,EAAE,UAAU,MAAM,cAAc,OAAO,EAAE,GAAG,OAAO,KAAK;AAAA,EACjE,SAAS,OAAO;AACd,WAAO,EAAE,UAAU,OAAO,cAAc,MAAM,OAAO,eAAe,KAAK,EAAE;AAAA,EAC7E;AACF;AAEO,SAAS,mBAAmB,SAAkB,cAA0C;AAC7F,SAAO;AAAA,IACL,MAAM,CAAC,SAAS,YACd;AAAA,MAAS,MACP,aAAa;AAAA,QACX;AAAA,UACE,MAAM;AAAA,UACN,SAAS,QAAQ;AAAA,UACjB,UAAU,QAAQ;AAAA,UAClB,GAAI,QAAQ,YAAY,EAAE,WAAW,QAAQ,UAAU,IAAI,CAAC;AAAA,QAC9D;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,IACF,MAAM,KAAK,IAAI,SAAS;AACtB,YAAM,SAAS,aAAa,EAAE;AAC9B,YAAM,aACJ,WAAW,SAAY,SAAY,MAAM,QAAQ,WAAW,QAAQ,OAAO;AAC7E,UAAI,CAAC,WAAY,OAAM,IAAI,MAAM,sBAAsB,EAAE,EAAE;AAC3D,YAAM,UAAU,MAAM,WAAW,KAAK,OAAO;AAC7C,YAAM,EAAE,QAAQ,OAAO,IAAI;AAC3B,UAAI,WAAW,OAAW,QAAO,EAAE,QAAQ,cAAc,MAAM,MAAM,QAAQ,OAAO,MAAM,EAAE;AAC5F,YAAM,QAAQ,MAAM,QAAQ,OAAO,CAAC,OAAO,GAAG,MAAM,gBAAgB,MAAM,GAAG,OAAO;AACpF,aAAO,EAAE,QAAQ,QAAQ,MAAM,WAAW,OAAO,QAAQ,CAAC,GAAG,OAAO,GAAG,QAAQ,KAAK;AAAA,IACtF;AAAA,IACA,MAAM,SAAS,IAAI,SAAS;AAC1B,YAAM,SAAS,aAAa,EAAE;AAC9B,UAAI,WAAW,OAAW,QAAO,EAAE,SAAS,YAAY;AACxD,YAAM,SAAS,MAAM,QAAQ,gBAAgB,QAAQ,SAAS,aAAa,EAAE;AAC7E,UAAI,WAAW,UAAW,QAAO,EAAE,SAAS,YAAY;AACxD,aAAO,EAAE,SAAS,WAAW,cAAc,cAAc,iBAAiB;AAAA,IAC5E;AAAA,IACA,OAAO,CAAC,YAAY,aAAa,MAAM,OAAO;AAAA,IAC9C,SAAS,CAAC,cAAc,YACtB,SAAS,MAAM,aAAa,QAAQ,gBAAgB,QAAW,OAAO,CAAC;AAAA,IACzE,OAAO,CAAC,SAAS,YAAY,aAAa,MAAM,WAAW,QAAW,OAAO;AAAA,IAC7E,WAAW,CAAC,QAAQ,YAClB,aAAa;AAAA,MACX;AAAA,QACE,GAAI,OAAO,QAAQ,EAAE,OAAO,OAAO,MAAM,IAAI,CAAC;AAAA,QAC9C,GAAI,OAAO,gBAAgB,EAAE,eAAe,OAAO,cAAc,IAAI,CAAC;AAAA,MACxE;AAAA,MACA;AAAA,IACF;AAAA,EACJ;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/index.ts"],
|
|
4
|
-
"sourcesContent": ["export { type Agent, type AgentOptions, answerText, openAgent } from './agent.ts';\nexport { type AgentConnection, connectAgent } from './client.ts';\nexport { createAgentControl } from './control.ts';\nexport { type AgentHost, hostAgent } from './host.ts';\nexport {\n AGENT_LOCK,\n type AgentOwner,\n type AgentWorker,\n type OwnerOptions,\n startAgent,\n} from './owner.ts';\nexport {\n AGENT_SESSION,\n AgentControl,\n AgentSessions,\n AgentTranscript,\n type OperationError,\n type PromptResult,\n type SendMode,\n type SendRequest,\n type SendResponse,\n} from './services.ts';\nexport {\n AGENT_DIRECTORY,\n type OpfsSqliteOptions,\n openMemorySqliteStorage,\n openOpfsSqliteStorage,\n WasmSqliteDatabase,\n} from './sqlite.ts';\nexport { PortChannel, type PortEndpoint, PortListener, withUnrefTimers } from './wire.ts';\nexport { serveConnections, type WorkerScope } from './worker.ts';\n"],
|
|
5
|
-
"mappings": "AAAA,SAAwC,YAAY,iBAAiB;AACrE,SAA+B,oBAAoB;AACnD,SAAS,0BAA0B;AACnC,SAAyB,iBAAiB;AAC1C;AAAA,EACE;AAAA,EAIA;AAAA,OACK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,
|
|
4
|
+
"sourcesContent": ["export { type Agent, type AgentOptions, answerText, openAgent } from './agent.ts';\nexport { type AgentConnection, connectAgent } from './client.ts';\nexport { createAgentControl } from './control.ts';\nexport { type AgentHost, hostAgent } from './host.ts';\nexport {\n AGENT_LOCK,\n type AgentOwner,\n type AgentWorker,\n type OwnerOptions,\n startAgent,\n} from './owner.ts';\nexport {\n AGENT_SESSION,\n AgentControl,\n AgentSessions,\n type AgentSettingsChange,\n AgentTranscript,\n type OperationError,\n type PromptResult,\n type SendMode,\n type SendRequest,\n type SendResponse,\n} from './services.ts';\nexport {\n AGENT_DIRECTORY,\n type OpfsSqliteOptions,\n openMemorySqliteStorage,\n openOpfsSqliteStorage,\n WasmSqliteDatabase,\n} from './sqlite.ts';\nexport { PortChannel, type PortEndpoint, PortListener, withUnrefTimers } from './wire.ts';\nexport { serveConnections, type WorkerScope } from './worker.ts';\n"],
|
|
5
|
+
"mappings": "AAAA,SAAwC,YAAY,iBAAiB;AACrE,SAA+B,oBAAoB;AACnD,SAAS,0BAA0B;AACnC,SAAyB,iBAAiB;AAC1C;AAAA,EACE;AAAA,EAIA;AAAA,OACK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EAEA;AAAA,OAMK;AACP;AAAA,EACE;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,aAAgC,cAAc,uBAAuB;AAC9E,SAAS,wBAA0C;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/services.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/services.ts"],
|
|
4
|
-
"sourcesContent": ["import { type Context, defineService, type ReplicatedState } from '@earendil-works/chord';\nimport type { ConversationView } from '@earendil-works/pi-durable';\n\nexport type SendMode = 'steer' | 'followUp' | 'reject';\n\nexport interface SendRequest {\n text: string;\n whenBusy: SendMode;\n requestId: string | null;\n}\n\nexport interface OperationError {\n code: string;\n message: string;\n}\n\nexport type SendResponse =\n | { accepted: true; submissionId: string; error: null }\n | { accepted: false; submissionId: null; error: OperationError };\n\nexport type PromptResult =\n | { status: 'done'; text: string; reason: null }\n | { status: 'unanswered'; text: null; reason: string };\n\nexport interface AgentControl {\n send(request: SendRequest, context: Context): Promise<SendResponse>;\n wait(submissionId: string, context: Context): Promise<PromptResult>;\n withdraw(\n submissionId: string,\n context: Context\n ): Promise<{ outcome: 'withdrawn' | 'already_placed' | 'not_found' }>;\n abort(context: Context): Promise<void>;\n compact(instructions: string | null, context: Context): Promise<SendResponse>;\n}\n\nexport const AgentControl = defineService<AgentControl>('slicc.agent.control');\n\nexport interface AgentTranscript {\n readonly state: ReplicatedState<ConversationView>;\n}\n\nexport const AgentTranscript = defineService<AgentTranscript>('slicc.agent.transcript');\n\nexport interface AgentSessions {\n attach(sessionId: string, context: Context): Promise<void>;\n detach(context: Context): Promise<void>;\n}\n\nexport const AgentSessions = defineService<AgentSessions>('slicc.agent.sessions');\n\nexport const AGENT_SESSION = 'agent';\n"],
|
|
5
|
-
"mappings": "AAAA,SAAuB,qBAA2C;
|
|
4
|
+
"sourcesContent": ["import { type Context, defineService, type ReplicatedState } from '@earendil-works/chord';\nimport type { ConversationView } from '@earendil-works/pi-durable';\n\nexport type SendMode = 'steer' | 'followUp' | 'reject';\n\nexport interface SendRequest {\n text: string;\n whenBusy: SendMode;\n requestId: string | null;\n}\n\nexport interface OperationError {\n code: string;\n message: string;\n}\n\nexport type SendResponse =\n | { accepted: true; submissionId: string; error: null }\n | { accepted: false; submissionId: null; error: OperationError };\n\nexport type PromptResult =\n | { status: 'done'; text: string; reason: null }\n | { status: 'unanswered'; text: null; reason: string };\n\nexport interface AgentControl {\n send(request: SendRequest, context: Context): Promise<SendResponse>;\n wait(submissionId: string, context: Context): Promise<PromptResult>;\n withdraw(\n submissionId: string,\n context: Context\n ): Promise<{ outcome: 'withdrawn' | 'already_placed' | 'not_found' }>;\n abort(context: Context): Promise<void>;\n compact(instructions: string | null, context: Context): Promise<SendResponse>;\n reset(handoff: string | null, context: Context): Promise<void>;\n configure(change: AgentSettingsChange, context: Context): Promise<void>;\n}\n\nexport interface AgentSettingsChange {\n model: { provider: string; modelId: string } | null;\n thinkingLevel: 'off' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh' | 'max' | null;\n}\n\nexport const AgentControl = defineService<AgentControl>('slicc.agent.control');\n\nexport interface AgentTranscript {\n readonly state: ReplicatedState<ConversationView>;\n}\n\nexport const AgentTranscript = defineService<AgentTranscript>('slicc.agent.transcript');\n\nexport interface AgentSessions {\n attach(sessionId: string, context: Context): Promise<void>;\n detach(context: Context): Promise<void>;\n}\n\nexport const AgentSessions = defineService<AgentSessions>('slicc.agent.sessions');\n\nexport const AGENT_SESSION = 'agent';\n"],
|
|
5
|
+
"mappings": "AAAA,SAAuB,qBAA2C;AA0C3D,MAAM,eAAe,cAA4B,qBAAqB;AAMtE,MAAM,kBAAkB,cAA+B,wBAAwB;AAO/E,MAAM,gBAAgB,cAA6B,sBAAsB;AAEzE,MAAM,gBAAgB;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { BACKGROUND_CONTEXT } from "@earendil-works/chord/context";
|
|
2
|
+
import { Emitter } from "./emitter.js";
|
|
3
|
+
import { isBusy, queued, toMessages } from "./messages.js";
|
|
4
|
+
const CONE = "cone";
|
|
5
|
+
const thinking = {
|
|
6
|
+
off: "off",
|
|
7
|
+
minimal: "low",
|
|
8
|
+
low: "low",
|
|
9
|
+
medium: "medium",
|
|
10
|
+
high: "high",
|
|
11
|
+
xhigh: "high",
|
|
12
|
+
max: "high"
|
|
13
|
+
};
|
|
14
|
+
function status(view, messages) {
|
|
15
|
+
if (isBusy(view)) {
|
|
16
|
+
const live = view?.docs["pi.live"];
|
|
17
|
+
return live?.tools?.some((slot) => slot.status === "running") ? "working" : "thinking";
|
|
18
|
+
}
|
|
19
|
+
const last = messages.at(-1);
|
|
20
|
+
return last?.role === "assistant" && last.status === "error" ? "error" : "idle";
|
|
21
|
+
}
|
|
22
|
+
class AgentAdapter extends Emitter {
|
|
23
|
+
#connection;
|
|
24
|
+
#ready;
|
|
25
|
+
#messages = [];
|
|
26
|
+
constructor(connection) {
|
|
27
|
+
super();
|
|
28
|
+
this.#connection = connection;
|
|
29
|
+
this.#ready = new Promise((resolve) => {
|
|
30
|
+
connection.transcript.subscribe((view) => {
|
|
31
|
+
this.#update(view);
|
|
32
|
+
resolve();
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
#view() {
|
|
37
|
+
return this.#connection.transcript.value;
|
|
38
|
+
}
|
|
39
|
+
#update(view) {
|
|
40
|
+
const before = this.#messages;
|
|
41
|
+
this.#messages = toMessages(view);
|
|
42
|
+
this.emit("agents", this.list());
|
|
43
|
+
if (before.length !== this.#messages.length) {
|
|
44
|
+
this.emit("messages", CONE);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
const changed = this.#messages.filter(
|
|
48
|
+
(message, index) => JSON.stringify(message) !== JSON.stringify(before[index])
|
|
49
|
+
);
|
|
50
|
+
if (changed.length === 1)
|
|
51
|
+
this.emit("message", { agentId: CONE, message: changed[0] });
|
|
52
|
+
else if (changed.length > 1) this.emit("messages", CONE);
|
|
53
|
+
}
|
|
54
|
+
ready() {
|
|
55
|
+
return this.#ready;
|
|
56
|
+
}
|
|
57
|
+
list() {
|
|
58
|
+
const doc = this.#view()?.docs["pi.agent"];
|
|
59
|
+
return [
|
|
60
|
+
{
|
|
61
|
+
id: CONE,
|
|
62
|
+
name: "sliccy",
|
|
63
|
+
kind: "cone",
|
|
64
|
+
parentId: null,
|
|
65
|
+
status: status(this.#view(), this.#messages),
|
|
66
|
+
model: doc?.model ? `${doc.model.provider}/${doc.model.modelId}` : "",
|
|
67
|
+
contextFill: 0,
|
|
68
|
+
unread: 0,
|
|
69
|
+
thinking: thinking[doc?.thinkingLevel ?? "off"] ?? "off"
|
|
70
|
+
}
|
|
71
|
+
];
|
|
72
|
+
}
|
|
73
|
+
active() {
|
|
74
|
+
return CONE;
|
|
75
|
+
}
|
|
76
|
+
select() {
|
|
77
|
+
}
|
|
78
|
+
messages() {
|
|
79
|
+
return this.#messages;
|
|
80
|
+
}
|
|
81
|
+
async send(_agentId, input) {
|
|
82
|
+
const outgoing = typeof input === "string" ? { text: input } : input;
|
|
83
|
+
const sent = await this.#connection.control.send(
|
|
84
|
+
{
|
|
85
|
+
text: outgoing.text,
|
|
86
|
+
whenBusy: outgoing.mode === "steer" ? "steer" : "followUp",
|
|
87
|
+
requestId: crypto.randomUUID()
|
|
88
|
+
},
|
|
89
|
+
BACKGROUND_CONTEXT
|
|
90
|
+
);
|
|
91
|
+
if (!sent.accepted) throw new Error(sent.error.message);
|
|
92
|
+
}
|
|
93
|
+
stop() {
|
|
94
|
+
void this.#connection.control.abort(BACKGROUND_CONTEXT);
|
|
95
|
+
}
|
|
96
|
+
busy() {
|
|
97
|
+
return isBusy(this.#view());
|
|
98
|
+
}
|
|
99
|
+
queue() {
|
|
100
|
+
return queued(this.#view());
|
|
101
|
+
}
|
|
102
|
+
unqueue(_agentId, messageId) {
|
|
103
|
+
void this.#connection.control.withdraw(messageId.replace(/^q/, ""), BACKGROUND_CONTEXT);
|
|
104
|
+
}
|
|
105
|
+
suggestion() {
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
answer() {
|
|
109
|
+
}
|
|
110
|
+
resolveLick() {
|
|
111
|
+
}
|
|
112
|
+
compact() {
|
|
113
|
+
void this.#connection.control.compact(null, BACKGROUND_CONTEXT);
|
|
114
|
+
}
|
|
115
|
+
clear() {
|
|
116
|
+
void this.#connection.control.reset(null, BACKGROUND_CONTEXT);
|
|
117
|
+
}
|
|
118
|
+
#configure(change) {
|
|
119
|
+
void this.#connection.control.configure(
|
|
120
|
+
{ model: change.model ?? null, thinkingLevel: change.thinkingLevel ?? null },
|
|
121
|
+
BACKGROUND_CONTEXT
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
setModel(_agentId, model) {
|
|
125
|
+
const at = model.indexOf("/");
|
|
126
|
+
if (at <= 0) return;
|
|
127
|
+
this.#configure({ model: { provider: model.slice(0, at), modelId: model.slice(at + 1) } });
|
|
128
|
+
}
|
|
129
|
+
setThinking(_agentId, level) {
|
|
130
|
+
this.#configure({ thinkingLevel: level });
|
|
131
|
+
}
|
|
132
|
+
async older() {
|
|
133
|
+
return [];
|
|
134
|
+
}
|
|
135
|
+
commands() {
|
|
136
|
+
return [];
|
|
137
|
+
}
|
|
138
|
+
createScoop() {
|
|
139
|
+
throw new Error("Scoops come with a later slicc-agent");
|
|
140
|
+
}
|
|
141
|
+
frozen() {
|
|
142
|
+
return [];
|
|
143
|
+
}
|
|
144
|
+
freeze() {
|
|
145
|
+
}
|
|
146
|
+
thaw() {
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
149
|
+
discard() {
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
export {
|
|
153
|
+
AgentAdapter,
|
|
154
|
+
CONE
|
|
155
|
+
};
|
|
156
|
+
//# sourceMappingURL=agent-port.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/spectrum/agent-port.ts"],
|
|
4
|
+
"sourcesContent": ["import type {\n Agent,\n AgentEvents,\n AgentPort,\n AgentStatus,\n FrozenCone,\n Message,\n Outgoing,\n SlashCommand,\n Thinking,\n UserMessage,\n} from '@ai-ecoverse/slicc-spectrum/ui';\nimport { BACKGROUND_CONTEXT } from '@earendil-works/chord/context';\nimport type { ConversationView } from '@earendil-works/pi-durable';\nimport type { AgentConnection } from '../client.ts';\nimport type { AgentSettingsChange } from '../services.ts';\nimport { Emitter } from './emitter.ts';\nimport { isBusy, queued, toMessages } from './messages.ts';\n\nexport const CONE = 'cone';\n\nconst thinking: Record<string, Thinking> = {\n off: 'off',\n minimal: 'low',\n low: 'low',\n medium: 'medium',\n high: 'high',\n xhigh: 'high',\n max: 'high',\n};\n\ninterface AgentDoc {\n model?: { provider: string; modelId: string };\n thinkingLevel?: string;\n}\n\nfunction status(view: ConversationView | undefined, messages: readonly Message[]): AgentStatus {\n if (isBusy(view)) {\n const live = view?.docs['pi.live'] as { tools?: { status: string }[] } | undefined;\n return live?.tools?.some((slot) => slot.status === 'running') ? 'working' : 'thinking';\n }\n const last = messages.at(-1);\n return last?.role === 'assistant' && last.status === 'error' ? 'error' : 'idle';\n}\n\nexport class AgentAdapter extends Emitter<AgentEvents> implements AgentPort {\n readonly #connection: AgentConnection;\n readonly #ready: Promise<void>;\n #messages: Message[] = [];\n\n constructor(connection: AgentConnection) {\n super();\n this.#connection = connection;\n this.#ready = new Promise((resolve) => {\n connection.transcript.subscribe((view) => {\n this.#update(view);\n resolve();\n });\n });\n }\n\n #view(): ConversationView | undefined {\n return this.#connection.transcript.value;\n }\n\n #update(view: ConversationView): void {\n const before = this.#messages;\n this.#messages = toMessages(view);\n this.emit('agents', this.list());\n if (before.length !== this.#messages.length) {\n this.emit('messages', CONE);\n return;\n }\n const changed = this.#messages.filter(\n (message, index) => JSON.stringify(message) !== JSON.stringify(before[index])\n );\n if (changed.length === 1)\n this.emit('message', { agentId: CONE, message: changed[0] as Message });\n else if (changed.length > 1) this.emit('messages', CONE);\n }\n\n ready(): Promise<void> {\n return this.#ready;\n }\n\n list(): readonly Agent[] {\n const doc = this.#view()?.docs['pi.agent'] as AgentDoc | undefined;\n return [\n {\n id: CONE,\n name: 'sliccy',\n kind: 'cone',\n parentId: null,\n status: status(this.#view(), this.#messages),\n model: doc?.model ? `${doc.model.provider}/${doc.model.modelId}` : '',\n contextFill: 0,\n unread: 0,\n thinking: thinking[doc?.thinkingLevel ?? 'off'] ?? 'off',\n },\n ];\n }\n\n active(): string {\n return CONE;\n }\n\n select(): void {}\n\n messages(): readonly Message[] {\n return this.#messages;\n }\n\n async send(_agentId: string, input: string | Outgoing): Promise<void> {\n const outgoing = typeof input === 'string' ? { text: input } : input;\n const sent = await this.#connection.control.send(\n {\n text: outgoing.text,\n whenBusy: outgoing.mode === 'steer' ? 'steer' : 'followUp',\n requestId: crypto.randomUUID(),\n },\n BACKGROUND_CONTEXT\n );\n if (!sent.accepted) throw new Error(sent.error.message);\n }\n\n stop(): void {\n void this.#connection.control.abort(BACKGROUND_CONTEXT);\n }\n\n busy(): boolean {\n return isBusy(this.#view());\n }\n\n queue(): readonly UserMessage[] {\n return queued(this.#view());\n }\n\n unqueue(_agentId: string, messageId: string): void {\n void this.#connection.control.withdraw(messageId.replace(/^q/, ''), BACKGROUND_CONTEXT);\n }\n\n suggestion(): string | null {\n return null;\n }\n\n answer(): void {}\n\n resolveLick(): void {}\n\n compact(): void {\n void this.#connection.control.compact(null, BACKGROUND_CONTEXT);\n }\n\n clear(): void {\n void this.#connection.control.reset(null, BACKGROUND_CONTEXT);\n }\n\n #configure(change: Partial<AgentSettingsChange>): void {\n void this.#connection.control.configure(\n { model: change.model ?? null, thinkingLevel: change.thinkingLevel ?? null },\n BACKGROUND_CONTEXT\n );\n }\n\n setModel(_agentId: string, model: string): void {\n const at = model.indexOf('/');\n if (at <= 0) return;\n this.#configure({ model: { provider: model.slice(0, at), modelId: model.slice(at + 1) } });\n }\n\n setThinking(_agentId: string, level: Thinking): void {\n this.#configure({ thinkingLevel: level });\n }\n\n async older(): Promise<readonly Message[]> {\n return [];\n }\n\n commands(): readonly SlashCommand[] {\n return [];\n }\n\n createScoop(): Agent {\n throw new Error('Scoops come with a later slicc-agent');\n }\n\n frozen(): readonly FrozenCone[] {\n return [];\n }\n\n freeze(): void {}\n\n thaw(): Agent | null {\n return null;\n }\n\n discard(): void {}\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
class Emitter {
|
|
2
|
+
#listeners = /* @__PURE__ */ new Map();
|
|
3
|
+
on(type, listener) {
|
|
4
|
+
let set = this.#listeners.get(type);
|
|
5
|
+
if (!set) {
|
|
6
|
+
set = /* @__PURE__ */ new Set();
|
|
7
|
+
this.#listeners.set(type, set);
|
|
8
|
+
}
|
|
9
|
+
set.add(listener);
|
|
10
|
+
return () => set.delete(listener);
|
|
11
|
+
}
|
|
12
|
+
emit(type, detail) {
|
|
13
|
+
for (const listener of [...this.#listeners.get(type) ?? []])
|
|
14
|
+
listener(detail);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
export {
|
|
18
|
+
Emitter
|
|
19
|
+
};
|
|
20
|
+
//# sourceMappingURL=emitter.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/spectrum/emitter.ts"],
|
|
4
|
+
"sourcesContent": ["type Listener<T> = (detail: T) => void;\n\nexport class Emitter<Events extends object> {\n readonly #listeners = new Map<keyof Events, Set<Listener<never>>>();\n\n on<K extends keyof Events>(type: K, listener: Listener<Events[K]>): () => void {\n let set = this.#listeners.get(type);\n if (!set) {\n set = new Set();\n this.#listeners.set(type, set);\n }\n set.add(listener as Listener<never>);\n return () => set.delete(listener as Listener<never>);\n }\n\n emit<K extends keyof Events>(type: K, detail: Events[K]): void {\n for (const listener of [...(this.#listeners.get(type) ?? [])])\n (listener as Listener<Events[K]>)(detail);\n }\n}\n"],
|
|
5
|
+
"mappings": "AAEO,MAAM,QAA+B;AAAA,EACjC,aAAa,oBAAI,IAAwC;AAAA,EAElE,GAA2B,MAAS,UAA2C;AAC7E,QAAI,MAAM,KAAK,WAAW,IAAI,IAAI;AAClC,QAAI,CAAC,KAAK;AACR,YAAM,oBAAI,IAAI;AACd,WAAK,WAAW,IAAI,MAAM,GAAG;AAAA,IAC/B;AACA,QAAI,IAAI,QAA2B;AACnC,WAAO,MAAM,IAAI,OAAO,QAA2B;AAAA,EACrD;AAAA,EAEA,KAA6B,MAAS,QAAyB;AAC7D,eAAW,YAAY,CAAC,GAAI,KAAK,WAAW,IAAI,IAAI,KAAK,CAAC,CAAE;AAC1D,MAAC,SAAiC,MAAM;AAAA,EAC5C;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { AgentAdapter } from "./agent-port.js";
|
|
2
|
+
import { AgentAdapter as AgentAdapter2, CONE } from "./agent-port.js";
|
|
3
|
+
import { assistant, isBusy, queued, textOf, toMessages } from "./messages.js";
|
|
4
|
+
function createAgentModel(connection) {
|
|
5
|
+
return { agent: new AgentAdapter(connection) };
|
|
6
|
+
}
|
|
7
|
+
export {
|
|
8
|
+
AgentAdapter2 as AgentAdapter,
|
|
9
|
+
CONE,
|
|
10
|
+
assistant,
|
|
11
|
+
createAgentModel,
|
|
12
|
+
isBusy,
|
|
13
|
+
queued,
|
|
14
|
+
textOf,
|
|
15
|
+
toMessages
|
|
16
|
+
};
|
|
17
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/spectrum/index.ts"],
|
|
4
|
+
"sourcesContent": ["import type { AgentConnection } from '../client.ts';\nimport { AgentAdapter } from './agent-port.ts';\n\nexport { AgentAdapter, CONE } from './agent-port.ts';\nexport { assistant, isBusy, queued, textOf, toMessages } from './messages.ts';\n\nexport function createAgentModel(connection: AgentConnection): { agent: AgentAdapter } {\n return { agent: new AgentAdapter(connection) };\n}\n"],
|
|
5
|
+
"mappings": "AACA,SAAS,oBAAoB;AAE7B,SAAS,gBAAAA,eAAc,YAAY;AACnC,SAAS,WAAW,QAAQ,QAAQ,QAAQ,kBAAkB;AAEvD,SAAS,iBAAiB,YAAsD;AACrF,SAAO,EAAE,OAAO,IAAI,aAAa,UAAU,EAAE;AAC/C;",
|
|
6
|
+
"names": ["AgentAdapter"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
function textOf(content) {
|
|
2
|
+
if (typeof content === "string") return content;
|
|
3
|
+
return (content ?? []).map((block) => block.type === "text" ? block.text ?? "" : "").join("");
|
|
4
|
+
}
|
|
5
|
+
const paths = (args) => typeof args?.path === "string" ? [args.path] : [];
|
|
6
|
+
function title(name, args) {
|
|
7
|
+
const subject = args?.command ?? args?.path;
|
|
8
|
+
return typeof subject === "string" ? `${name} ${subject}` : name;
|
|
9
|
+
}
|
|
10
|
+
function toolCall(block) {
|
|
11
|
+
return {
|
|
12
|
+
id: block.id ?? "",
|
|
13
|
+
name: block.name ?? "tool",
|
|
14
|
+
title: title(block.name ?? "tool", block.arguments),
|
|
15
|
+
input: JSON.stringify(block.arguments ?? {}),
|
|
16
|
+
output: "",
|
|
17
|
+
status: "running",
|
|
18
|
+
paths: paths(block.arguments)
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
function part(block) {
|
|
22
|
+
if (block.type === "text") return { type: "text", text: block.text ?? "" };
|
|
23
|
+
if (block.type === "thinking") return { type: "thinking", text: block.thinking ?? "" };
|
|
24
|
+
if (block.type === "toolCall") return { type: "tool", tool: toolCall(block) };
|
|
25
|
+
return void 0;
|
|
26
|
+
}
|
|
27
|
+
function usage(message) {
|
|
28
|
+
const used = message.usage;
|
|
29
|
+
if (!used) return void 0;
|
|
30
|
+
return {
|
|
31
|
+
input: used.input ?? 0,
|
|
32
|
+
output: used.output ?? 0,
|
|
33
|
+
cost: used.cost?.total ?? 0,
|
|
34
|
+
cacheRead: used.cacheRead ?? 0,
|
|
35
|
+
cacheWrite: used.cacheWrite ?? 0
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
const statuses = { error: "error", aborted: "stopped" };
|
|
39
|
+
function assistant(id, message, status) {
|
|
40
|
+
const blocks = Array.isArray(message.content) ? message.content : [];
|
|
41
|
+
const parts = blocks.map(part).filter((item) => item !== void 0);
|
|
42
|
+
if (message.errorMessage)
|
|
43
|
+
parts.push({ type: "error", message: message.errorMessage, action: "retry" });
|
|
44
|
+
const used = usage(message);
|
|
45
|
+
return {
|
|
46
|
+
id,
|
|
47
|
+
role: "assistant",
|
|
48
|
+
parts,
|
|
49
|
+
status: status ?? statuses[message.stopReason ?? ""] ?? "done",
|
|
50
|
+
createdAt: message.timestamp ?? 0,
|
|
51
|
+
...message.provider && message.model ? { model: `${message.provider}/${message.model}` } : {},
|
|
52
|
+
...used ? { usage: used } : {}
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
function user(id, message) {
|
|
56
|
+
return { id, role: "user", text: textOf(message.content), createdAt: message.timestamp ?? 0 };
|
|
57
|
+
}
|
|
58
|
+
function system(id, entry, text) {
|
|
59
|
+
const reason = entry.data?.reason;
|
|
60
|
+
return {
|
|
61
|
+
id,
|
|
62
|
+
role: "system",
|
|
63
|
+
kind: "compaction",
|
|
64
|
+
text,
|
|
65
|
+
createdAt: 0,
|
|
66
|
+
state: "summarized",
|
|
67
|
+
...reason ? { trigger: reason } : {}
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
function tools(messages) {
|
|
71
|
+
const found = /* @__PURE__ */ new Map();
|
|
72
|
+
for (const message of messages) {
|
|
73
|
+
if (message.role !== "assistant") continue;
|
|
74
|
+
for (const item of message.parts) if (item.type === "tool") found.set(item.tool.id, item.tool);
|
|
75
|
+
}
|
|
76
|
+
return found;
|
|
77
|
+
}
|
|
78
|
+
function settle(calls, result) {
|
|
79
|
+
const call = calls.get(result.toolCallId ?? "");
|
|
80
|
+
if (!call) return;
|
|
81
|
+
call.output = textOf(result.content);
|
|
82
|
+
call.status = result.isError ? "error" : "done";
|
|
83
|
+
}
|
|
84
|
+
function entryMessage(entry, out, calls) {
|
|
85
|
+
const id = `e${entry.id}`;
|
|
86
|
+
const model = entry.model?.[0];
|
|
87
|
+
if (entry.kind === "pi.user" && model) out.push(user(id, model));
|
|
88
|
+
else if (entry.kind === "pi.assistant" && model) {
|
|
89
|
+
const message = assistant(id, model);
|
|
90
|
+
out.push(message);
|
|
91
|
+
for (const [key, value] of tools([message])) calls.set(key, value);
|
|
92
|
+
} else if (entry.kind === "pi.tool-result" && model) settle(calls, model);
|
|
93
|
+
else if (entry.kind === "pi.compaction") out.push(system(id, entry, textOf(model?.content)));
|
|
94
|
+
}
|
|
95
|
+
const slotStatus = {
|
|
96
|
+
pending: "running",
|
|
97
|
+
running: "running",
|
|
98
|
+
done: "done"
|
|
99
|
+
};
|
|
100
|
+
function live(view, out, calls) {
|
|
101
|
+
const state = view.docs["pi.live"];
|
|
102
|
+
for (const slot of state?.tools ?? []) {
|
|
103
|
+
const call = calls.get(slot.callId);
|
|
104
|
+
if (call && call.status === "running") {
|
|
105
|
+
call.status = slotStatus[slot.status] ?? "running";
|
|
106
|
+
call.output = slot.output ?? call.output;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
const partial = state?.generation?.message;
|
|
110
|
+
if (partial) out.push(assistant("live", partial, "streaming"));
|
|
111
|
+
for (const compaction of state?.compactions ?? []) {
|
|
112
|
+
out.push({
|
|
113
|
+
id: `compaction-${compaction.taskId}`,
|
|
114
|
+
role: "system",
|
|
115
|
+
kind: "compaction",
|
|
116
|
+
text: "",
|
|
117
|
+
createdAt: 0,
|
|
118
|
+
state: "summarizing",
|
|
119
|
+
trigger: compaction.reason
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
const retry = state?.generation?.retry;
|
|
123
|
+
if (retry)
|
|
124
|
+
out.push({
|
|
125
|
+
id: "retry",
|
|
126
|
+
role: "system",
|
|
127
|
+
kind: "notice",
|
|
128
|
+
text: retry.error,
|
|
129
|
+
createdAt: retry.at
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
function toMessages(view) {
|
|
133
|
+
const out = [];
|
|
134
|
+
if (!view) return out;
|
|
135
|
+
const calls = /* @__PURE__ */ new Map();
|
|
136
|
+
for (const entry of view.entries) entryMessage(entry, out, calls);
|
|
137
|
+
live(view, out, calls);
|
|
138
|
+
return out;
|
|
139
|
+
}
|
|
140
|
+
function isBusy(view) {
|
|
141
|
+
return Boolean(view?.docs["pi.live"]?.run);
|
|
142
|
+
}
|
|
143
|
+
function queued(view) {
|
|
144
|
+
const items = view?.docs["pi.inbox"]?.items ?? [];
|
|
145
|
+
return items.filter((item) => item.mode !== "write").map((item) => ({
|
|
146
|
+
id: `q${item.id}`,
|
|
147
|
+
role: "user",
|
|
148
|
+
text: textOf(item.content),
|
|
149
|
+
createdAt: 0,
|
|
150
|
+
queued: true,
|
|
151
|
+
mode: item.mode === "steer" ? "steer" : "queue"
|
|
152
|
+
}));
|
|
153
|
+
}
|
|
154
|
+
export {
|
|
155
|
+
assistant,
|
|
156
|
+
isBusy,
|
|
157
|
+
queued,
|
|
158
|
+
textOf,
|
|
159
|
+
toMessages
|
|
160
|
+
};
|
|
161
|
+
//# sourceMappingURL=messages.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/spectrum/messages.ts"],
|
|
4
|
+
"sourcesContent": ["import type {\n AssistantMessage,\n AssistantStatus,\n Message,\n MessagePart,\n SystemMessage,\n ToolCall,\n ToolStatus,\n Usage,\n UserMessage,\n} from '@ai-ecoverse/slicc-spectrum/ui';\nimport type { ConversationView, EntryRecord } from '@earendil-works/pi-durable';\n\ntype Json = Record<string, unknown>;\n\ninterface Block {\n type: string;\n text?: string;\n thinking?: string;\n id?: string;\n name?: string;\n arguments?: Json;\n}\n\ninterface ModelMessage {\n role: string;\n content?: string | Block[];\n timestamp?: number;\n stopReason?: string;\n errorMessage?: string;\n provider?: string;\n model?: string;\n usage?: {\n input?: number;\n output?: number;\n cacheRead?: number;\n cacheWrite?: number;\n cost?: { total?: number };\n };\n toolCallId?: string;\n isError?: boolean;\n}\n\ninterface Slot {\n callId: string;\n status: string;\n output?: string;\n}\n\ninterface Live {\n run?: unknown;\n generation?: { message?: ModelMessage; retry?: { at: number; error: string } };\n tools?: Slot[];\n compactions?: { taskId: number; reason: string }[];\n}\n\nexport function textOf(content: ModelMessage['content']): string {\n if (typeof content === 'string') return content;\n return (content ?? []).map((block) => (block.type === 'text' ? (block.text ?? '') : '')).join('');\n}\n\nconst paths = (args: Json | undefined): string[] =>\n typeof args?.path === 'string' ? [args.path] : [];\n\nfunction title(name: string, args: Json | undefined): string {\n const subject = args?.command ?? args?.path;\n return typeof subject === 'string' ? `${name} ${subject}` : name;\n}\n\nfunction toolCall(block: Block): ToolCall {\n return {\n id: block.id ?? '',\n name: block.name ?? 'tool',\n title: title(block.name ?? 'tool', block.arguments),\n input: JSON.stringify(block.arguments ?? {}),\n output: '',\n status: 'running',\n paths: paths(block.arguments),\n };\n}\n\nfunction part(block: Block): MessagePart | undefined {\n if (block.type === 'text') return { type: 'text', text: block.text ?? '' };\n if (block.type === 'thinking') return { type: 'thinking', text: block.thinking ?? '' };\n if (block.type === 'toolCall') return { type: 'tool', tool: toolCall(block) };\n return undefined;\n}\n\nfunction usage(message: ModelMessage): Usage | undefined {\n const used = message.usage;\n if (!used) return undefined;\n return {\n input: used.input ?? 0,\n output: used.output ?? 0,\n cost: used.cost?.total ?? 0,\n cacheRead: used.cacheRead ?? 0,\n cacheWrite: used.cacheWrite ?? 0,\n };\n}\n\nconst statuses: Record<string, AssistantStatus> = { error: 'error', aborted: 'stopped' };\n\nexport function assistant(\n id: string,\n message: ModelMessage,\n status?: AssistantStatus\n): AssistantMessage {\n const blocks = Array.isArray(message.content) ? message.content : [];\n const parts = blocks.map(part).filter((item): item is MessagePart => item !== undefined);\n if (message.errorMessage)\n parts.push({ type: 'error', message: message.errorMessage, action: 'retry' });\n const used = usage(message);\n return {\n id,\n role: 'assistant',\n parts,\n status: status ?? statuses[message.stopReason ?? ''] ?? 'done',\n createdAt: message.timestamp ?? 0,\n ...(message.provider && message.model ? { model: `${message.provider}/${message.model}` } : {}),\n ...(used ? { usage: used } : {}),\n };\n}\n\nfunction user(id: string, message: ModelMessage): UserMessage {\n return { id, role: 'user', text: textOf(message.content), createdAt: message.timestamp ?? 0 };\n}\n\nfunction system(id: string, entry: EntryRecord, text: string): SystemMessage {\n const reason = (entry.data as Json | undefined)?.reason as SystemMessage['trigger'] | undefined;\n return {\n id,\n role: 'system',\n kind: 'compaction',\n text,\n createdAt: 0,\n state: 'summarized',\n ...(reason ? { trigger: reason } : {}),\n };\n}\n\nfunction tools(messages: Message[]): Map<string, ToolCall> {\n const found = new Map<string, ToolCall>();\n for (const message of messages) {\n if (message.role !== 'assistant') continue;\n for (const item of message.parts) if (item.type === 'tool') found.set(item.tool.id, item.tool);\n }\n return found;\n}\n\nfunction settle(calls: Map<string, ToolCall>, result: ModelMessage): void {\n const call = calls.get(result.toolCallId ?? '');\n if (!call) return;\n call.output = textOf(result.content);\n call.status = result.isError ? 'error' : 'done';\n}\n\nfunction entryMessage(entry: EntryRecord, out: Message[], calls: Map<string, ToolCall>): void {\n const id = `e${entry.id}`;\n const model = entry.model?.[0] as ModelMessage | undefined;\n if (entry.kind === 'pi.user' && model) out.push(user(id, model));\n else if (entry.kind === 'pi.assistant' && model) {\n const message = assistant(id, model);\n out.push(message);\n for (const [key, value] of tools([message])) calls.set(key, value);\n } else if (entry.kind === 'pi.tool-result' && model) settle(calls, model);\n else if (entry.kind === 'pi.compaction') out.push(system(id, entry, textOf(model?.content)));\n}\n\nconst slotStatus: Record<string, ToolStatus> = {\n pending: 'running',\n running: 'running',\n done: 'done',\n};\n\nfunction live(view: ConversationView, out: Message[], calls: Map<string, ToolCall>): void {\n const state = view.docs['pi.live'] as Live | undefined;\n for (const slot of state?.tools ?? []) {\n const call = calls.get(slot.callId);\n if (call && call.status === 'running') {\n call.status = slotStatus[slot.status] ?? 'running';\n call.output = slot.output ?? call.output;\n }\n }\n const partial = state?.generation?.message;\n if (partial) out.push(assistant('live', partial, 'streaming'));\n for (const compaction of state?.compactions ?? []) {\n out.push({\n id: `compaction-${compaction.taskId}`,\n role: 'system',\n kind: 'compaction',\n text: '',\n createdAt: 0,\n state: 'summarizing',\n trigger: compaction.reason as SystemMessage['trigger'],\n });\n }\n const retry = state?.generation?.retry;\n if (retry)\n out.push({\n id: 'retry',\n role: 'system',\n kind: 'notice',\n text: retry.error,\n createdAt: retry.at,\n });\n}\n\nexport function toMessages(view: ConversationView | undefined): Message[] {\n const out: Message[] = [];\n if (!view) return out;\n const calls = new Map<string, ToolCall>();\n for (const entry of view.entries) entryMessage(entry, out, calls);\n live(view, out, calls);\n return out;\n}\n\nexport function isBusy(view: ConversationView | undefined): boolean {\n return Boolean((view?.docs['pi.live'] as Live | undefined)?.run);\n}\n\nexport function queued(view: ConversationView | undefined): UserMessage[] {\n const items = ((view?.docs['pi.inbox'] as { items?: Json[] } | undefined)?.items ?? []) as {\n id: number;\n mode: string;\n content?: ModelMessage['content'];\n }[];\n return items\n .filter((item) => item.mode !== 'write')\n .map((item) => ({\n id: `q${item.id}`,\n role: 'user',\n text: textOf(item.content),\n createdAt: 0,\n queued: true,\n mode: item.mode === 'steer' ? 'steer' : 'queue',\n }));\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ export { type AgentConnection, connectAgent } from './client.ts';
|
|
|
3
3
|
export { createAgentControl } from './control.ts';
|
|
4
4
|
export { type AgentHost, hostAgent } from './host.ts';
|
|
5
5
|
export { AGENT_LOCK, type AgentOwner, type AgentWorker, type OwnerOptions, startAgent, } from './owner.ts';
|
|
6
|
-
export { AGENT_SESSION, AgentControl, AgentSessions, AgentTranscript, type OperationError, type PromptResult, type SendMode, type SendRequest, type SendResponse, } from './services.ts';
|
|
6
|
+
export { AGENT_SESSION, AgentControl, AgentSessions, type AgentSettingsChange, AgentTranscript, type OperationError, type PromptResult, type SendMode, type SendRequest, type SendResponse, } from './services.ts';
|
|
7
7
|
export { AGENT_DIRECTORY, type OpfsSqliteOptions, openMemorySqliteStorage, openOpfsSqliteStorage, WasmSqliteDatabase, } from './sqlite.ts';
|
|
8
8
|
export { PortChannel, type PortEndpoint, PortListener, withUnrefTimers } from './wire.ts';
|
|
9
9
|
export { serveConnections, type WorkerScope } from './worker.ts';
|
package/dist/types/services.d.ts
CHANGED
|
@@ -36,6 +36,15 @@ export interface AgentControl {
|
|
|
36
36
|
}>;
|
|
37
37
|
abort(context: Context): Promise<void>;
|
|
38
38
|
compact(instructions: string | null, context: Context): Promise<SendResponse>;
|
|
39
|
+
reset(handoff: string | null, context: Context): Promise<void>;
|
|
40
|
+
configure(change: AgentSettingsChange, context: Context): Promise<void>;
|
|
41
|
+
}
|
|
42
|
+
export interface AgentSettingsChange {
|
|
43
|
+
model: {
|
|
44
|
+
provider: string;
|
|
45
|
+
modelId: string;
|
|
46
|
+
} | null;
|
|
47
|
+
thinkingLevel: 'off' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh' | 'max' | null;
|
|
39
48
|
}
|
|
40
49
|
export declare const AgentControl: import("@earendil-works/chord").Service<AgentControl>;
|
|
41
50
|
export interface AgentTranscript {
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { Agent, AgentEvents, AgentPort, FrozenCone, Message, Outgoing, SlashCommand, Thinking, UserMessage } from '@ai-ecoverse/slicc-spectrum/ui';
|
|
2
|
+
import type { AgentConnection } from '../client.ts';
|
|
3
|
+
import { Emitter } from './emitter.ts';
|
|
4
|
+
export declare const CONE = "cone";
|
|
5
|
+
export declare class AgentAdapter extends Emitter<AgentEvents> implements AgentPort {
|
|
6
|
+
#private;
|
|
7
|
+
constructor(connection: AgentConnection);
|
|
8
|
+
ready(): Promise<void>;
|
|
9
|
+
list(): readonly Agent[];
|
|
10
|
+
active(): string;
|
|
11
|
+
select(): void;
|
|
12
|
+
messages(): readonly Message[];
|
|
13
|
+
send(_agentId: string, input: string | Outgoing): Promise<void>;
|
|
14
|
+
stop(): void;
|
|
15
|
+
busy(): boolean;
|
|
16
|
+
queue(): readonly UserMessage[];
|
|
17
|
+
unqueue(_agentId: string, messageId: string): void;
|
|
18
|
+
suggestion(): string | null;
|
|
19
|
+
answer(): void;
|
|
20
|
+
resolveLick(): void;
|
|
21
|
+
compact(): void;
|
|
22
|
+
clear(): void;
|
|
23
|
+
setModel(_agentId: string, model: string): void;
|
|
24
|
+
setThinking(_agentId: string, level: Thinking): void;
|
|
25
|
+
older(): Promise<readonly Message[]>;
|
|
26
|
+
commands(): readonly SlashCommand[];
|
|
27
|
+
createScoop(): Agent;
|
|
28
|
+
frozen(): readonly FrozenCone[];
|
|
29
|
+
freeze(): void;
|
|
30
|
+
thaw(): Agent | null;
|
|
31
|
+
discard(): void;
|
|
32
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
type Listener<T> = (detail: T) => void;
|
|
2
|
+
export declare class Emitter<Events extends object> {
|
|
3
|
+
#private;
|
|
4
|
+
on<K extends keyof Events>(type: K, listener: Listener<Events[K]>): () => void;
|
|
5
|
+
emit<K extends keyof Events>(type: K, detail: Events[K]): void;
|
|
6
|
+
}
|
|
7
|
+
export {};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { AgentConnection } from '../client.ts';
|
|
2
|
+
import { AgentAdapter } from './agent-port.ts';
|
|
3
|
+
export { AgentAdapter, CONE } from './agent-port.ts';
|
|
4
|
+
export { assistant, isBusy, queued, textOf, toMessages } from './messages.ts';
|
|
5
|
+
export declare function createAgentModel(connection: AgentConnection): {
|
|
6
|
+
agent: AgentAdapter;
|
|
7
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { AssistantMessage, AssistantStatus, Message, UserMessage } from '@ai-ecoverse/slicc-spectrum/ui';
|
|
2
|
+
import type { ConversationView } from '@earendil-works/pi-durable';
|
|
3
|
+
type Json = Record<string, unknown>;
|
|
4
|
+
interface Block {
|
|
5
|
+
type: string;
|
|
6
|
+
text?: string;
|
|
7
|
+
thinking?: string;
|
|
8
|
+
id?: string;
|
|
9
|
+
name?: string;
|
|
10
|
+
arguments?: Json;
|
|
11
|
+
}
|
|
12
|
+
interface ModelMessage {
|
|
13
|
+
role: string;
|
|
14
|
+
content?: string | Block[];
|
|
15
|
+
timestamp?: number;
|
|
16
|
+
stopReason?: string;
|
|
17
|
+
errorMessage?: string;
|
|
18
|
+
provider?: string;
|
|
19
|
+
model?: string;
|
|
20
|
+
usage?: {
|
|
21
|
+
input?: number;
|
|
22
|
+
output?: number;
|
|
23
|
+
cacheRead?: number;
|
|
24
|
+
cacheWrite?: number;
|
|
25
|
+
cost?: {
|
|
26
|
+
total?: number;
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
toolCallId?: string;
|
|
30
|
+
isError?: boolean;
|
|
31
|
+
}
|
|
32
|
+
export declare function textOf(content: ModelMessage['content']): string;
|
|
33
|
+
export declare function assistant(id: string, message: ModelMessage, status?: AssistantStatus): AssistantMessage;
|
|
34
|
+
export declare function toMessages(view: ConversationView | undefined): Message[];
|
|
35
|
+
export declare function isBusy(view: ConversationView | undefined): boolean;
|
|
36
|
+
export declare function queued(view: ConversationView | undefined): UserMessage[];
|
|
37
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ai-ecoverse/slicc-agent",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "SLICC's agent core on pi durable: an agent worker, session storage, remoting and pi extensions",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -25,6 +25,10 @@
|
|
|
25
25
|
".": {
|
|
26
26
|
"types": "./dist/types/index.d.ts",
|
|
27
27
|
"default": "./dist/index.js"
|
|
28
|
+
},
|
|
29
|
+
"./spectrum": {
|
|
30
|
+
"types": "./dist/types/spectrum/index.d.ts",
|
|
31
|
+
"default": "./dist/spectrum/index.js"
|
|
28
32
|
}
|
|
29
33
|
},
|
|
30
34
|
"files": [
|
|
@@ -47,6 +51,7 @@
|
|
|
47
51
|
},
|
|
48
52
|
"devDependencies": {
|
|
49
53
|
"@ai-ecoverse/slicc-shared-web": "1.5.0",
|
|
54
|
+
"@ai-ecoverse/slicc-spectrum": "1.7.0",
|
|
50
55
|
"@biomejs/biome": "2.5.15",
|
|
51
56
|
"@types/node": "24.19.1",
|
|
52
57
|
"esbuild": "0.28.2",
|
|
@@ -64,5 +69,8 @@
|
|
|
64
69
|
"@earendil-works/pi-protocol": "1.0.4",
|
|
65
70
|
"@earendil-works/pi-server": "1.0.4",
|
|
66
71
|
"@sqlite.org/sqlite-wasm": "3.53.4-build2"
|
|
72
|
+
},
|
|
73
|
+
"peerDependencies": {
|
|
74
|
+
"@ai-ecoverse/slicc-spectrum": "^1.7.0"
|
|
67
75
|
}
|
|
68
76
|
}
|