@ai-ecoverse/slicc-agent 2.2.0 → 2.4.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 +34 -2
- 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 +15 -3
- package/dist/host.js.map +2 -2
- package/dist/index.js +30 -1
- package/dist/index.js.map +2 -2
- package/dist/listener.js +73 -0
- package/dist/listener.js.map +7 -0
- 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/patches.js +24 -0
- package/dist/patches.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 +3 -1
- package/dist/types/index.d.ts +8 -1
- package/dist/types/listener.d.ts +11 -0
- package/dist/types/main.d.ts +23 -0
- package/dist/types/net.d.ts +19 -0
- package/dist/types/patches.d.ts +10 -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/dist/types/wire.d.ts +6 -10
- package/dist/wire.js +1 -67
- package/dist/wire.js.map +2 -2
- package/package.json +9 -3
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,12 +87,22 @@ 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
|
+
## Patched dependencies
|
|
98
|
+
|
|
99
|
+
Fixes to pi stay in this repository. [`patches/patches.json`](patches/patches.json) lists each one with its `kind`, `package`, `patchedVersion`, `reason`, `removeWhen` and `verify` command, and an optional `marker` (a file in the package and a string it must contain):
|
|
100
|
+
|
|
101
|
+
- `monkeypatch`: code that runs in users' browsers is patched at runtime. `applyPatches()` in [`src/patches.ts`](src/patches.ts) applies them once before pi is used: `PortListener.start()` calls it, so `hostAgent` and a `PortListener` used directly with pi's `Server` both get them. Each one checks that the code it replaces still looks as expected and throws, naming its manifest entry, if not. Today there is one: pi-server's `Server.accept` calls `unref()` on its handshake timer, which browsers don't have, so the patch gives numeric timer ids a no-op `unref`.
|
|
102
|
+
- `patch-package`: repository-only fixes go in `patches/<package>+<version>.patch`, applied by a `postinstall` that runs [patch-package](https://github.com/ds300/patch-package). There are none yet.
|
|
103
|
+
- `environment`: something the host must provide. pi-server imports `randomUUID` from `node:crypto`; slicc-bios serves a stub backed by `globalThis.crypto`, and the integration bundles alias it to `test/integration/shims/node-crypto.js`.
|
|
104
|
+
|
|
105
|
+
`npm run lint:patches` (part of `npm run lint`) fails when an installed version differs from `patchedVersion`, a marker is gone, a monkeypatch isn't named in `src/patches.ts`, a patch file and its entry don't match, or `renovate.json` doesn't route the package to the `patched dependencies` group with automerge off. That group covers every `@earendil-works/*` package, so a pi bump is always a reviewed PR: rerun each entry's `verify`, then move `patchedVersion` forward or drop the entry.
|
|
74
106
|
|
|
75
107
|
## Develop
|
|
76
108
|
|
|
@@ -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 {
|
|
@@ -8,8 +9,9 @@ import {
|
|
|
8
9
|
SessionNotFoundError
|
|
9
10
|
} from "@earendil-works/pi-server";
|
|
10
11
|
import { createAgentControl } from "./control.js";
|
|
12
|
+
import { PortListener } from "./listener.js";
|
|
11
13
|
import { AGENT_SESSION, AgentControl, AgentSessions, AgentTranscript } from "./services.js";
|
|
12
|
-
import {
|
|
14
|
+
import { AgentSettings } from "./settings.js";
|
|
13
15
|
function endpointFor(provider) {
|
|
14
16
|
const endpoint = createRemoteServiceEndpoint(provider);
|
|
15
17
|
return {
|
|
@@ -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
|
|
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,
|
|
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 { PortListener } from './listener.ts';\nimport { AGENT_SESSION, AgentControl, AgentSessions, AgentTranscript } from './services.ts';\nimport { AgentSettings } from './settings.ts';\nimport type { PortEndpoint } 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,25 +1,41 @@
|
|
|
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 { PortListener } from "./listener.js";
|
|
8
|
+
import {
|
|
9
|
+
runAgentWorker
|
|
10
|
+
} from "./main.js";
|
|
11
|
+
import { transportFetch } from "./net.js";
|
|
6
12
|
import {
|
|
7
13
|
AGENT_LOCK,
|
|
8
14
|
startAgent
|
|
9
15
|
} from "./owner.js";
|
|
16
|
+
import { applyPatches, patchServerAccept } from "./patches.js";
|
|
17
|
+
import { SliccPrompt } from "./prompt.js";
|
|
10
18
|
import {
|
|
11
19
|
AGENT_SESSION,
|
|
12
20
|
AgentControl,
|
|
13
21
|
AgentSessions,
|
|
14
22
|
AgentTranscript
|
|
15
23
|
} from "./services.js";
|
|
24
|
+
import {
|
|
25
|
+
AgentSettings,
|
|
26
|
+
BEDROCK,
|
|
27
|
+
createAgentSettings,
|
|
28
|
+
createSliccModels,
|
|
29
|
+
DEFAULT_MODEL,
|
|
30
|
+
sliccProviders
|
|
31
|
+
} from "./settings.js";
|
|
16
32
|
import {
|
|
17
33
|
AGENT_DIRECTORY,
|
|
18
34
|
openMemorySqliteStorage,
|
|
19
35
|
openOpfsSqliteStorage,
|
|
20
36
|
WasmSqliteDatabase
|
|
21
37
|
} from "./sqlite.js";
|
|
22
|
-
import { PortChannel,
|
|
38
|
+
import { PortChannel, withUnrefTimers } from "./wire.js";
|
|
23
39
|
import { kernelPort, serveConnections } from "./worker.js";
|
|
24
40
|
export {
|
|
25
41
|
AGENT_DIRECTORY,
|
|
@@ -27,23 +43,36 @@ export {
|
|
|
27
43
|
AGENT_SESSION,
|
|
28
44
|
AgentControl,
|
|
29
45
|
AgentSessions,
|
|
46
|
+
AgentSettings,
|
|
30
47
|
AgentTranscript,
|
|
48
|
+
BEDROCK,
|
|
49
|
+
CREDENTIALS_DATABASE,
|
|
50
|
+
DEFAULT_MODEL,
|
|
51
|
+
EncryptedCredentialStore,
|
|
31
52
|
HOME,
|
|
32
53
|
PortChannel,
|
|
33
54
|
PortListener,
|
|
34
55
|
SliccKernelEnv,
|
|
56
|
+
SliccPrompt,
|
|
35
57
|
WasmSqliteDatabase,
|
|
36
58
|
answerText,
|
|
59
|
+
applyPatches,
|
|
37
60
|
connectAgent,
|
|
38
61
|
createAgentControl,
|
|
62
|
+
createAgentSettings,
|
|
63
|
+
createSliccModels,
|
|
39
64
|
hostAgent,
|
|
40
65
|
kernelEnvironment,
|
|
41
66
|
kernelPort,
|
|
42
67
|
openAgent,
|
|
43
68
|
openMemorySqliteStorage,
|
|
44
69
|
openOpfsSqliteStorage,
|
|
70
|
+
patchServerAccept,
|
|
71
|
+
runAgentWorker,
|
|
45
72
|
serveConnections,
|
|
73
|
+
sliccProviders,
|
|
46
74
|
startAgent,
|
|
75
|
+
transportFetch,
|
|
47
76
|
withUnrefTimers
|
|
48
77
|
};
|
|
49
78
|
//# 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,
|
|
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,
|
|
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 { PortListener } from './listener.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 { applyPatches, patchServerAccept } from './patches.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, 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,SAAS,oBAAoB;AAC7B;AAAA,EAIE;AAAA,OACK;AACP,SAAiD,sBAAsB;AACvE;AAAA,EACE;AAAA,EAIA;AAAA,OACK;AACP,SAAS,cAAc,yBAAyB;AAChD,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,uBAAuB;AAChE,SAAS,YAAY,wBAA0C;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/listener.js
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { applyPatches } from "./patches.js";
|
|
2
|
+
import { post } from "./wire.js";
|
|
3
|
+
class PortConnection {
|
|
4
|
+
closed = false;
|
|
5
|
+
#endpoint;
|
|
6
|
+
#ended;
|
|
7
|
+
constructor(endpoint, ended) {
|
|
8
|
+
this.#endpoint = endpoint;
|
|
9
|
+
this.#ended = ended;
|
|
10
|
+
}
|
|
11
|
+
async send(chunk) {
|
|
12
|
+
if (this.closed) throw new Error("connection is closed");
|
|
13
|
+
post(this.#endpoint, chunk);
|
|
14
|
+
}
|
|
15
|
+
close(finalChunk) {
|
|
16
|
+
if (this.closed) return;
|
|
17
|
+
if (finalChunk) post(this.#endpoint, finalChunk);
|
|
18
|
+
this.closed = true;
|
|
19
|
+
this.#endpoint.postMessage({ close: true });
|
|
20
|
+
this.#endpoint.close?.();
|
|
21
|
+
this.#ended();
|
|
22
|
+
}
|
|
23
|
+
end() {
|
|
24
|
+
this.closed = true;
|
|
25
|
+
this.#ended();
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
class PortListener {
|
|
29
|
+
#serverId;
|
|
30
|
+
#connections = /* @__PURE__ */ new Set();
|
|
31
|
+
#accept;
|
|
32
|
+
constructor(serverId) {
|
|
33
|
+
this.#serverId = serverId;
|
|
34
|
+
}
|
|
35
|
+
async start(accept) {
|
|
36
|
+
applyPatches();
|
|
37
|
+
this.#accept = accept;
|
|
38
|
+
}
|
|
39
|
+
async close() {
|
|
40
|
+
for (const connection of [...this.#connections]) connection.close();
|
|
41
|
+
this.#accept = void 0;
|
|
42
|
+
}
|
|
43
|
+
connect(endpoint) {
|
|
44
|
+
const accept = this.#accept;
|
|
45
|
+
if (!accept) throw new Error("agent host is not listening");
|
|
46
|
+
const connection = new PortConnection(endpoint, () => this.#connections.delete(connection));
|
|
47
|
+
this.#connections.add(connection);
|
|
48
|
+
const handler = accept(connection);
|
|
49
|
+
endpoint.addEventListener("message", ({ data }) => {
|
|
50
|
+
if (data instanceof Uint8Array) handler.onData(data);
|
|
51
|
+
else if (data?.close) {
|
|
52
|
+
connection.end();
|
|
53
|
+
handler.onClose();
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
const failed = (event) => {
|
|
57
|
+
connection.end();
|
|
58
|
+
handler.onError(new Error(`agent port ${event.type}`));
|
|
59
|
+
};
|
|
60
|
+
endpoint.addEventListener("messageerror", failed);
|
|
61
|
+
endpoint.addEventListener("close", () => {
|
|
62
|
+
if (connection.closed) return;
|
|
63
|
+
connection.end();
|
|
64
|
+
handler.onClose();
|
|
65
|
+
});
|
|
66
|
+
endpoint.start?.();
|
|
67
|
+
endpoint.postMessage({ hello: this.#serverId });
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
export {
|
|
71
|
+
PortListener
|
|
72
|
+
};
|
|
73
|
+
//# sourceMappingURL=listener.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/listener.ts"],
|
|
4
|
+
"sourcesContent": ["import type { ServerListener } from '@earendil-works/pi-server';\nimport { applyPatches } from './patches.ts';\nimport { type Frame, type PortEndpoint, post } from './wire.ts';\n\ntype ByteConnectionAcceptor = Parameters<ServerListener['start']>[0];\ntype ByteConnection = Parameters<ByteConnectionAcceptor>[0];\ntype ByteConnectionHandler = ReturnType<ByteConnectionAcceptor>;\n\nclass PortConnection implements ByteConnection {\n closed = false;\n readonly #endpoint: PortEndpoint;\n readonly #ended: () => void;\n\n constructor(endpoint: PortEndpoint, ended: () => void) {\n this.#endpoint = endpoint;\n this.#ended = ended;\n }\n\n async send(chunk: Uint8Array): Promise<void> {\n if (this.closed) throw new Error('connection is closed');\n post(this.#endpoint, chunk);\n }\n\n close(finalChunk?: Uint8Array): void {\n if (this.closed) return;\n if (finalChunk) post(this.#endpoint, finalChunk);\n this.closed = true;\n this.#endpoint.postMessage({ close: true } satisfies Frame);\n this.#endpoint.close?.();\n this.#ended();\n }\n\n end(): void {\n this.closed = true;\n this.#ended();\n }\n}\n\nexport class PortListener implements ServerListener {\n readonly #serverId: string;\n readonly #connections = new Set<PortConnection>();\n #accept: ByteConnectionAcceptor | undefined;\n\n constructor(serverId: string) {\n this.#serverId = serverId;\n }\n\n async start(accept: ByteConnectionAcceptor): Promise<void> {\n applyPatches();\n this.#accept = accept;\n }\n\n async close(): Promise<void> {\n for (const connection of [...this.#connections]) connection.close();\n this.#accept = undefined;\n }\n\n connect(endpoint: PortEndpoint): void {\n const accept = this.#accept;\n if (!accept) throw new Error('agent host is not listening');\n const connection = new PortConnection(endpoint, () => this.#connections.delete(connection));\n this.#connections.add(connection);\n const handler: ByteConnectionHandler = accept(connection);\n endpoint.addEventListener('message', ({ data }) => {\n if (data instanceof Uint8Array) handler.onData(data);\n else if ((data as { close?: boolean } | null)?.close) {\n connection.end();\n handler.onClose();\n }\n });\n const failed = (event: Event) => {\n connection.end();\n handler.onError(new Error(`agent port ${event.type}`));\n };\n endpoint.addEventListener('messageerror', failed);\n endpoint.addEventListener('close', () => {\n if (connection.closed) return;\n connection.end();\n handler.onClose();\n });\n endpoint.start?.();\n endpoint.postMessage({ hello: this.#serverId } satisfies Frame);\n }\n}\n"],
|
|
5
|
+
"mappings": "AACA,SAAS,oBAAoB;AAC7B,SAAwC,YAAY;AAMpD,MAAM,eAAyC;AAAA,EAC7C,SAAS;AAAA,EACA;AAAA,EACA;AAAA,EAET,YAAY,UAAwB,OAAmB;AACrD,SAAK,YAAY;AACjB,SAAK,SAAS;AAAA,EAChB;AAAA,EAEA,MAAM,KAAK,OAAkC;AAC3C,QAAI,KAAK,OAAQ,OAAM,IAAI,MAAM,sBAAsB;AACvD,SAAK,KAAK,WAAW,KAAK;AAAA,EAC5B;AAAA,EAEA,MAAM,YAA+B;AACnC,QAAI,KAAK,OAAQ;AACjB,QAAI,WAAY,MAAK,KAAK,WAAW,UAAU;AAC/C,SAAK,SAAS;AACd,SAAK,UAAU,YAAY,EAAE,OAAO,KAAK,CAAiB;AAC1D,SAAK,UAAU,QAAQ;AACvB,SAAK,OAAO;AAAA,EACd;AAAA,EAEA,MAAY;AACV,SAAK,SAAS;AACd,SAAK,OAAO;AAAA,EACd;AACF;AAEO,MAAM,aAAuC;AAAA,EACzC;AAAA,EACA,eAAe,oBAAI,IAAoB;AAAA,EAChD;AAAA,EAEA,YAAY,UAAkB;AAC5B,SAAK,YAAY;AAAA,EACnB;AAAA,EAEA,MAAM,MAAM,QAA+C;AACzD,iBAAa;AACb,SAAK,UAAU;AAAA,EACjB;AAAA,EAEA,MAAM,QAAuB;AAC3B,eAAW,cAAc,CAAC,GAAG,KAAK,YAAY,EAAG,YAAW,MAAM;AAClE,SAAK,UAAU;AAAA,EACjB;AAAA,EAEA,QAAQ,UAA8B;AACpC,UAAM,SAAS,KAAK;AACpB,QAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,6BAA6B;AAC1D,UAAM,aAAa,IAAI,eAAe,UAAU,MAAM,KAAK,aAAa,OAAO,UAAU,CAAC;AAC1F,SAAK,aAAa,IAAI,UAAU;AAChC,UAAM,UAAiC,OAAO,UAAU;AACxD,aAAS,iBAAiB,WAAW,CAAC,EAAE,KAAK,MAAM;AACjD,UAAI,gBAAgB,WAAY,SAAQ,OAAO,IAAI;AAAA,eACzC,MAAqC,OAAO;AACpD,mBAAW,IAAI;AACf,gBAAQ,QAAQ;AAAA,MAClB;AAAA,IACF,CAAC;AACD,UAAM,SAAS,CAAC,UAAiB;AAC/B,iBAAW,IAAI;AACf,cAAQ,QAAQ,IAAI,MAAM,cAAc,MAAM,IAAI,EAAE,CAAC;AAAA,IACvD;AACA,aAAS,iBAAiB,gBAAgB,MAAM;AAChD,aAAS,iBAAiB,SAAS,MAAM;AACvC,UAAI,WAAW,OAAQ;AACvB,iBAAW,IAAI;AACf,cAAQ,QAAQ;AAAA,IAClB,CAAC;AACD,aAAS,QAAQ;AACjB,aAAS,YAAY,EAAE,OAAO,KAAK,UAAU,CAAiB;AAAA,EAChE;AACF;",
|
|
6
|
+
"names": []
|
|
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
|
+
}
|