@ai-ecoverse/slicc-agent 2.2.0 → 2.3.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 +25 -1
- package/dist/agent-worker.js +6 -0
- package/dist/agent-worker.js.map +7 -0
- package/dist/client.js +4 -1
- package/dist/client.js.map +2 -2
- package/dist/credentials.js +100 -0
- package/dist/credentials.js.map +7 -0
- package/dist/host.js +14 -2
- package/dist/host.js.map +2 -2
- package/dist/index.js +25 -0
- package/dist/index.js.map +2 -2
- package/dist/main.js +46 -0
- package/dist/main.js.map +7 -0
- package/dist/net.js +39 -0
- package/dist/net.js.map +7 -0
- package/dist/prompt.js +18 -0
- package/dist/prompt.js.map +7 -0
- package/dist/settings.js +77 -0
- package/dist/settings.js.map +7 -0
- package/dist/spectrum/index.js +10 -2
- package/dist/spectrum/index.js.map +3 -3
- package/dist/spectrum/settings-port.js +73 -0
- package/dist/spectrum/settings-port.js.map +7 -0
- package/dist/types/agent-worker.d.ts +1 -0
- package/dist/types/client.d.ts +2 -0
- package/dist/types/credentials.d.ts +12 -0
- package/dist/types/host.d.ts +2 -0
- package/dist/types/index.d.ts +5 -0
- package/dist/types/main.d.ts +23 -0
- package/dist/types/net.d.ts +19 -0
- package/dist/types/prompt.d.ts +1 -0
- package/dist/types/settings.d.ts +37 -0
- package/dist/types/spectrum/index.d.ts +6 -1
- package/dist/types/spectrum/settings-port.d.ts +17 -0
- package/package.json +7 -2
package/README.md
CHANGED
|
@@ -57,6 +57,28 @@ const agent = await openAgent({ models, model, storage, registry, env: kernelEnv
|
|
|
57
57
|
|
|
58
58
|
A conversation without a `cwd` works in `/home`.
|
|
59
59
|
|
|
60
|
+
### The worker seven starts
|
|
61
|
+
|
|
62
|
+
`@ai-ecoverse/slicc-agent/agent-worker` is a complete agent worker. It waits for the page kernel's port, then:
|
|
63
|
+
- attaches to the kernel and routes its cross-origin `fetch` through the kernel's transport when that transport isn't bound by CORS (slicc-node, slicc-swift or slicc-extension);
|
|
64
|
+
- opens the encrypted credential store, the AWS Bedrock provider and the session in OPFS SQLite;
|
|
65
|
+
- installs durable's coding tools and SLICC's system prompt, and serves the agent.
|
|
66
|
+
|
|
67
|
+
```js
|
|
68
|
+
const owner = await startAgent({
|
|
69
|
+
worker: () => new Worker(new URL('@ai-ecoverse/slicc-agent/agent-worker', import.meta.url), { type: 'module' }),
|
|
70
|
+
kernel: { connect: () => kernel.connect() },
|
|
71
|
+
});
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
`runAgentWorker(self, options)` is the same with its parts replaceable (model, providers, kernel attach, credentials, storage).
|
|
75
|
+
|
|
76
|
+
**Providers.** The first provider is AWS Bedrock with a Bedrock API key as the bearer token; the default model is `us.anthropic.claude-sonnet-5-5`. Bedrock sends no CORS headers, so it needs a CORS-free transport, and its account says so (`needs: 'cors-free-transport'`).
|
|
77
|
+
|
|
78
|
+
**Credentials.** They live in the IndexedDB database `slicc-agent-credentials`, sealed with AES-GCM under a non-extractable key that never leaves WebCrypto. They never enter the session database or the transcript, and followers never see them.
|
|
79
|
+
|
|
80
|
+
**Settings.** The `slicc.agent.settings` service shows the models and accounts and takes `connect(providerId, apiKey)` and `disconnect(providerId)`.
|
|
81
|
+
|
|
60
82
|
### In slicc-spectrum
|
|
61
83
|
|
|
62
84
|
`@ai-ecoverse/slicc-agent/spectrum` turns an `AgentConnection` into slicc-spectrum's `AgentPort`, so `<slicc-app>` shows the real agent:
|
|
@@ -65,9 +87,11 @@ A conversation without a `cwd` works in `/home`.
|
|
|
65
87
|
import { createAgentModel } from '@ai-ecoverse/slicc-agent/spectrum';
|
|
66
88
|
|
|
67
89
|
const agent = await owner.connect();
|
|
68
|
-
app.model = { ...createKernelModel({ kernel, root }), ...createAgentModel(agent) };
|
|
90
|
+
app.model = { ...createKernelModel({ kernel, root }), ...createAgentModel(agent, { storage: localStorage }) };
|
|
69
91
|
```
|
|
70
92
|
|
|
93
|
+
`createAgentModel()` returns the `agent` and `settings` ports. Settings keeps the UI preferences in `storage`; model and thinking belong to the conversation, and accounts and models come from the worker.
|
|
94
|
+
|
|
71
95
|
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.
|
|
72
96
|
|
|
73
97
|
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`.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/agent-worker.ts"],
|
|
4
|
+
"sourcesContent": ["import { type AgentWorkerScope, runAgentWorker } from './main.ts';\n\nexport const host = runAgentWorker(globalThis as unknown as AgentWorkerScope);\n"],
|
|
5
|
+
"mappings": "AAAA,SAAgC,sBAAsB;AAE/C,MAAM,OAAO,eAAe,UAAyC;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/dist/client.js
CHANGED
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
AgentSessions,
|
|
10
10
|
AgentTranscript
|
|
11
11
|
} from "./services.js";
|
|
12
|
+
import { AgentSettings } from "./settings.js";
|
|
12
13
|
import { PortChannel } from "./wire.js";
|
|
13
14
|
function attached(client) {
|
|
14
15
|
return new Promise((resolve) => {
|
|
@@ -32,17 +33,19 @@ async function connectAgent(endpoint, options = {}) {
|
|
|
32
33
|
await server.use(AgentSessions).attach(AGENT_SESSION, context);
|
|
33
34
|
await ready;
|
|
34
35
|
const session = createRemoteServiceBinding({
|
|
35
|
-
services: [AgentControl, AgentTranscript],
|
|
36
|
+
services: [AgentControl, AgentTranscript, AgentSettings],
|
|
36
37
|
transport: createClientServiceTransport(client, () => client.attachment),
|
|
37
38
|
bound: true
|
|
38
39
|
});
|
|
39
40
|
const control = session.use(AgentControl);
|
|
40
41
|
const transcript = session.use(AgentTranscript).state;
|
|
42
|
+
const settings = session.use(AgentSettings);
|
|
41
43
|
await session.ready(context);
|
|
42
44
|
return {
|
|
43
45
|
serverId,
|
|
44
46
|
control,
|
|
45
47
|
transcript,
|
|
48
|
+
settings,
|
|
46
49
|
async prompt(text, whenBusy = "followUp") {
|
|
47
50
|
const sent = await control.send({ text, whenBusy, requestId: null }, context);
|
|
48
51
|
if (!sent.accepted) throw new Error(`${sent.error.code}: ${sent.error.message}`);
|
package/dist/client.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/client.ts"],
|
|
4
|
-
"sourcesContent": ["import {\n type Context,\n createRemoteServiceBinding,\n type ReplicatedState,\n} from '@earendil-works/chord';\nimport { BACKGROUND_CONTEXT } from '@earendil-works/chord/context';\nimport { Client, createClientServiceTransport } from '@earendil-works/pi-client';\nimport type { ConversationView } from '@earendil-works/pi-durable';\nimport {\n AGENT_SESSION,\n AgentControl,\n AgentSessions,\n AgentTranscript,\n type SendMode,\n} from './services.ts';\nimport { PortChannel, type PortEndpoint } from './wire.ts';\n\nexport interface AgentConnection {\n readonly serverId: string;\n readonly control: AgentControl;\n readonly transcript: ReplicatedState<ConversationView>;\n prompt(text: string, whenBusy?: SendMode): Promise<string>;\n close(): Promise<void>;\n}\n\nfunction attached(client: Client): Promise<void> {\n return new Promise((resolve) => {\n const stop = client.onAttachmentChange(() => {\n stop();\n resolve();\n });\n });\n}\n\nexport async function connectAgent(\n endpoint: PortEndpoint,\n options: { context?: Context } = {}\n): Promise<AgentConnection> {\n const context = options.context ?? BACKGROUND_CONTEXT;\n const channel = new PortChannel(endpoint);\n const serverId = await channel.hello;\n const client = await Client.connect({ serverId, transportFactory: channel.transport });\n const server = createRemoteServiceBinding({\n services: [AgentSessions],\n transport: createClientServiceTransport(client, () => ({ serverId })),\n bound: true,\n });\n const ready = attached(client);\n await server.use(AgentSessions).attach(AGENT_SESSION, context);\n await ready;\n const session = createRemoteServiceBinding({\n services: [AgentControl, AgentTranscript],\n transport: createClientServiceTransport(client, () => client.attachment),\n bound: true,\n });\n const control = session.use(AgentControl);\n const transcript = session.use(AgentTranscript).state;\n await session.ready(context);\n return {\n serverId,\n control,\n transcript,\n async prompt(text, whenBusy = 'followUp') {\n const sent = await control.send({ text, whenBusy, requestId: null }, context);\n if (!sent.accepted) throw new Error(`${sent.error.code}: ${sent.error.message}`);\n const settled = await control.wait(sent.submissionId, context);\n if (settled.status !== 'done') throw new Error(`unanswered: ${settled.reason}`);\n return settled.text;\n },\n async close() {\n await server.use(AgentSessions).detach(context);\n await session.dispose(context);\n await server.dispose(context);\n await client.dispose();\n },\n };\n}\n"],
|
|
5
|
-
"mappings": "AAAA;AAAA,EAEE;AAAA,OAEK;AACP,SAAS,0BAA0B;AACnC,SAAS,QAAQ,oCAAoC;AAErD;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AACP,SAAS,mBAAsC;
|
|
4
|
+
"sourcesContent": ["import {\n type Context,\n createRemoteServiceBinding,\n type ReplicatedState,\n} from '@earendil-works/chord';\nimport { BACKGROUND_CONTEXT } from '@earendil-works/chord/context';\nimport { Client, createClientServiceTransport } from '@earendil-works/pi-client';\nimport type { ConversationView } from '@earendil-works/pi-durable';\nimport {\n AGENT_SESSION,\n AgentControl,\n AgentSessions,\n AgentTranscript,\n type SendMode,\n} from './services.ts';\nimport { AgentSettings } from './settings.ts';\nimport { PortChannel, type PortEndpoint } from './wire.ts';\n\nexport interface AgentConnection {\n readonly serverId: string;\n readonly control: AgentControl;\n readonly transcript: ReplicatedState<ConversationView>;\n readonly settings: AgentSettings;\n prompt(text: string, whenBusy?: SendMode): Promise<string>;\n close(): Promise<void>;\n}\n\nfunction attached(client: Client): Promise<void> {\n return new Promise((resolve) => {\n const stop = client.onAttachmentChange(() => {\n stop();\n resolve();\n });\n });\n}\n\nexport async function connectAgent(\n endpoint: PortEndpoint,\n options: { context?: Context } = {}\n): Promise<AgentConnection> {\n const context = options.context ?? BACKGROUND_CONTEXT;\n const channel = new PortChannel(endpoint);\n const serverId = await channel.hello;\n const client = await Client.connect({ serverId, transportFactory: channel.transport });\n const server = createRemoteServiceBinding({\n services: [AgentSessions],\n transport: createClientServiceTransport(client, () => ({ serverId })),\n bound: true,\n });\n const ready = attached(client);\n await server.use(AgentSessions).attach(AGENT_SESSION, context);\n await ready;\n const session = createRemoteServiceBinding({\n services: [AgentControl, AgentTranscript, AgentSettings],\n transport: createClientServiceTransport(client, () => client.attachment),\n bound: true,\n });\n const control = session.use(AgentControl);\n const transcript = session.use(AgentTranscript).state;\n const settings = session.use(AgentSettings);\n await session.ready(context);\n return {\n serverId,\n control,\n transcript,\n settings,\n async prompt(text, whenBusy = 'followUp') {\n const sent = await control.send({ text, whenBusy, requestId: null }, context);\n if (!sent.accepted) throw new Error(`${sent.error.code}: ${sent.error.message}`);\n const settled = await control.wait(sent.submissionId, context);\n if (settled.status !== 'done') throw new Error(`unanswered: ${settled.reason}`);\n return settled.text;\n },\n async close() {\n await server.use(AgentSessions).detach(context);\n await session.dispose(context);\n await server.dispose(context);\n await client.dispose();\n },\n };\n}\n"],
|
|
5
|
+
"mappings": "AAAA;AAAA,EAEE;AAAA,OAEK;AACP,SAAS,0BAA0B;AACnC,SAAS,QAAQ,oCAAoC;AAErD;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AACP,SAAS,qBAAqB;AAC9B,SAAS,mBAAsC;AAW/C,SAAS,SAAS,QAA+B;AAC/C,SAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,UAAM,OAAO,OAAO,mBAAmB,MAAM;AAC3C,WAAK;AACL,cAAQ;AAAA,IACV,CAAC;AAAA,EACH,CAAC;AACH;AAEA,eAAsB,aACpB,UACA,UAAiC,CAAC,GACR;AAC1B,QAAM,UAAU,QAAQ,WAAW;AACnC,QAAM,UAAU,IAAI,YAAY,QAAQ;AACxC,QAAM,WAAW,MAAM,QAAQ;AAC/B,QAAM,SAAS,MAAM,OAAO,QAAQ,EAAE,UAAU,kBAAkB,QAAQ,UAAU,CAAC;AACrF,QAAM,SAAS,2BAA2B;AAAA,IACxC,UAAU,CAAC,aAAa;AAAA,IACxB,WAAW,6BAA6B,QAAQ,OAAO,EAAE,SAAS,EAAE;AAAA,IACpE,OAAO;AAAA,EACT,CAAC;AACD,QAAM,QAAQ,SAAS,MAAM;AAC7B,QAAM,OAAO,IAAI,aAAa,EAAE,OAAO,eAAe,OAAO;AAC7D,QAAM;AACN,QAAM,UAAU,2BAA2B;AAAA,IACzC,UAAU,CAAC,cAAc,iBAAiB,aAAa;AAAA,IACvD,WAAW,6BAA6B,QAAQ,MAAM,OAAO,UAAU;AAAA,IACvE,OAAO;AAAA,EACT,CAAC;AACD,QAAM,UAAU,QAAQ,IAAI,YAAY;AACxC,QAAM,aAAa,QAAQ,IAAI,eAAe,EAAE;AAChD,QAAM,WAAW,QAAQ,IAAI,aAAa;AAC1C,QAAM,QAAQ,MAAM,OAAO;AAC3B,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,MAAM,OAAO,MAAM,WAAW,YAAY;AACxC,YAAM,OAAO,MAAM,QAAQ,KAAK,EAAE,MAAM,UAAU,WAAW,KAAK,GAAG,OAAO;AAC5E,UAAI,CAAC,KAAK,SAAU,OAAM,IAAI,MAAM,GAAG,KAAK,MAAM,IAAI,KAAK,KAAK,MAAM,OAAO,EAAE;AAC/E,YAAM,UAAU,MAAM,QAAQ,KAAK,KAAK,cAAc,OAAO;AAC7D,UAAI,QAAQ,WAAW,OAAQ,OAAM,IAAI,MAAM,eAAe,QAAQ,MAAM,EAAE;AAC9E,aAAO,QAAQ;AAAA,IACjB;AAAA,IACA,MAAM,QAAQ;AACZ,YAAM,OAAO,IAAI,aAAa,EAAE,OAAO,OAAO;AAC9C,YAAM,QAAQ,QAAQ,OAAO;AAC7B,YAAM,OAAO,QAAQ,OAAO;AAC5B,YAAM,OAAO,QAAQ;AAAA,IACvB;AAAA,EACF;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
const CREDENTIALS_DATABASE = "slicc-agent-credentials";
|
|
2
|
+
function request(operation) {
|
|
3
|
+
return new Promise((resolve, reject) => {
|
|
4
|
+
operation.onsuccess = () => resolve(operation.result);
|
|
5
|
+
operation.onerror = () => reject(operation.error);
|
|
6
|
+
});
|
|
7
|
+
}
|
|
8
|
+
function open(name) {
|
|
9
|
+
const opening = indexedDB.open(name, 1);
|
|
10
|
+
opening.onupgradeneeded = () => {
|
|
11
|
+
opening.result.createObjectStore("keys");
|
|
12
|
+
opening.result.createObjectStore("credentials");
|
|
13
|
+
};
|
|
14
|
+
return request(opening);
|
|
15
|
+
}
|
|
16
|
+
async function sealingKey(db) {
|
|
17
|
+
const keys = db.transaction("keys", "readonly").objectStore("keys");
|
|
18
|
+
const existing = await request(keys.get("aes"));
|
|
19
|
+
if (existing) return existing;
|
|
20
|
+
const key = await crypto.subtle.generateKey({ name: "AES-GCM", length: 256 }, false, [
|
|
21
|
+
"encrypt",
|
|
22
|
+
"decrypt"
|
|
23
|
+
]);
|
|
24
|
+
const store = db.transaction("keys", "readwrite").objectStore("keys");
|
|
25
|
+
await request(store.add(key, "aes")).catch(() => void 0);
|
|
26
|
+
return await request(
|
|
27
|
+
db.transaction("keys", "readonly").objectStore("keys").get("aes")
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
class EncryptedCredentialStore {
|
|
31
|
+
#db;
|
|
32
|
+
#key;
|
|
33
|
+
#chains = /* @__PURE__ */ new Map();
|
|
34
|
+
constructor(db, key) {
|
|
35
|
+
this.#db = db;
|
|
36
|
+
this.#key = key;
|
|
37
|
+
}
|
|
38
|
+
static async open(name = CREDENTIALS_DATABASE) {
|
|
39
|
+
const db = await open(name);
|
|
40
|
+
return new EncryptedCredentialStore(db, await sealingKey(db));
|
|
41
|
+
}
|
|
42
|
+
#store(mode) {
|
|
43
|
+
return this.#db.transaction("credentials", mode).objectStore("credentials");
|
|
44
|
+
}
|
|
45
|
+
async read(providerId) {
|
|
46
|
+
const sealed = await request(this.#store("readonly").get(providerId));
|
|
47
|
+
if (!sealed) return void 0;
|
|
48
|
+
const plain = await crypto.subtle.decrypt(
|
|
49
|
+
{ name: "AES-GCM", iv: sealed.iv },
|
|
50
|
+
this.#key,
|
|
51
|
+
sealed.data
|
|
52
|
+
);
|
|
53
|
+
return JSON.parse(new TextDecoder().decode(plain));
|
|
54
|
+
}
|
|
55
|
+
async list() {
|
|
56
|
+
const ids = await request(this.#store("readonly").getAllKeys());
|
|
57
|
+
const found = [];
|
|
58
|
+
for (const providerId of ids) {
|
|
59
|
+
const credential = await this.read(providerId);
|
|
60
|
+
if (credential) found.push({ providerId, type: credential.type });
|
|
61
|
+
}
|
|
62
|
+
return found;
|
|
63
|
+
}
|
|
64
|
+
#serial(providerId, operation) {
|
|
65
|
+
const result = (this.#chains.get(providerId) ?? Promise.resolve()).then(operation);
|
|
66
|
+
this.#chains.set(
|
|
67
|
+
providerId,
|
|
68
|
+
result.catch(() => void 0)
|
|
69
|
+
);
|
|
70
|
+
return result;
|
|
71
|
+
}
|
|
72
|
+
modify(providerId, fn) {
|
|
73
|
+
return this.#serial(providerId, async () => {
|
|
74
|
+
const current = await this.read(providerId);
|
|
75
|
+
const next = await fn(current);
|
|
76
|
+
if (next === void 0) return current;
|
|
77
|
+
const iv = crypto.getRandomValues(new Uint8Array(12));
|
|
78
|
+
const data = await crypto.subtle.encrypt(
|
|
79
|
+
{ name: "AES-GCM", iv },
|
|
80
|
+
this.#key,
|
|
81
|
+
new TextEncoder().encode(JSON.stringify(next))
|
|
82
|
+
);
|
|
83
|
+
await request(this.#store("readwrite").put({ iv, data }, providerId));
|
|
84
|
+
return next;
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
delete(providerId) {
|
|
88
|
+
return this.#serial(providerId, async () => {
|
|
89
|
+
await request(this.#store("readwrite").delete(providerId));
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
close() {
|
|
93
|
+
this.#db.close();
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
export {
|
|
97
|
+
CREDENTIALS_DATABASE,
|
|
98
|
+
EncryptedCredentialStore
|
|
99
|
+
};
|
|
100
|
+
//# sourceMappingURL=credentials.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/credentials.ts"],
|
|
4
|
+
"sourcesContent": ["import type { Credential, CredentialInfo, CredentialStore } from '@earendil-works/pi-ai';\n\nexport const CREDENTIALS_DATABASE = 'slicc-agent-credentials';\n\ninterface Sealed {\n iv: Uint8Array<ArrayBuffer>;\n data: ArrayBuffer;\n}\n\nfunction request<T>(operation: IDBRequest<T>): Promise<T> {\n return new Promise((resolve, reject) => {\n operation.onsuccess = () => resolve(operation.result);\n operation.onerror = () => reject(operation.error);\n });\n}\n\nfunction open(name: string): Promise<IDBDatabase> {\n const opening = indexedDB.open(name, 1);\n opening.onupgradeneeded = () => {\n opening.result.createObjectStore('keys');\n opening.result.createObjectStore('credentials');\n };\n return request(opening);\n}\n\nasync function sealingKey(db: IDBDatabase): Promise<CryptoKey> {\n const keys = db.transaction('keys', 'readonly').objectStore('keys');\n const existing = (await request(keys.get('aes'))) as CryptoKey | undefined;\n if (existing) return existing;\n const key = await crypto.subtle.generateKey({ name: 'AES-GCM', length: 256 }, false, [\n 'encrypt',\n 'decrypt',\n ]);\n const store = db.transaction('keys', 'readwrite').objectStore('keys');\n await request(store.add(key, 'aes')).catch(() => undefined);\n return (await request(\n db.transaction('keys', 'readonly').objectStore('keys').get('aes')\n )) as CryptoKey;\n}\n\nexport class EncryptedCredentialStore implements CredentialStore {\n readonly #db: IDBDatabase;\n readonly #key: CryptoKey;\n readonly #chains = new Map<string, Promise<unknown>>();\n\n private constructor(db: IDBDatabase, key: CryptoKey) {\n this.#db = db;\n this.#key = key;\n }\n\n static async open(name = CREDENTIALS_DATABASE): Promise<EncryptedCredentialStore> {\n const db = await open(name);\n return new EncryptedCredentialStore(db, await sealingKey(db));\n }\n\n #store(mode: IDBTransactionMode): IDBObjectStore {\n return this.#db.transaction('credentials', mode).objectStore('credentials');\n }\n\n async read(providerId: string): Promise<Credential | undefined> {\n const sealed = (await request(this.#store('readonly').get(providerId))) as Sealed | undefined;\n if (!sealed) return undefined;\n const plain = await crypto.subtle.decrypt(\n { name: 'AES-GCM', iv: sealed.iv },\n this.#key,\n sealed.data\n );\n return JSON.parse(new TextDecoder().decode(plain)) as Credential;\n }\n\n async list(): Promise<readonly CredentialInfo[]> {\n const ids = (await request(this.#store('readonly').getAllKeys())) as string[];\n const found: CredentialInfo[] = [];\n for (const providerId of ids) {\n const credential = await this.read(providerId);\n if (credential) found.push({ providerId, type: credential.type });\n }\n return found;\n }\n\n #serial<T>(providerId: string, operation: () => Promise<T>): Promise<T> {\n const result = (this.#chains.get(providerId) ?? Promise.resolve()).then(operation);\n this.#chains.set(\n providerId,\n result.catch(() => undefined)\n );\n return result;\n }\n\n modify(\n providerId: string,\n fn: (current: Credential | undefined) => Promise<Credential | undefined>\n ): Promise<Credential | undefined> {\n return this.#serial(providerId, async () => {\n const current = await this.read(providerId);\n const next = await fn(current);\n if (next === undefined) return current;\n const iv = crypto.getRandomValues(new Uint8Array(12));\n const data = await crypto.subtle.encrypt(\n { name: 'AES-GCM', iv },\n this.#key,\n new TextEncoder().encode(JSON.stringify(next))\n );\n await request(this.#store('readwrite').put({ iv, data } satisfies Sealed, providerId));\n return next;\n });\n }\n\n delete(providerId: string): Promise<void> {\n return this.#serial(providerId, async () => {\n await request(this.#store('readwrite').delete(providerId));\n });\n }\n\n close(): void {\n this.#db.close();\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/dist/host.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createRemoteServiceEndpoint,
|
|
3
|
-
RemoteServiceProvider
|
|
3
|
+
RemoteServiceProvider,
|
|
4
|
+
replicatedState
|
|
4
5
|
} from "@earendil-works/chord";
|
|
5
6
|
import { BACKGROUND_CONTEXT } from "@earendil-works/chord/context";
|
|
6
7
|
import {
|
|
@@ -9,6 +10,7 @@ import {
|
|
|
9
10
|
} from "@earendil-works/pi-server";
|
|
10
11
|
import { createAgentControl } from "./control.js";
|
|
11
12
|
import { AGENT_SESSION, AgentControl, AgentSessions, AgentTranscript } from "./services.js";
|
|
13
|
+
import { AgentSettings } from "./settings.js";
|
|
12
14
|
import { PortListener } from "./wire.js";
|
|
13
15
|
function endpointFor(provider) {
|
|
14
16
|
const endpoint = createRemoteServiceEndpoint(provider);
|
|
@@ -43,16 +45,26 @@ function serverServices() {
|
|
|
43
45
|
}
|
|
44
46
|
};
|
|
45
47
|
}
|
|
48
|
+
const noSettings = {
|
|
49
|
+
state: replicatedState({ models: [], accounts: [] }),
|
|
50
|
+
connect: async () => {
|
|
51
|
+
throw new Error("this agent has no accounts");
|
|
52
|
+
},
|
|
53
|
+
disconnect: async () => {
|
|
54
|
+
}
|
|
55
|
+
};
|
|
46
56
|
async function hostAgent(agent, options = {}) {
|
|
47
57
|
const context = options.context ?? BACKGROUND_CONTEXT;
|
|
48
58
|
const serverId = options.serverId ?? crypto.randomUUID();
|
|
49
59
|
const state = await agent.root.viewState(context);
|
|
50
60
|
const provider = new RemoteServiceProvider([
|
|
51
61
|
{ service: AgentControl, mode: "singleton" },
|
|
52
|
-
{ service: AgentTranscript, mode: "singleton" }
|
|
62
|
+
{ service: AgentTranscript, mode: "singleton" },
|
|
63
|
+
{ service: AgentSettings, mode: "singleton" }
|
|
53
64
|
]);
|
|
54
65
|
provider.provide(AgentControl, createAgentControl(agent.harness, agent.root));
|
|
55
66
|
provider.provide(AgentTranscript, { state });
|
|
67
|
+
provider.provide(AgentSettings, options.settings ?? noSettings);
|
|
56
68
|
const host = {
|
|
57
69
|
serverServices: serverServices(),
|
|
58
70
|
async resolveSession(sessionId) {
|
package/dist/host.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/host.ts"],
|
|
4
|
-
"sourcesContent": ["import {\n type Context,\n createRemoteServiceEndpoint,\n RemoteServiceProvider,\n} from '@earendil-works/chord';\nimport { BACKGROUND_CONTEXT } from '@earendil-works/chord/context';\nimport {\n type RoutedServerServiceHost,\n type RoutedSessionAttachment,\n type RoutedSessionHandle,\n Server,\n type ServerHost,\n SessionNotFoundError,\n} from '@earendil-works/pi-server';\nimport type { Agent } from './agent.ts';\nimport { createAgentControl } from './control.ts';\nimport { AGENT_SESSION, AgentControl, AgentSessions, AgentTranscript } from './services.ts';\nimport { type PortEndpoint, PortListener } from './wire.ts';\n\nexport interface AgentHost {\n readonly serverId: string;\n readonly agent: Agent;\n connect(endpoint: PortEndpoint): void;\n close(): Promise<void>;\n}\n\nfunction endpointFor(provider: RemoteServiceProvider): RoutedSessionAttachment {\n const endpoint = createRemoteServiceEndpoint(provider);\n return {\n invokeService: (call, publish, context) =>\n endpoint.invoke(call, (id, update) => publish(id, update, context), context),\n release: () => endpoint.dispose(),\n };\n}\n\nfunction sessionServices(provider: RemoteServiceProvider): RoutedSessionHandle {\n return {\n attachClient: () => endpointFor(provider),\n close: async () => {},\n };\n}\n\nfunction serverServices(): RoutedServerServiceHost {\n return {\n attachClient(presentation) {\n const provider = new RemoteServiceProvider([{ service: AgentSessions, mode: 'singleton' }]);\n provider.provide(AgentSessions, {\n attach: (sessionId, context) => presentation.attachSession(sessionId, context),\n detach: (context) => presentation.detachSession(context),\n });\n const attachment = endpointFor(provider);\n return {\n invokeService: attachment.invokeService,\n release(context) {\n attachment.release(context);\n provider.dispose();\n },\n };\n },\n };\n}\n\nexport async function hostAgent(\n agent: Agent,\n options: { serverId?: string; context?: Context } = {}\n): Promise<AgentHost> {\n const context = options.context ?? BACKGROUND_CONTEXT;\n const serverId = options.serverId ?? crypto.randomUUID();\n const state = await agent.root.viewState(context);\n const provider = new RemoteServiceProvider([\n { service: AgentControl, mode: 'singleton' },\n { service: AgentTranscript, mode: 'singleton' },\n ]);\n provider.provide(AgentControl, createAgentControl(agent.harness, agent.root));\n provider.provide(AgentTranscript, { state });\n const host: ServerHost = {\n serverServices: serverServices(),\n async resolveSession(sessionId) {\n if (sessionId !== AGENT_SESSION)\n throw new SessionNotFoundError(`unknown session ${sessionId}`);\n return { id: sessionId };\n },\n openSession: async () => sessionServices(provider),\n };\n const listener = new PortListener(serverId);\n const server = await new Server(host, { serverId, listeners: [listener] }).start();\n return {\n serverId,\n agent,\n connect: (endpoint) => listener.connect(endpoint),\n async close() {\n await server.close();\n provider.dispose();\n state.dispose();\n await agent.close();\n },\n };\n}\n"],
|
|
5
|
-
"mappings": "AAAA;AAAA,EAEE;AAAA,EACA;AAAA,OACK;AACP,SAAS,0BAA0B;AACnC;AAAA,EAIE;AAAA,EAEA;AAAA,OACK;AAEP,SAAS,0BAA0B;AACnC,SAAS,eAAe,cAAc,eAAe,uBAAuB;AAC5E,SAA4B,oBAAoB;AAShD,SAAS,YAAY,UAA0D;AAC7E,QAAM,WAAW,4BAA4B,QAAQ;AACrD,SAAO;AAAA,IACL,eAAe,CAAC,MAAM,SAAS,YAC7B,SAAS,OAAO,MAAM,CAAC,IAAI,WAAW,QAAQ,IAAI,QAAQ,OAAO,GAAG,OAAO;AAAA,IAC7E,SAAS,MAAM,SAAS,QAAQ;AAAA,EAClC;AACF;AAEA,SAAS,gBAAgB,UAAsD;AAC7E,SAAO;AAAA,IACL,cAAc,MAAM,YAAY,QAAQ;AAAA,IACxC,OAAO,YAAY;AAAA,IAAC;AAAA,EACtB;AACF;AAEA,SAAS,iBAA0C;AACjD,SAAO;AAAA,IACL,aAAa,cAAc;AACzB,YAAM,WAAW,IAAI,sBAAsB,CAAC,EAAE,SAAS,eAAe,MAAM,YAAY,CAAC,CAAC;AAC1F,eAAS,QAAQ,eAAe;AAAA,QAC9B,QAAQ,CAAC,WAAW,YAAY,aAAa,cAAc,WAAW,OAAO;AAAA,QAC7E,QAAQ,CAAC,YAAY,aAAa,cAAc,OAAO;AAAA,MACzD,CAAC;AACD,YAAM,aAAa,YAAY,QAAQ;AACvC,aAAO;AAAA,QACL,eAAe,WAAW;AAAA,QAC1B,QAAQ,SAAS;AACf,qBAAW,QAAQ,OAAO;AAC1B,mBAAS,QAAQ;AAAA,QACnB;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAEA,eAAsB,UACpB,OACA,
|
|
4
|
+
"sourcesContent": ["import {\n type Context,\n createRemoteServiceEndpoint,\n RemoteServiceProvider,\n replicatedState,\n} from '@earendil-works/chord';\nimport { BACKGROUND_CONTEXT } from '@earendil-works/chord/context';\nimport {\n type RoutedServerServiceHost,\n type RoutedSessionAttachment,\n type RoutedSessionHandle,\n Server,\n type ServerHost,\n SessionNotFoundError,\n} from '@earendil-works/pi-server';\nimport type { Agent } from './agent.ts';\nimport { createAgentControl } from './control.ts';\nimport { AGENT_SESSION, AgentControl, AgentSessions, AgentTranscript } from './services.ts';\nimport { AgentSettings } from './settings.ts';\nimport { type PortEndpoint, PortListener } from './wire.ts';\n\nexport interface AgentHost {\n readonly serverId: string;\n readonly agent: Agent;\n connect(endpoint: PortEndpoint): void;\n close(): Promise<void>;\n}\n\nfunction endpointFor(provider: RemoteServiceProvider): RoutedSessionAttachment {\n const endpoint = createRemoteServiceEndpoint(provider);\n return {\n invokeService: (call, publish, context) =>\n endpoint.invoke(call, (id, update) => publish(id, update, context), context),\n release: () => endpoint.dispose(),\n };\n}\n\nfunction sessionServices(provider: RemoteServiceProvider): RoutedSessionHandle {\n return {\n attachClient: () => endpointFor(provider),\n close: async () => {},\n };\n}\n\nfunction serverServices(): RoutedServerServiceHost {\n return {\n attachClient(presentation) {\n const provider = new RemoteServiceProvider([{ service: AgentSessions, mode: 'singleton' }]);\n provider.provide(AgentSessions, {\n attach: (sessionId, context) => presentation.attachSession(sessionId, context),\n detach: (context) => presentation.detachSession(context),\n });\n const attachment = endpointFor(provider);\n return {\n invokeService: attachment.invokeService,\n release(context) {\n attachment.release(context);\n provider.dispose();\n },\n };\n },\n };\n}\n\nconst noSettings: AgentSettings = {\n state: replicatedState({ models: [], accounts: [] }),\n connect: async () => {\n throw new Error('this agent has no accounts');\n },\n disconnect: async () => {},\n};\n\nexport async function hostAgent(\n agent: Agent,\n options: { serverId?: string; context?: Context; settings?: AgentSettings } = {}\n): Promise<AgentHost> {\n const context = options.context ?? BACKGROUND_CONTEXT;\n const serverId = options.serverId ?? crypto.randomUUID();\n const state = await agent.root.viewState(context);\n const provider = new RemoteServiceProvider([\n { service: AgentControl, mode: 'singleton' },\n { service: AgentTranscript, mode: 'singleton' },\n { service: AgentSettings, mode: 'singleton' },\n ]);\n provider.provide(AgentControl, createAgentControl(agent.harness, agent.root));\n provider.provide(AgentTranscript, { state });\n provider.provide(AgentSettings, options.settings ?? noSettings);\n const host: ServerHost = {\n serverServices: serverServices(),\n async resolveSession(sessionId) {\n if (sessionId !== AGENT_SESSION)\n throw new SessionNotFoundError(`unknown session ${sessionId}`);\n return { id: sessionId };\n },\n openSession: async () => sessionServices(provider),\n };\n const listener = new PortListener(serverId);\n const server = await new Server(host, { serverId, listeners: [listener] }).start();\n return {\n serverId,\n agent,\n connect: (endpoint) => listener.connect(endpoint),\n async close() {\n await server.close();\n provider.dispose();\n state.dispose();\n await agent.close();\n },\n };\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/index.js
CHANGED
|
@@ -1,18 +1,32 @@
|
|
|
1
1
|
import { answerText, openAgent } from "./agent.js";
|
|
2
2
|
import { connectAgent } from "./client.js";
|
|
3
3
|
import { createAgentControl } from "./control.js";
|
|
4
|
+
import { CREDENTIALS_DATABASE, EncryptedCredentialStore } from "./credentials.js";
|
|
4
5
|
import { hostAgent } from "./host.js";
|
|
5
6
|
import { HOME, kernelEnvironment, SliccKernelEnv } from "./kernel/env.js";
|
|
7
|
+
import {
|
|
8
|
+
runAgentWorker
|
|
9
|
+
} from "./main.js";
|
|
10
|
+
import { transportFetch } from "./net.js";
|
|
6
11
|
import {
|
|
7
12
|
AGENT_LOCK,
|
|
8
13
|
startAgent
|
|
9
14
|
} from "./owner.js";
|
|
15
|
+
import { SliccPrompt } from "./prompt.js";
|
|
10
16
|
import {
|
|
11
17
|
AGENT_SESSION,
|
|
12
18
|
AgentControl,
|
|
13
19
|
AgentSessions,
|
|
14
20
|
AgentTranscript
|
|
15
21
|
} from "./services.js";
|
|
22
|
+
import {
|
|
23
|
+
AgentSettings,
|
|
24
|
+
BEDROCK,
|
|
25
|
+
createAgentSettings,
|
|
26
|
+
createSliccModels,
|
|
27
|
+
DEFAULT_MODEL,
|
|
28
|
+
sliccProviders
|
|
29
|
+
} from "./settings.js";
|
|
16
30
|
import {
|
|
17
31
|
AGENT_DIRECTORY,
|
|
18
32
|
openMemorySqliteStorage,
|
|
@@ -27,23 +41,34 @@ export {
|
|
|
27
41
|
AGENT_SESSION,
|
|
28
42
|
AgentControl,
|
|
29
43
|
AgentSessions,
|
|
44
|
+
AgentSettings,
|
|
30
45
|
AgentTranscript,
|
|
46
|
+
BEDROCK,
|
|
47
|
+
CREDENTIALS_DATABASE,
|
|
48
|
+
DEFAULT_MODEL,
|
|
49
|
+
EncryptedCredentialStore,
|
|
31
50
|
HOME,
|
|
32
51
|
PortChannel,
|
|
33
52
|
PortListener,
|
|
34
53
|
SliccKernelEnv,
|
|
54
|
+
SliccPrompt,
|
|
35
55
|
WasmSqliteDatabase,
|
|
36
56
|
answerText,
|
|
37
57
|
connectAgent,
|
|
38
58
|
createAgentControl,
|
|
59
|
+
createAgentSettings,
|
|
60
|
+
createSliccModels,
|
|
39
61
|
hostAgent,
|
|
40
62
|
kernelEnvironment,
|
|
41
63
|
kernelPort,
|
|
42
64
|
openAgent,
|
|
43
65
|
openMemorySqliteStorage,
|
|
44
66
|
openOpfsSqliteStorage,
|
|
67
|
+
runAgentWorker,
|
|
45
68
|
serveConnections,
|
|
69
|
+
sliccProviders,
|
|
46
70
|
startAgent,
|
|
71
|
+
transportFetch,
|
|
47
72
|
withUnrefTimers
|
|
48
73
|
};
|
|
49
74
|
//# sourceMappingURL=index.js.map
|
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 type {\n KernelClient,\n KernelFs,\n KernelProcess,\n KernelStat,\n SpawnOptions,\n} from './kernel/client.ts';\nexport { HOME, type KernelEnvOptions, kernelEnvironment, SliccKernelEnv } from './kernel/env.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 { kernelPort, serveConnections, type WorkerScope } from './worker.ts';\n"],
|
|
5
|
-
"mappings": "AAAA,SAAwC,YAAY,iBAAiB;AACrE,SAA+B,oBAAoB;AACnD,SAAS,0BAA0B;AACnC,SAAyB,iBAAiB;AAQ1C,SAAS,MAA6B,mBAAmB,sBAAsB;AAC/E;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,YAAY,wBAA0C;",
|
|
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 { CREDENTIALS_DATABASE, EncryptedCredentialStore } from './credentials.ts';\nexport { type AgentHost, hostAgent } from './host.ts';\nexport type {\n KernelClient,\n KernelFs,\n KernelProcess,\n KernelStat,\n SpawnOptions,\n} from './kernel/client.ts';\nexport { HOME, type KernelEnvOptions, kernelEnvironment, SliccKernelEnv } from './kernel/env.ts';\nexport {\n type AgentWorkerOptions,\n type AgentWorkerScope,\n type KernelAttach,\n runAgentWorker,\n} from './main.ts';\nexport { type Transport, type TransportResponse, transportFetch } from './net.ts';\nexport {\n AGENT_LOCK,\n type AgentOwner,\n type AgentWorker,\n type OwnerOptions,\n startAgent,\n} from './owner.ts';\nexport { SliccPrompt } from './prompt.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 type AccountState,\n AgentSettings,\n BEDROCK,\n createAgentSettings,\n createSliccModels,\n DEFAULT_MODEL,\n type ModelChoice,\n type SettingsState,\n sliccProviders,\n} from './settings.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 { kernelPort, serveConnections, type WorkerScope } from './worker.ts';\n"],
|
|
5
|
+
"mappings": "AAAA,SAAwC,YAAY,iBAAiB;AACrE,SAA+B,oBAAoB;AACnD,SAAS,0BAA0B;AACnC,SAAS,sBAAsB,gCAAgC;AAC/D,SAAyB,iBAAiB;AAQ1C,SAAS,MAA6B,mBAAmB,sBAAsB;AAC/E;AAAA,EAIE;AAAA,OACK;AACP,SAAiD,sBAAsB;AACvE;AAAA,EACE;AAAA,EAIA;AAAA,OACK;AACP,SAAS,mBAAmB;AAC5B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EAEA;AAAA,OAMK;AACP;AAAA,EAEE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAGA;AAAA,OACK;AACP;AAAA,EACE;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,aAAgC,cAAc,uBAAuB;AAC9E,SAAS,YAAY,wBAA0C;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/main.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { attachKernel } from "@ai-ecoverse/slicc-kernel";
|
|
2
|
+
import { createRegistry } from "@earendil-works/pi-durable";
|
|
3
|
+
import { CodingTools } from "@earendil-works/pi-durable/tools";
|
|
4
|
+
import { openAgent } from "./agent.js";
|
|
5
|
+
import { EncryptedCredentialStore } from "./credentials.js";
|
|
6
|
+
import { hostAgent } from "./host.js";
|
|
7
|
+
import { kernelEnvironment } from "./kernel/env.js";
|
|
8
|
+
import { transportFetch } from "./net.js";
|
|
9
|
+
import { SliccPrompt } from "./prompt.js";
|
|
10
|
+
import {
|
|
11
|
+
createAgentSettings,
|
|
12
|
+
createSliccModels,
|
|
13
|
+
DEFAULT_MODEL,
|
|
14
|
+
sliccProviders
|
|
15
|
+
} from "./settings.js";
|
|
16
|
+
import { openOpfsSqliteStorage } from "./sqlite.js";
|
|
17
|
+
import { kernelPort, serveConnections } from "./worker.js";
|
|
18
|
+
async function start(scope, port, options) {
|
|
19
|
+
const attach = options.attach ?? attachKernel;
|
|
20
|
+
const client = await attach(await port);
|
|
21
|
+
scope.fetch = transportFetch(client.transport, scope.location.origin, scope.fetch.bind(scope));
|
|
22
|
+
const credentials = await (options.credentials ?? (() => EncryptedCredentialStore.open()))();
|
|
23
|
+
const providers = options.providers ?? sliccProviders();
|
|
24
|
+
const models = createSliccModels(credentials, providers);
|
|
25
|
+
const registry = createRegistry();
|
|
26
|
+
registry.install(CodingTools);
|
|
27
|
+
registry.install(SliccPrompt);
|
|
28
|
+
const agent = await openAgent({
|
|
29
|
+
models,
|
|
30
|
+
model: options.model ?? DEFAULT_MODEL,
|
|
31
|
+
storage: await (options.storage ?? (() => openOpfsSqliteStorage()))(),
|
|
32
|
+
registry,
|
|
33
|
+
env: kernelEnvironment(client)
|
|
34
|
+
});
|
|
35
|
+
return hostAgent(agent, { settings: await createAgentSettings(models, credentials, providers) });
|
|
36
|
+
}
|
|
37
|
+
function runAgentWorker(scope, options = {}) {
|
|
38
|
+
const host = start(scope, kernelPort(scope), options);
|
|
39
|
+
host.catch(() => void 0);
|
|
40
|
+
serveConnections(scope, host);
|
|
41
|
+
return host;
|
|
42
|
+
}
|
|
43
|
+
export {
|
|
44
|
+
runAgentWorker
|
|
45
|
+
};
|
|
46
|
+
//# sourceMappingURL=main.js.map
|
package/dist/main.js.map
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/main.ts"],
|
|
4
|
+
"sourcesContent": ["import { attachKernel } from '@ai-ecoverse/slicc-kernel';\nimport type { CredentialStore, Provider } from '@earendil-works/pi-ai';\nimport { createRegistry, type ModelRef, type Storage } from '@earendil-works/pi-durable';\nimport { CodingTools } from '@earendil-works/pi-durable/tools';\nimport { openAgent } from './agent.ts';\nimport { EncryptedCredentialStore } from './credentials.ts';\nimport { type AgentHost, hostAgent } from './host.ts';\nimport type { KernelClient } from './kernel/client.ts';\nimport { kernelEnvironment } from './kernel/env.ts';\nimport { type Transport, transportFetch } from './net.ts';\nimport { SliccPrompt } from './prompt.ts';\nimport {\n createAgentSettings,\n createSliccModels,\n DEFAULT_MODEL,\n sliccProviders,\n} from './settings.ts';\nimport { openOpfsSqliteStorage } from './sqlite.ts';\nimport { kernelPort, serveConnections, type WorkerScope } from './worker.ts';\n\nexport interface AgentWorkerScope extends WorkerScope {\n fetch: typeof fetch;\n location: { origin: string };\n}\n\nexport type KernelAttach = (port: MessagePort) => Promise<KernelClient & { transport: Transport }>;\n\nexport interface AgentWorkerOptions {\n model?: ModelRef;\n providers?: Provider[];\n attach?: KernelAttach;\n credentials?: () => Promise<CredentialStore>;\n storage?: () => Promise<Storage>;\n}\n\nasync function start(\n scope: AgentWorkerScope,\n port: Promise<MessagePort>,\n options: AgentWorkerOptions\n): Promise<AgentHost> {\n const attach: KernelAttach = options.attach ?? attachKernel;\n const client = await attach(await port);\n scope.fetch = transportFetch(client.transport, scope.location.origin, scope.fetch.bind(scope));\n const credentials = await (options.credentials ?? (() => EncryptedCredentialStore.open()))();\n const providers = options.providers ?? sliccProviders();\n const models = createSliccModels(credentials, providers);\n const registry = createRegistry();\n registry.install(CodingTools);\n registry.install(SliccPrompt);\n const agent = await openAgent({\n models,\n model: options.model ?? DEFAULT_MODEL,\n storage: await (options.storage ?? (() => openOpfsSqliteStorage()))(),\n registry,\n env: kernelEnvironment(client),\n });\n return hostAgent(agent, { settings: await createAgentSettings(models, credentials, providers) });\n}\n\nexport function runAgentWorker(\n scope: AgentWorkerScope,\n options: AgentWorkerOptions = {}\n): Promise<AgentHost> {\n const host = start(scope, kernelPort(scope), options);\n host.catch(() => undefined);\n serveConnections(scope, host);\n return host;\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,oBAAoB;AAE7B,SAAS,sBAAmD;AAC5D,SAAS,mBAAmB;AAC5B,SAAS,iBAAiB;AAC1B,SAAS,gCAAgC;AACzC,SAAyB,iBAAiB;AAE1C,SAAS,yBAAyB;AAClC,SAAyB,sBAAsB;AAC/C,SAAS,mBAAmB;AAC5B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,6BAA6B;AACtC,SAAS,YAAY,wBAA0C;AAiB/D,eAAe,MACb,OACA,MACA,SACoB;AACpB,QAAM,SAAuB,QAAQ,UAAU;AAC/C,QAAM,SAAS,MAAM,OAAO,MAAM,IAAI;AACtC,QAAM,QAAQ,eAAe,OAAO,WAAW,MAAM,SAAS,QAAQ,MAAM,MAAM,KAAK,KAAK,CAAC;AAC7F,QAAM,cAAc,OAAO,QAAQ,gBAAgB,MAAM,yBAAyB,KAAK,IAAI;AAC3F,QAAM,YAAY,QAAQ,aAAa,eAAe;AACtD,QAAM,SAAS,kBAAkB,aAAa,SAAS;AACvD,QAAM,WAAW,eAAe;AAChC,WAAS,QAAQ,WAAW;AAC5B,WAAS,QAAQ,WAAW;AAC5B,QAAM,QAAQ,MAAM,UAAU;AAAA,IAC5B;AAAA,IACA,OAAO,QAAQ,SAAS;AAAA,IACxB,SAAS,OAAO,QAAQ,YAAY,MAAM,sBAAsB,IAAI;AAAA,IACpE;AAAA,IACA,KAAK,kBAAkB,MAAM;AAAA,EAC/B,CAAC;AACD,SAAO,UAAU,OAAO,EAAE,UAAU,MAAM,oBAAoB,QAAQ,aAAa,SAAS,EAAE,CAAC;AACjG;AAEO,SAAS,eACd,OACA,UAA8B,CAAC,GACX;AACpB,QAAM,OAAO,MAAM,OAAO,WAAW,KAAK,GAAG,OAAO;AACpD,OAAK,MAAM,MAAM,MAAS;AAC1B,mBAAiB,OAAO,IAAI;AAC5B,SAAO;AACT;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/dist/net.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
const empty = /* @__PURE__ */ new Set([101, 103, 204, 205, 304]);
|
|
2
|
+
function stream(body) {
|
|
3
|
+
const iterator = body[Symbol.asyncIterator]();
|
|
4
|
+
return new ReadableStream({
|
|
5
|
+
async pull(controller) {
|
|
6
|
+
const next = await iterator.next();
|
|
7
|
+
if (next.done) controller.close();
|
|
8
|
+
else controller.enqueue(next.value);
|
|
9
|
+
},
|
|
10
|
+
async cancel() {
|
|
11
|
+
await iterator.return?.();
|
|
12
|
+
}
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
function transportFetch(transport, origin, native = globalThis.fetch.bind(globalThis)) {
|
|
16
|
+
return async (input, init) => {
|
|
17
|
+
const request = new Request(input, init);
|
|
18
|
+
if (new URL(request.url).origin === origin || transport.traits?.crossOrigin === "cors") {
|
|
19
|
+
return native(request);
|
|
20
|
+
}
|
|
21
|
+
const body = ["GET", "HEAD"].includes(request.method) ? void 0 : new Uint8Array(await request.arrayBuffer());
|
|
22
|
+
const response = await transport.fetch({
|
|
23
|
+
url: request.url,
|
|
24
|
+
method: request.method,
|
|
25
|
+
headers: [...request.headers],
|
|
26
|
+
...body ? { body } : {},
|
|
27
|
+
signal: request.signal
|
|
28
|
+
});
|
|
29
|
+
return new Response(empty.has(response.status) ? null : stream(response.body), {
|
|
30
|
+
status: response.status,
|
|
31
|
+
statusText: response.statusText ?? "",
|
|
32
|
+
headers: response.headers
|
|
33
|
+
});
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
export {
|
|
37
|
+
transportFetch
|
|
38
|
+
};
|
|
39
|
+
//# sourceMappingURL=net.js.map
|
package/dist/net.js.map
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/net.ts"],
|
|
4
|
+
"sourcesContent": ["export interface TransportResponse {\n status: number;\n statusText?: string;\n headers: HeadersInit;\n body: AsyncIterable<Uint8Array>;\n}\n\nexport interface Transport {\n traits?: { crossOrigin?: 'cors' | 'any' };\n fetch(request: {\n url: string;\n method: string;\n headers: [string, string][];\n body?: Uint8Array;\n signal?: AbortSignal;\n }): Promise<TransportResponse>;\n}\n\nconst empty = new Set([101, 103, 204, 205, 304]);\n\nfunction stream(body: AsyncIterable<Uint8Array>): ReadableStream<Uint8Array> {\n const iterator = body[Symbol.asyncIterator]();\n return new ReadableStream({\n async pull(controller) {\n const next = await iterator.next();\n if (next.done) controller.close();\n else controller.enqueue(next.value);\n },\n async cancel() {\n await iterator.return?.();\n },\n });\n}\n\nexport function transportFetch(\n transport: Transport,\n origin: string,\n native: typeof fetch = globalThis.fetch.bind(globalThis)\n): typeof fetch {\n return async (input, init) => {\n const request = new Request(input, init);\n if (new URL(request.url).origin === origin || transport.traits?.crossOrigin === 'cors') {\n return native(request);\n }\n const body = ['GET', 'HEAD'].includes(request.method)\n ? undefined\n : new Uint8Array(await request.arrayBuffer());\n const response = await transport.fetch({\n url: request.url,\n method: request.method,\n headers: [...request.headers],\n ...(body ? { body } : {}),\n signal: request.signal,\n });\n return new Response(empty.has(response.status) ? null : stream(response.body), {\n status: response.status,\n statusText: response.statusText ?? '',\n headers: response.headers,\n });\n };\n}\n"],
|
|
5
|
+
"mappings": "AAkBA,MAAM,QAAQ,oBAAI,IAAI,CAAC,KAAK,KAAK,KAAK,KAAK,GAAG,CAAC;AAE/C,SAAS,OAAO,MAA6D;AAC3E,QAAM,WAAW,KAAK,OAAO,aAAa,EAAE;AAC5C,SAAO,IAAI,eAAe;AAAA,IACxB,MAAM,KAAK,YAAY;AACrB,YAAM,OAAO,MAAM,SAAS,KAAK;AACjC,UAAI,KAAK,KAAM,YAAW,MAAM;AAAA,UAC3B,YAAW,QAAQ,KAAK,KAAK;AAAA,IACpC;AAAA,IACA,MAAM,SAAS;AACb,YAAM,SAAS,SAAS;AAAA,IAC1B;AAAA,EACF,CAAC;AACH;AAEO,SAAS,eACd,WACA,QACA,SAAuB,WAAW,MAAM,KAAK,UAAU,GACzC;AACd,SAAO,OAAO,OAAO,SAAS;AAC5B,UAAM,UAAU,IAAI,QAAQ,OAAO,IAAI;AACvC,QAAI,IAAI,IAAI,QAAQ,GAAG,EAAE,WAAW,UAAU,UAAU,QAAQ,gBAAgB,QAAQ;AACtF,aAAO,OAAO,OAAO;AAAA,IACvB;AACA,UAAM,OAAO,CAAC,OAAO,MAAM,EAAE,SAAS,QAAQ,MAAM,IAChD,SACA,IAAI,WAAW,MAAM,QAAQ,YAAY,CAAC;AAC9C,UAAM,WAAW,MAAM,UAAU,MAAM;AAAA,MACrC,KAAK,QAAQ;AAAA,MACb,QAAQ,QAAQ;AAAA,MAChB,SAAS,CAAC,GAAG,QAAQ,OAAO;AAAA,MAC5B,GAAI,OAAO,EAAE,KAAK,IAAI,CAAC;AAAA,MACvB,QAAQ,QAAQ;AAAA,IAClB,CAAC;AACD,WAAO,IAAI,SAAS,MAAM,IAAI,SAAS,MAAM,IAAI,OAAO,OAAO,SAAS,IAAI,GAAG;AAAA,MAC7E,QAAQ,SAAS;AAAA,MACjB,YAAY,SAAS,cAAc;AAAA,MACnC,SAAS,SAAS;AAAA,IACpB,CAAC;AAAA,EACH;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/dist/prompt.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { defineExtension, section } from "@earendil-works/pi-durable";
|
|
2
|
+
const PREAMBLE = [
|
|
3
|
+
"You are sliccy, the agent of SLICC. You run in a worker inside the user\u2019s browser tab.",
|
|
4
|
+
"Your tools work on slicc-kernel: bash and coreutils compiled to WebAssembly, on the browser\u2019s private file system.",
|
|
5
|
+
"The user can watch and stop your processes from a terminal next to this chat.",
|
|
6
|
+
"Be brief, do the work with your tools, and say what you changed."
|
|
7
|
+
].join("\n");
|
|
8
|
+
const SliccPrompt = defineExtension({
|
|
9
|
+
name: "slicc",
|
|
10
|
+
sections: [
|
|
11
|
+
section("preamble", () => PREAMBLE, { tag: false }),
|
|
12
|
+
section("cwd", (input) => input.env?.cwd)
|
|
13
|
+
]
|
|
14
|
+
});
|
|
15
|
+
export {
|
|
16
|
+
SliccPrompt
|
|
17
|
+
};
|
|
18
|
+
//# sourceMappingURL=prompt.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/prompt.ts"],
|
|
4
|
+
"sourcesContent": ["import { defineExtension, section } from '@earendil-works/pi-durable';\n\nconst PREAMBLE = [\n 'You are sliccy, the agent of SLICC. You run in a worker inside the user\u2019s browser tab.',\n 'Your tools work on slicc-kernel: bash and coreutils compiled to WebAssembly, on the browser\u2019s private file system.',\n 'The user can watch and stop your processes from a terminal next to this chat.',\n 'Be brief, do the work with your tools, and say what you changed.',\n].join('\\n');\n\nexport const SliccPrompt = defineExtension({\n name: 'slicc',\n sections: [\n section('preamble', () => PREAMBLE, { tag: false }),\n section('cwd', (input) => input.env?.cwd),\n ],\n});\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,iBAAiB,eAAe;AAEzC,MAAM,WAAW;AAAA,EACf;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,EAAE,KAAK,IAAI;AAEJ,MAAM,cAAc,gBAAgB;AAAA,EACzC,MAAM;AAAA,EACN,UAAU;AAAA,IACR,QAAQ,YAAY,MAAM,UAAU,EAAE,KAAK,MAAM,CAAC;AAAA,IAClD,QAAQ,OAAO,CAAC,UAAU,MAAM,KAAK,GAAG;AAAA,EAC1C;AACF,CAAC;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/dist/settings.js
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import {
|
|
2
|
+
defineService,
|
|
3
|
+
replicatedState
|
|
4
|
+
} from "@earendil-works/chord";
|
|
5
|
+
import { createModels } from "@earendil-works/pi-ai/models";
|
|
6
|
+
import { amazonBedrockProvider } from "@earendil-works/pi-ai/providers/amazon-bedrock";
|
|
7
|
+
const BEDROCK = "amazon-bedrock";
|
|
8
|
+
const DEFAULT_MODEL = { provider: BEDROCK, modelId: "us.anthropic.claude-sonnet-5-5" };
|
|
9
|
+
const AgentSettings = defineService("slicc.agent.settings");
|
|
10
|
+
const corsFree = /* @__PURE__ */ new Set([BEDROCK]);
|
|
11
|
+
function sliccProviders() {
|
|
12
|
+
return [amazonBedrockProvider()];
|
|
13
|
+
}
|
|
14
|
+
function createSliccModels(credentials, providers = sliccProviders()) {
|
|
15
|
+
const models = createModels({ credentials });
|
|
16
|
+
for (const provider of providers) models.setProvider(provider);
|
|
17
|
+
return models;
|
|
18
|
+
}
|
|
19
|
+
function choices(models, providers) {
|
|
20
|
+
return providers.flatMap(
|
|
21
|
+
(provider) => models.getModels(provider.id).map((model) => ({
|
|
22
|
+
id: `${provider.id}/${model.id}`,
|
|
23
|
+
label: model.name,
|
|
24
|
+
provider: provider.name ?? provider.id,
|
|
25
|
+
kind: "chat",
|
|
26
|
+
reasoning: Boolean(model.reasoning),
|
|
27
|
+
contextWindow: model.contextWindow
|
|
28
|
+
}))
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
async function accounts(credentials, providers) {
|
|
32
|
+
const stored = new Set((await credentials.list()).map((info) => info.providerId));
|
|
33
|
+
return providers.map((provider) => ({
|
|
34
|
+
id: provider.id,
|
|
35
|
+
provider: provider.name ?? provider.id,
|
|
36
|
+
identity: stored.has(provider.id) ? "API key" : "",
|
|
37
|
+
status: stored.has(provider.id) ? "connected" : "disconnected",
|
|
38
|
+
auth: "api-key",
|
|
39
|
+
needs: corsFree.has(provider.id) ? "cors-free-transport" : null
|
|
40
|
+
}));
|
|
41
|
+
}
|
|
42
|
+
async function createAgentSettings(models, credentials, providers = sliccProviders()) {
|
|
43
|
+
const state = replicatedState({
|
|
44
|
+
models: choices(models, providers),
|
|
45
|
+
accounts: await accounts(credentials, providers)
|
|
46
|
+
});
|
|
47
|
+
const refresh = async (context) => {
|
|
48
|
+
state.replace(context, {
|
|
49
|
+
models: choices(models, providers),
|
|
50
|
+
accounts: await accounts(credentials, providers)
|
|
51
|
+
});
|
|
52
|
+
};
|
|
53
|
+
return {
|
|
54
|
+
state,
|
|
55
|
+
async connect(providerId, secret, region, context) {
|
|
56
|
+
await credentials.modify(providerId, async () => ({
|
|
57
|
+
type: "api_key",
|
|
58
|
+
key: secret,
|
|
59
|
+
...region ? { env: { AWS_REGION: region } } : {}
|
|
60
|
+
}));
|
|
61
|
+
await refresh(context);
|
|
62
|
+
},
|
|
63
|
+
async disconnect(providerId, context) {
|
|
64
|
+
await credentials.delete(providerId);
|
|
65
|
+
await refresh(context);
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
export {
|
|
70
|
+
AgentSettings,
|
|
71
|
+
BEDROCK,
|
|
72
|
+
DEFAULT_MODEL,
|
|
73
|
+
createAgentSettings,
|
|
74
|
+
createSliccModels,
|
|
75
|
+
sliccProviders
|
|
76
|
+
};
|
|
77
|
+
//# sourceMappingURL=settings.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/settings.ts"],
|
|
4
|
+
"sourcesContent": ["import {\n type Context,\n defineService,\n type ReplicatedState,\n replicatedState,\n} from '@earendil-works/chord';\nimport type { CredentialStore, Provider } from '@earendil-works/pi-ai';\nimport { createModels, type MutableModels } from '@earendil-works/pi-ai/models';\nimport { amazonBedrockProvider } from '@earendil-works/pi-ai/providers/amazon-bedrock';\n\nexport const BEDROCK = 'amazon-bedrock';\nexport const DEFAULT_MODEL = { provider: BEDROCK, modelId: 'us.anthropic.claude-sonnet-5-5' };\n\nexport interface ModelChoice {\n id: string;\n label: string;\n provider: string;\n kind: 'chat' | 'classifier';\n reasoning: boolean;\n contextWindow: number;\n}\n\nexport interface AccountState {\n id: string;\n provider: string;\n identity: string;\n status: 'connected' | 'disconnected';\n auth: 'api-key';\n needs: 'cors-free-transport' | null;\n}\n\nexport interface SettingsState {\n models: ModelChoice[];\n accounts: AccountState[];\n}\n\nexport interface AgentSettings {\n readonly state: ReplicatedState<SettingsState>;\n connect(\n providerId: string,\n secret: string,\n region: string | null,\n context: Context\n ): Promise<void>;\n disconnect(providerId: string, context: Context): Promise<void>;\n}\n\nexport const AgentSettings = defineService<AgentSettings>('slicc.agent.settings');\n\nconst corsFree = new Set([BEDROCK]);\n\nexport function sliccProviders(): Provider[] {\n return [amazonBedrockProvider() as Provider];\n}\n\nexport function createSliccModels(\n credentials: CredentialStore,\n providers = sliccProviders()\n): MutableModels {\n const models = createModels({ credentials });\n for (const provider of providers) models.setProvider(provider);\n return models;\n}\n\nfunction choices(models: MutableModels, providers: Provider[]): ModelChoice[] {\n return providers.flatMap((provider) =>\n models.getModels(provider.id).map((model) => ({\n id: `${provider.id}/${model.id}`,\n label: model.name,\n provider: provider.name ?? provider.id,\n kind: 'chat' as const,\n reasoning: Boolean(model.reasoning),\n contextWindow: model.contextWindow,\n }))\n );\n}\n\nasync function accounts(\n credentials: CredentialStore,\n providers: Provider[]\n): Promise<AccountState[]> {\n const stored = new Set((await credentials.list()).map((info) => info.providerId));\n return providers.map((provider) => ({\n id: provider.id,\n provider: provider.name ?? provider.id,\n identity: stored.has(provider.id) ? 'API key' : '',\n status: stored.has(provider.id) ? 'connected' : 'disconnected',\n auth: 'api-key',\n needs: corsFree.has(provider.id) ? 'cors-free-transport' : null,\n }));\n}\n\nexport async function createAgentSettings(\n models: MutableModels,\n credentials: CredentialStore,\n providers = sliccProviders()\n): Promise<AgentSettings> {\n const state = replicatedState<SettingsState>({\n models: choices(models, providers),\n accounts: await accounts(credentials, providers),\n });\n const refresh = async (context: Context) => {\n state.replace(context, {\n models: choices(models, providers),\n accounts: await accounts(credentials, providers),\n });\n };\n return {\n state,\n async connect(providerId, secret, region, context) {\n await credentials.modify(providerId, async () => ({\n type: 'api_key',\n key: secret,\n ...(region ? { env: { AWS_REGION: region } } : {}),\n }));\n await refresh(context);\n },\n async disconnect(providerId, context) {\n await credentials.delete(providerId);\n await refresh(context);\n },\n };\n}\n"],
|
|
5
|
+
"mappings": "AAAA;AAAA,EAEE;AAAA,EAEA;AAAA,OACK;AAEP,SAAS,oBAAwC;AACjD,SAAS,6BAA6B;AAE/B,MAAM,UAAU;AAChB,MAAM,gBAAgB,EAAE,UAAU,SAAS,SAAS,iCAAiC;AAoCrF,MAAM,gBAAgB,cAA6B,sBAAsB;AAEhF,MAAM,WAAW,oBAAI,IAAI,CAAC,OAAO,CAAC;AAE3B,SAAS,iBAA6B;AAC3C,SAAO,CAAC,sBAAsB,CAAa;AAC7C;AAEO,SAAS,kBACd,aACA,YAAY,eAAe,GACZ;AACf,QAAM,SAAS,aAAa,EAAE,YAAY,CAAC;AAC3C,aAAW,YAAY,UAAW,QAAO,YAAY,QAAQ;AAC7D,SAAO;AACT;AAEA,SAAS,QAAQ,QAAuB,WAAsC;AAC5E,SAAO,UAAU;AAAA,IAAQ,CAAC,aACxB,OAAO,UAAU,SAAS,EAAE,EAAE,IAAI,CAAC,WAAW;AAAA,MAC5C,IAAI,GAAG,SAAS,EAAE,IAAI,MAAM,EAAE;AAAA,MAC9B,OAAO,MAAM;AAAA,MACb,UAAU,SAAS,QAAQ,SAAS;AAAA,MACpC,MAAM;AAAA,MACN,WAAW,QAAQ,MAAM,SAAS;AAAA,MAClC,eAAe,MAAM;AAAA,IACvB,EAAE;AAAA,EACJ;AACF;AAEA,eAAe,SACb,aACA,WACyB;AACzB,QAAM,SAAS,IAAI,KAAK,MAAM,YAAY,KAAK,GAAG,IAAI,CAAC,SAAS,KAAK,UAAU,CAAC;AAChF,SAAO,UAAU,IAAI,CAAC,cAAc;AAAA,IAClC,IAAI,SAAS;AAAA,IACb,UAAU,SAAS,QAAQ,SAAS;AAAA,IACpC,UAAU,OAAO,IAAI,SAAS,EAAE,IAAI,YAAY;AAAA,IAChD,QAAQ,OAAO,IAAI,SAAS,EAAE,IAAI,cAAc;AAAA,IAChD,MAAM;AAAA,IACN,OAAO,SAAS,IAAI,SAAS,EAAE,IAAI,wBAAwB;AAAA,EAC7D,EAAE;AACJ;AAEA,eAAsB,oBACpB,QACA,aACA,YAAY,eAAe,GACH;AACxB,QAAM,QAAQ,gBAA+B;AAAA,IAC3C,QAAQ,QAAQ,QAAQ,SAAS;AAAA,IACjC,UAAU,MAAM,SAAS,aAAa,SAAS;AAAA,EACjD,CAAC;AACD,QAAM,UAAU,OAAO,YAAqB;AAC1C,UAAM,QAAQ,SAAS;AAAA,MACrB,QAAQ,QAAQ,QAAQ,SAAS;AAAA,MACjC,UAAU,MAAM,SAAS,aAAa,SAAS;AAAA,IACjD,CAAC;AAAA,EACH;AACA,SAAO;AAAA,IACL;AAAA,IACA,MAAM,QAAQ,YAAY,QAAQ,QAAQ,SAAS;AACjD,YAAM,YAAY,OAAO,YAAY,aAAa;AAAA,QAChD,MAAM;AAAA,QACN,KAAK;AAAA,QACL,GAAI,SAAS,EAAE,KAAK,EAAE,YAAY,OAAO,EAAE,IAAI,CAAC;AAAA,MAClD,EAAE;AACF,YAAM,QAAQ,OAAO;AAAA,IACvB;AAAA,IACA,MAAM,WAAW,YAAY,SAAS;AACpC,YAAM,YAAY,OAAO,UAAU;AACnC,YAAM,QAAQ,OAAO;AAAA,IACvB;AAAA,EACF;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/dist/spectrum/index.js
CHANGED
|
@@ -1,12 +1,20 @@
|
|
|
1
1
|
import { AgentAdapter } from "./agent-port.js";
|
|
2
|
+
import { SettingsAdapter } from "./settings-port.js";
|
|
2
3
|
import { AgentAdapter as AgentAdapter2, CONE } from "./agent-port.js";
|
|
3
4
|
import { assistant, isBusy, queued, textOf, toMessages } from "./messages.js";
|
|
4
|
-
|
|
5
|
-
|
|
5
|
+
import { SETTINGS_KEY, SettingsAdapter as SettingsAdapter2 } from "./settings-port.js";
|
|
6
|
+
function createAgentModel(connection, options = {}) {
|
|
7
|
+
const agent = new AgentAdapter(connection);
|
|
8
|
+
return {
|
|
9
|
+
agent,
|
|
10
|
+
settings: new SettingsAdapter(connection.settings, agent, options.storage ?? null)
|
|
11
|
+
};
|
|
6
12
|
}
|
|
7
13
|
export {
|
|
8
14
|
AgentAdapter2 as AgentAdapter,
|
|
9
15
|
CONE,
|
|
16
|
+
SETTINGS_KEY,
|
|
17
|
+
SettingsAdapter2 as SettingsAdapter,
|
|
10
18
|
assistant,
|
|
11
19
|
createAgentModel,
|
|
12
20
|
isBusy,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
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 {
|
|
5
|
-
"mappings": "AACA,SAAS,oBAAoB;
|
|
6
|
-
"names": ["AgentAdapter"]
|
|
4
|
+
"sourcesContent": ["import type { AgentConnection } from '../client.ts';\nimport { AgentAdapter } from './agent-port.ts';\nimport { SettingsAdapter } from './settings-port.ts';\n\nexport { AgentAdapter, CONE } from './agent-port.ts';\nexport { assistant, isBusy, queued, textOf, toMessages } from './messages.ts';\nexport { SETTINGS_KEY, SettingsAdapter } from './settings-port.ts';\n\nexport function createAgentModel(\n connection: AgentConnection,\n options: { storage?: Pick<Storage, 'getItem' | 'setItem'> | null } = {}\n): { agent: AgentAdapter; settings: SettingsAdapter } {\n const agent = new AgentAdapter(connection);\n return {\n agent,\n settings: new SettingsAdapter(connection.settings, agent, options.storage ?? null),\n };\n}\n"],
|
|
5
|
+
"mappings": "AACA,SAAS,oBAAoB;AAC7B,SAAS,uBAAuB;AAEhC,SAAS,gBAAAA,eAAc,YAAY;AACnC,SAAS,WAAW,QAAQ,QAAQ,QAAQ,kBAAkB;AAC9D,SAAS,cAAc,mBAAAC,wBAAuB;AAEvC,SAAS,iBACd,YACA,UAAqE,CAAC,GAClB;AACpD,QAAM,QAAQ,IAAI,aAAa,UAAU;AACzC,SAAO;AAAA,IACL;AAAA,IACA,UAAU,IAAI,gBAAgB,WAAW,UAAU,OAAO,QAAQ,WAAW,IAAI;AAAA,EACnF;AACF;",
|
|
6
|
+
"names": ["AgentAdapter", "SettingsAdapter"]
|
|
7
7
|
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { BACKGROUND_CONTEXT } from "@earendil-works/chord/context";
|
|
2
|
+
import { Emitter } from "./emitter.js";
|
|
3
|
+
const SETTINGS_KEY = "slicc-agent.settings";
|
|
4
|
+
const defaults = {
|
|
5
|
+
color: "system",
|
|
6
|
+
model: "",
|
|
7
|
+
thinking: "off",
|
|
8
|
+
sendOnEnter: true,
|
|
9
|
+
showThinking: false,
|
|
10
|
+
diffStyle: "unified"
|
|
11
|
+
};
|
|
12
|
+
class SettingsAdapter extends Emitter {
|
|
13
|
+
#settings;
|
|
14
|
+
#agent;
|
|
15
|
+
#storage;
|
|
16
|
+
#local;
|
|
17
|
+
constructor(settings, agent, storage) {
|
|
18
|
+
super();
|
|
19
|
+
this.#settings = settings;
|
|
20
|
+
this.#agent = agent;
|
|
21
|
+
this.#storage = storage;
|
|
22
|
+
const saved = JSON.parse(storage?.getItem(SETTINGS_KEY) ?? "{}");
|
|
23
|
+
const { model: _model, thinking: _thinking, ...local } = { ...defaults, ...saved };
|
|
24
|
+
this.#local = local;
|
|
25
|
+
settings.state.subscribe(() => {
|
|
26
|
+
this.emit("accounts", this.accounts());
|
|
27
|
+
this.emit("settings", this.get());
|
|
28
|
+
});
|
|
29
|
+
agent.on("agents", () => this.emit("settings", this.get()));
|
|
30
|
+
}
|
|
31
|
+
#state() {
|
|
32
|
+
return this.#settings.state.value ?? { models: [], accounts: [] };
|
|
33
|
+
}
|
|
34
|
+
get() {
|
|
35
|
+
const cone = this.#agent.list()[0];
|
|
36
|
+
return { ...this.#local, model: cone?.model ?? "", thinking: cone?.thinking ?? "off" };
|
|
37
|
+
}
|
|
38
|
+
update(patch) {
|
|
39
|
+
const { model, thinking, ...local } = patch;
|
|
40
|
+
const id = this.#agent.active();
|
|
41
|
+
if (model !== void 0) this.#agent.setModel(id, model);
|
|
42
|
+
if (thinking !== void 0) this.#agent.setThinking(id, thinking);
|
|
43
|
+
this.#local = { ...this.#local, ...local };
|
|
44
|
+
this.#storage?.setItem(SETTINGS_KEY, JSON.stringify(this.#local));
|
|
45
|
+
this.emit("settings", this.get());
|
|
46
|
+
}
|
|
47
|
+
models() {
|
|
48
|
+
return this.#state().models.map(({ id, label, provider, kind, reasoning }) => ({
|
|
49
|
+
id,
|
|
50
|
+
label,
|
|
51
|
+
provider,
|
|
52
|
+
kind,
|
|
53
|
+
reasoning
|
|
54
|
+
}));
|
|
55
|
+
}
|
|
56
|
+
accounts() {
|
|
57
|
+
return this.#state().accounts.map(
|
|
58
|
+
({ needs, ...account }) => needs ? { ...account, needs } : account
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
async connect(id, secret, options = {}) {
|
|
62
|
+
if (!secret) throw new Error(`${id} needs an API key`);
|
|
63
|
+
await this.#settings.connect(id, secret, options.region ?? null, BACKGROUND_CONTEXT);
|
|
64
|
+
}
|
|
65
|
+
disconnect(id) {
|
|
66
|
+
void this.#settings.disconnect(id, BACKGROUND_CONTEXT);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
export {
|
|
70
|
+
SETTINGS_KEY,
|
|
71
|
+
SettingsAdapter
|
|
72
|
+
};
|
|
73
|
+
//# sourceMappingURL=settings-port.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/spectrum/settings-port.ts"],
|
|
4
|
+
"sourcesContent": ["import type {\n Account,\n ModelOption,\n Settings,\n SettingsEvents,\n SettingsPort,\n} from '@ai-ecoverse/slicc-spectrum/ui';\nimport { BACKGROUND_CONTEXT } from '@earendil-works/chord/context';\nimport type { AgentSettings, SettingsState } from '../settings.ts';\nimport type { AgentAdapter } from './agent-port.ts';\nimport { Emitter } from './emitter.ts';\n\nexport const SETTINGS_KEY = 'slicc-agent.settings';\n\nconst defaults: Settings = {\n color: 'system',\n model: '',\n thinking: 'off',\n sendOnEnter: true,\n showThinking: false,\n diffStyle: 'unified',\n};\n\ntype Local = Omit<Settings, 'model' | 'thinking'>;\n\nexport class SettingsAdapter extends Emitter<SettingsEvents> implements SettingsPort {\n readonly #settings: AgentSettings;\n readonly #agent: AgentAdapter;\n readonly #storage: Pick<Storage, 'getItem' | 'setItem'> | null;\n #local: Local;\n\n constructor(\n settings: AgentSettings,\n agent: AgentAdapter,\n storage: Pick<Storage, 'getItem' | 'setItem'> | null\n ) {\n super();\n this.#settings = settings;\n this.#agent = agent;\n this.#storage = storage;\n const saved = JSON.parse(storage?.getItem(SETTINGS_KEY) ?? '{}') as Partial<Local>;\n const { model: _model, thinking: _thinking, ...local } = { ...defaults, ...saved };\n this.#local = local;\n settings.state.subscribe(() => {\n this.emit('accounts', this.accounts());\n this.emit('settings', this.get());\n });\n agent.on('agents', () => this.emit('settings', this.get()));\n }\n\n #state(): SettingsState {\n return this.#settings.state.value ?? { models: [], accounts: [] };\n }\n\n get(): Settings {\n const cone = this.#agent.list()[0];\n return { ...this.#local, model: cone?.model ?? '', thinking: cone?.thinking ?? 'off' };\n }\n\n update(patch: Partial<Settings>): void {\n const { model, thinking, ...local } = patch;\n const id = this.#agent.active();\n if (model !== undefined) this.#agent.setModel(id, model);\n if (thinking !== undefined) this.#agent.setThinking(id, thinking);\n this.#local = { ...this.#local, ...local };\n this.#storage?.setItem(SETTINGS_KEY, JSON.stringify(this.#local));\n this.emit('settings', this.get());\n }\n\n models(): readonly ModelOption[] {\n return this.#state().models.map(({ id, label, provider, kind, reasoning }) => ({\n id,\n label,\n provider,\n kind,\n reasoning,\n }));\n }\n\n accounts(): readonly Account[] {\n return this.#state().accounts.map(({ needs, ...account }) =>\n needs ? { ...account, needs } : account\n );\n }\n\n async connect(id: string, secret?: string, options: { region?: string } = {}): Promise<void> {\n if (!secret) throw new Error(`${id} needs an API key`);\n await this.#settings.connect(id, secret, options.region ?? null, BACKGROUND_CONTEXT);\n }\n\n disconnect(id: string): void {\n void this.#settings.disconnect(id, BACKGROUND_CONTEXT);\n }\n}\n"],
|
|
5
|
+
"mappings": "AAOA,SAAS,0BAA0B;AAGnC,SAAS,eAAe;AAEjB,MAAM,eAAe;AAE5B,MAAM,WAAqB;AAAA,EACzB,OAAO;AAAA,EACP,OAAO;AAAA,EACP,UAAU;AAAA,EACV,aAAa;AAAA,EACb,cAAc;AAAA,EACd,WAAW;AACb;AAIO,MAAM,wBAAwB,QAAgD;AAAA,EAC1E;AAAA,EACA;AAAA,EACA;AAAA,EACT;AAAA,EAEA,YACE,UACA,OACA,SACA;AACA,UAAM;AACN,SAAK,YAAY;AACjB,SAAK,SAAS;AACd,SAAK,WAAW;AAChB,UAAM,QAAQ,KAAK,MAAM,SAAS,QAAQ,YAAY,KAAK,IAAI;AAC/D,UAAM,EAAE,OAAO,QAAQ,UAAU,WAAW,GAAG,MAAM,IAAI,EAAE,GAAG,UAAU,GAAG,MAAM;AACjF,SAAK,SAAS;AACd,aAAS,MAAM,UAAU,MAAM;AAC7B,WAAK,KAAK,YAAY,KAAK,SAAS,CAAC;AACrC,WAAK,KAAK,YAAY,KAAK,IAAI,CAAC;AAAA,IAClC,CAAC;AACD,UAAM,GAAG,UAAU,MAAM,KAAK,KAAK,YAAY,KAAK,IAAI,CAAC,CAAC;AAAA,EAC5D;AAAA,EAEA,SAAwB;AACtB,WAAO,KAAK,UAAU,MAAM,SAAS,EAAE,QAAQ,CAAC,GAAG,UAAU,CAAC,EAAE;AAAA,EAClE;AAAA,EAEA,MAAgB;AACd,UAAM,OAAO,KAAK,OAAO,KAAK,EAAE,CAAC;AACjC,WAAO,EAAE,GAAG,KAAK,QAAQ,OAAO,MAAM,SAAS,IAAI,UAAU,MAAM,YAAY,MAAM;AAAA,EACvF;AAAA,EAEA,OAAO,OAAgC;AACrC,UAAM,EAAE,OAAO,UAAU,GAAG,MAAM,IAAI;AACtC,UAAM,KAAK,KAAK,OAAO,OAAO;AAC9B,QAAI,UAAU,OAAW,MAAK,OAAO,SAAS,IAAI,KAAK;AACvD,QAAI,aAAa,OAAW,MAAK,OAAO,YAAY,IAAI,QAAQ;AAChE,SAAK,SAAS,EAAE,GAAG,KAAK,QAAQ,GAAG,MAAM;AACzC,SAAK,UAAU,QAAQ,cAAc,KAAK,UAAU,KAAK,MAAM,CAAC;AAChE,SAAK,KAAK,YAAY,KAAK,IAAI,CAAC;AAAA,EAClC;AAAA,EAEA,SAAiC;AAC/B,WAAO,KAAK,OAAO,EAAE,OAAO,IAAI,CAAC,EAAE,IAAI,OAAO,UAAU,MAAM,UAAU,OAAO;AAAA,MAC7E;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,EAAE;AAAA,EACJ;AAAA,EAEA,WAA+B;AAC7B,WAAO,KAAK,OAAO,EAAE,SAAS;AAAA,MAAI,CAAC,EAAE,OAAO,GAAG,QAAQ,MACrD,QAAQ,EAAE,GAAG,SAAS,MAAM,IAAI;AAAA,IAClC;AAAA,EACF;AAAA,EAEA,MAAM,QAAQ,IAAY,QAAiB,UAA+B,CAAC,GAAkB;AAC3F,QAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,GAAG,EAAE,mBAAmB;AACrD,UAAM,KAAK,UAAU,QAAQ,IAAI,QAAQ,QAAQ,UAAU,MAAM,kBAAkB;AAAA,EACrF;AAAA,EAEA,WAAW,IAAkB;AAC3B,SAAK,KAAK,UAAU,WAAW,IAAI,kBAAkB;AAAA,EACvD;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const host: Promise<import("./host.ts").AgentHost>;
|
package/dist/types/client.d.ts
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { type Context, type ReplicatedState } from '@earendil-works/chord';
|
|
2
2
|
import type { ConversationView } from '@earendil-works/pi-durable';
|
|
3
3
|
import { AgentControl, type SendMode } from './services.ts';
|
|
4
|
+
import { AgentSettings } from './settings.ts';
|
|
4
5
|
import { type PortEndpoint } from './wire.ts';
|
|
5
6
|
export interface AgentConnection {
|
|
6
7
|
readonly serverId: string;
|
|
7
8
|
readonly control: AgentControl;
|
|
8
9
|
readonly transcript: ReplicatedState<ConversationView>;
|
|
10
|
+
readonly settings: AgentSettings;
|
|
9
11
|
prompt(text: string, whenBusy?: SendMode): Promise<string>;
|
|
10
12
|
close(): Promise<void>;
|
|
11
13
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Credential, CredentialInfo, CredentialStore } from '@earendil-works/pi-ai';
|
|
2
|
+
export declare const CREDENTIALS_DATABASE = "slicc-agent-credentials";
|
|
3
|
+
export declare class EncryptedCredentialStore implements CredentialStore {
|
|
4
|
+
#private;
|
|
5
|
+
private constructor();
|
|
6
|
+
static open(name?: string): Promise<EncryptedCredentialStore>;
|
|
7
|
+
read(providerId: string): Promise<Credential | undefined>;
|
|
8
|
+
list(): Promise<readonly CredentialInfo[]>;
|
|
9
|
+
modify(providerId: string, fn: (current: Credential | undefined) => Promise<Credential | undefined>): Promise<Credential | undefined>;
|
|
10
|
+
delete(providerId: string): Promise<void>;
|
|
11
|
+
close(): void;
|
|
12
|
+
}
|
package/dist/types/host.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type Context } from '@earendil-works/chord';
|
|
2
2
|
import type { Agent } from './agent.ts';
|
|
3
|
+
import { AgentSettings } from './settings.ts';
|
|
3
4
|
import { type PortEndpoint } from './wire.ts';
|
|
4
5
|
export interface AgentHost {
|
|
5
6
|
readonly serverId: string;
|
|
@@ -10,4 +11,5 @@ export interface AgentHost {
|
|
|
10
11
|
export declare function hostAgent(agent: Agent, options?: {
|
|
11
12
|
serverId?: string;
|
|
12
13
|
context?: Context;
|
|
14
|
+
settings?: AgentSettings;
|
|
13
15
|
}): Promise<AgentHost>;
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
export { type Agent, type AgentOptions, answerText, openAgent } from './agent.ts';
|
|
2
2
|
export { type AgentConnection, connectAgent } from './client.ts';
|
|
3
3
|
export { createAgentControl } from './control.ts';
|
|
4
|
+
export { CREDENTIALS_DATABASE, EncryptedCredentialStore } from './credentials.ts';
|
|
4
5
|
export { type AgentHost, hostAgent } from './host.ts';
|
|
5
6
|
export type { KernelClient, KernelFs, KernelProcess, KernelStat, SpawnOptions, } from './kernel/client.ts';
|
|
6
7
|
export { HOME, type KernelEnvOptions, kernelEnvironment, SliccKernelEnv } from './kernel/env.ts';
|
|
8
|
+
export { type AgentWorkerOptions, type AgentWorkerScope, type KernelAttach, runAgentWorker, } from './main.ts';
|
|
9
|
+
export { type Transport, type TransportResponse, transportFetch } from './net.ts';
|
|
7
10
|
export { AGENT_LOCK, type AgentOwner, type AgentWorker, type OwnerOptions, startAgent, } from './owner.ts';
|
|
11
|
+
export { SliccPrompt } from './prompt.ts';
|
|
8
12
|
export { AGENT_SESSION, AgentControl, AgentSessions, type AgentSettingsChange, AgentTranscript, type OperationError, type PromptResult, type SendMode, type SendRequest, type SendResponse, } from './services.ts';
|
|
13
|
+
export { type AccountState, AgentSettings, BEDROCK, createAgentSettings, createSliccModels, DEFAULT_MODEL, type ModelChoice, type SettingsState, sliccProviders, } from './settings.ts';
|
|
9
14
|
export { AGENT_DIRECTORY, type OpfsSqliteOptions, openMemorySqliteStorage, openOpfsSqliteStorage, WasmSqliteDatabase, } from './sqlite.ts';
|
|
10
15
|
export { PortChannel, type PortEndpoint, PortListener, withUnrefTimers } from './wire.ts';
|
|
11
16
|
export { kernelPort, serveConnections, type WorkerScope } from './worker.ts';
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { CredentialStore, Provider } from '@earendil-works/pi-ai';
|
|
2
|
+
import { type ModelRef, type Storage } from '@earendil-works/pi-durable';
|
|
3
|
+
import { type AgentHost } from './host.ts';
|
|
4
|
+
import type { KernelClient } from './kernel/client.ts';
|
|
5
|
+
import { type Transport } from './net.ts';
|
|
6
|
+
import { type WorkerScope } from './worker.ts';
|
|
7
|
+
export interface AgentWorkerScope extends WorkerScope {
|
|
8
|
+
fetch: typeof fetch;
|
|
9
|
+
location: {
|
|
10
|
+
origin: string;
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
export type KernelAttach = (port: MessagePort) => Promise<KernelClient & {
|
|
14
|
+
transport: Transport;
|
|
15
|
+
}>;
|
|
16
|
+
export interface AgentWorkerOptions {
|
|
17
|
+
model?: ModelRef;
|
|
18
|
+
providers?: Provider[];
|
|
19
|
+
attach?: KernelAttach;
|
|
20
|
+
credentials?: () => Promise<CredentialStore>;
|
|
21
|
+
storage?: () => Promise<Storage>;
|
|
22
|
+
}
|
|
23
|
+
export declare function runAgentWorker(scope: AgentWorkerScope, options?: AgentWorkerOptions): Promise<AgentHost>;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export interface TransportResponse {
|
|
2
|
+
status: number;
|
|
3
|
+
statusText?: string;
|
|
4
|
+
headers: HeadersInit;
|
|
5
|
+
body: AsyncIterable<Uint8Array>;
|
|
6
|
+
}
|
|
7
|
+
export interface Transport {
|
|
8
|
+
traits?: {
|
|
9
|
+
crossOrigin?: 'cors' | 'any';
|
|
10
|
+
};
|
|
11
|
+
fetch(request: {
|
|
12
|
+
url: string;
|
|
13
|
+
method: string;
|
|
14
|
+
headers: [string, string][];
|
|
15
|
+
body?: Uint8Array;
|
|
16
|
+
signal?: AbortSignal;
|
|
17
|
+
}): Promise<TransportResponse>;
|
|
18
|
+
}
|
|
19
|
+
export declare function transportFetch(transport: Transport, origin: string, native?: typeof fetch): typeof fetch;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const SliccPrompt: import("@earendil-works/pi-durable").Extension<import("@earendil-works/pi-durable").ToolRegistration>;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { type Context, type ReplicatedState } from '@earendil-works/chord';
|
|
2
|
+
import type { CredentialStore, Provider } from '@earendil-works/pi-ai';
|
|
3
|
+
import { type MutableModels } from '@earendil-works/pi-ai/models';
|
|
4
|
+
export declare const BEDROCK = "amazon-bedrock";
|
|
5
|
+
export declare const DEFAULT_MODEL: {
|
|
6
|
+
provider: string;
|
|
7
|
+
modelId: string;
|
|
8
|
+
};
|
|
9
|
+
export interface ModelChoice {
|
|
10
|
+
id: string;
|
|
11
|
+
label: string;
|
|
12
|
+
provider: string;
|
|
13
|
+
kind: 'chat' | 'classifier';
|
|
14
|
+
reasoning: boolean;
|
|
15
|
+
contextWindow: number;
|
|
16
|
+
}
|
|
17
|
+
export interface AccountState {
|
|
18
|
+
id: string;
|
|
19
|
+
provider: string;
|
|
20
|
+
identity: string;
|
|
21
|
+
status: 'connected' | 'disconnected';
|
|
22
|
+
auth: 'api-key';
|
|
23
|
+
needs: 'cors-free-transport' | null;
|
|
24
|
+
}
|
|
25
|
+
export interface SettingsState {
|
|
26
|
+
models: ModelChoice[];
|
|
27
|
+
accounts: AccountState[];
|
|
28
|
+
}
|
|
29
|
+
export interface AgentSettings {
|
|
30
|
+
readonly state: ReplicatedState<SettingsState>;
|
|
31
|
+
connect(providerId: string, secret: string, region: string | null, context: Context): Promise<void>;
|
|
32
|
+
disconnect(providerId: string, context: Context): Promise<void>;
|
|
33
|
+
}
|
|
34
|
+
export declare const AgentSettings: import("@earendil-works/chord").Service<AgentSettings>;
|
|
35
|
+
export declare function sliccProviders(): Provider[];
|
|
36
|
+
export declare function createSliccModels(credentials: CredentialStore, providers?: Provider<import("@earendil-works/pi-ai").Api>[]): MutableModels;
|
|
37
|
+
export declare function createAgentSettings(models: MutableModels, credentials: CredentialStore, providers?: Provider<import("@earendil-works/pi-ai").Api>[]): Promise<AgentSettings>;
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import type { AgentConnection } from '../client.ts';
|
|
2
2
|
import { AgentAdapter } from './agent-port.ts';
|
|
3
|
+
import { SettingsAdapter } from './settings-port.ts';
|
|
3
4
|
export { AgentAdapter, CONE } from './agent-port.ts';
|
|
4
5
|
export { assistant, isBusy, queued, textOf, toMessages } from './messages.ts';
|
|
5
|
-
export
|
|
6
|
+
export { SETTINGS_KEY, SettingsAdapter } from './settings-port.ts';
|
|
7
|
+
export declare function createAgentModel(connection: AgentConnection, options?: {
|
|
8
|
+
storage?: Pick<Storage, 'getItem' | 'setItem'> | null;
|
|
9
|
+
}): {
|
|
6
10
|
agent: AgentAdapter;
|
|
11
|
+
settings: SettingsAdapter;
|
|
7
12
|
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Account, ModelOption, Settings, SettingsEvents, SettingsPort } from '@ai-ecoverse/slicc-spectrum/ui';
|
|
2
|
+
import type { AgentSettings } from '../settings.ts';
|
|
3
|
+
import type { AgentAdapter } from './agent-port.ts';
|
|
4
|
+
import { Emitter } from './emitter.ts';
|
|
5
|
+
export declare const SETTINGS_KEY = "slicc-agent.settings";
|
|
6
|
+
export declare class SettingsAdapter extends Emitter<SettingsEvents> implements SettingsPort {
|
|
7
|
+
#private;
|
|
8
|
+
constructor(settings: AgentSettings, agent: AgentAdapter, storage: Pick<Storage, 'getItem' | 'setItem'> | null);
|
|
9
|
+
get(): Settings;
|
|
10
|
+
update(patch: Partial<Settings>): void;
|
|
11
|
+
models(): readonly ModelOption[];
|
|
12
|
+
accounts(): readonly Account[];
|
|
13
|
+
connect(id: string, secret?: string, options?: {
|
|
14
|
+
region?: string;
|
|
15
|
+
}): Promise<void>;
|
|
16
|
+
disconnect(id: string): void;
|
|
17
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ai-ecoverse/slicc-agent",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.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",
|
|
@@ -29,6 +29,10 @@
|
|
|
29
29
|
"./spectrum": {
|
|
30
30
|
"types": "./dist/types/spectrum/index.d.ts",
|
|
31
31
|
"default": "./dist/spectrum/index.js"
|
|
32
|
+
},
|
|
33
|
+
"./agent-worker": {
|
|
34
|
+
"types": "./dist/types/agent-worker.d.ts",
|
|
35
|
+
"default": "./dist/agent-worker.js"
|
|
32
36
|
}
|
|
33
37
|
},
|
|
34
38
|
"files": [
|
|
@@ -50,7 +54,6 @@
|
|
|
50
54
|
"release": "semantic-release"
|
|
51
55
|
},
|
|
52
56
|
"devDependencies": {
|
|
53
|
-
"@ai-ecoverse/slicc-kernel": "1.9.0",
|
|
54
57
|
"@ai-ecoverse/slicc-shared-web": "1.5.0",
|
|
55
58
|
"@ai-ecoverse/slicc-spectrum": "1.7.0",
|
|
56
59
|
"@ai-ecoverse/wasm-bash": "5.3.0-7",
|
|
@@ -58,6 +61,7 @@
|
|
|
58
61
|
"@biomejs/biome": "2.5.15",
|
|
59
62
|
"@types/node": "24.19.1",
|
|
60
63
|
"esbuild": "0.28.2",
|
|
64
|
+
"fake-indexeddb": "6.2.5",
|
|
61
65
|
"lefthook": "2.1.16",
|
|
62
66
|
"monocart-coverage-reports": "2.13.0",
|
|
63
67
|
"playwright-core": "1.63.0",
|
|
@@ -65,6 +69,7 @@
|
|
|
65
69
|
"typescript": "7.0.2"
|
|
66
70
|
},
|
|
67
71
|
"dependencies": {
|
|
72
|
+
"@ai-ecoverse/slicc-kernel": "1.9.0",
|
|
68
73
|
"@earendil-works/chord": "1.0.4",
|
|
69
74
|
"@earendil-works/pi-ai": "1.0.4",
|
|
70
75
|
"@earendil-works/pi-client": "1.0.4",
|