@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.
Files changed (44) hide show
  1. package/README.md +34 -2
  2. package/dist/agent-worker.js +6 -0
  3. package/dist/agent-worker.js.map +7 -0
  4. package/dist/client.js +4 -1
  5. package/dist/client.js.map +2 -2
  6. package/dist/credentials.js +100 -0
  7. package/dist/credentials.js.map +7 -0
  8. package/dist/host.js +15 -3
  9. package/dist/host.js.map +2 -2
  10. package/dist/index.js +30 -1
  11. package/dist/index.js.map +2 -2
  12. package/dist/listener.js +73 -0
  13. package/dist/listener.js.map +7 -0
  14. package/dist/main.js +46 -0
  15. package/dist/main.js.map +7 -0
  16. package/dist/net.js +39 -0
  17. package/dist/net.js.map +7 -0
  18. package/dist/patches.js +24 -0
  19. package/dist/patches.js.map +7 -0
  20. package/dist/prompt.js +18 -0
  21. package/dist/prompt.js.map +7 -0
  22. package/dist/settings.js +77 -0
  23. package/dist/settings.js.map +7 -0
  24. package/dist/spectrum/index.js +10 -2
  25. package/dist/spectrum/index.js.map +3 -3
  26. package/dist/spectrum/settings-port.js +73 -0
  27. package/dist/spectrum/settings-port.js.map +7 -0
  28. package/dist/types/agent-worker.d.ts +1 -0
  29. package/dist/types/client.d.ts +2 -0
  30. package/dist/types/credentials.d.ts +12 -0
  31. package/dist/types/host.d.ts +3 -1
  32. package/dist/types/index.d.ts +8 -1
  33. package/dist/types/listener.d.ts +11 -0
  34. package/dist/types/main.d.ts +23 -0
  35. package/dist/types/net.d.ts +19 -0
  36. package/dist/types/patches.d.ts +10 -0
  37. package/dist/types/prompt.d.ts +1 -0
  38. package/dist/types/settings.d.ts +37 -0
  39. package/dist/types/spectrum/index.d.ts +6 -1
  40. package/dist/types/spectrum/settings-port.d.ts +17 -0
  41. package/dist/types/wire.d.ts +6 -10
  42. package/dist/wire.js +1 -67
  43. package/dist/wire.js.map +2 -2
  44. package/package.json +9 -3
@@ -0,0 +1,24 @@
1
+ import { Server } from "@earendil-works/pi-server";
2
+ import { withUnrefTimers } from "./wire.js";
3
+ const applied = /* @__PURE__ */ Symbol.for("slicc.agent.patches");
4
+ function patchServerAccept(target) {
5
+ if (target[applied]) return;
6
+ const original = target.prototype.accept;
7
+ if (typeof original !== "function" || !String(original).includes("handshakeTimeout.unref()")) {
8
+ throw new Error(
9
+ "pi-server-handshake-unref: Server.prototype.accept no longer calls handshakeTimeout.unref(); revisit patches.json"
10
+ );
11
+ }
12
+ target.prototype.accept = function accept(...args) {
13
+ return withUnrefTimers(() => original.apply(this, args));
14
+ };
15
+ target[applied] = true;
16
+ }
17
+ function applyPatches() {
18
+ patchServerAccept(Server);
19
+ }
20
+ export {
21
+ applyPatches,
22
+ patchServerAccept
23
+ };
24
+ //# sourceMappingURL=patches.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/patches.ts"],
4
+ "sourcesContent": ["import { Server } from '@earendil-works/pi-server';\nimport { withUnrefTimers } from './wire.ts';\n\nconst applied = Symbol.for('slicc.agent.patches');\n\ninterface Patchable {\n prototype: { accept: (...args: unknown[]) => unknown };\n [applied]?: true;\n}\n\nexport function patchServerAccept(target: Patchable): void {\n if (target[applied]) return;\n const original = target.prototype.accept;\n if (typeof original !== 'function' || !String(original).includes('handshakeTimeout.unref()')) {\n throw new Error(\n 'pi-server-handshake-unref: Server.prototype.accept no longer calls handshakeTimeout.unref(); revisit patches.json'\n );\n }\n target.prototype.accept = function accept(this: unknown, ...args: unknown[]) {\n return withUnrefTimers(() => original.apply(this, args));\n };\n target[applied] = true;\n}\n\nexport function applyPatches(): void {\n patchServerAccept(Server as unknown as Patchable);\n}\n"],
5
+ "mappings": "AAAA,SAAS,cAAc;AACvB,SAAS,uBAAuB;AAEhC,MAAM,UAAU,uBAAO,IAAI,qBAAqB;AAOzC,SAAS,kBAAkB,QAAyB;AACzD,MAAI,OAAO,OAAO,EAAG;AACrB,QAAM,WAAW,OAAO,UAAU;AAClC,MAAI,OAAO,aAAa,cAAc,CAAC,OAAO,QAAQ,EAAE,SAAS,0BAA0B,GAAG;AAC5F,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,SAAO,UAAU,SAAS,SAAS,UAAyB,MAAiB;AAC3E,WAAO,gBAAgB,MAAM,SAAS,MAAM,MAAM,IAAI,CAAC;AAAA,EACzD;AACA,SAAO,OAAO,IAAI;AACpB;AAEO,SAAS,eAAqB;AACnC,oBAAkB,MAA8B;AAClD;",
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
+ }
@@ -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
+ }
@@ -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
- function createAgentModel(connection) {
5
- return { agent: new AgentAdapter(connection) };
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 { agent: new AgentAdapter(connection) };\n}\n"],
5
- "mappings": "AACA,SAAS,oBAAoB;AAE7B,SAAS,gBAAAA,eAAc,YAAY;AACnC,SAAS,WAAW,QAAQ,QAAQ,QAAQ,kBAAkB;AAEvD,SAAS,iBAAiB,YAAsD;AACrF,SAAO,EAAE,OAAO,IAAI,aAAa,UAAU,EAAE;AAC/C;",
6
- "names": ["AgentAdapter"]
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>;
@@ -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
+ }
@@ -1,6 +1,7 @@
1
1
  import { type Context } from '@earendil-works/chord';
2
2
  import type { Agent } from './agent.ts';
3
- import { type PortEndpoint } from './wire.ts';
3
+ import { AgentSettings } from './settings.ts';
4
+ import type { PortEndpoint } from './wire.ts';
4
5
  export interface AgentHost {
5
6
  readonly serverId: string;
6
7
  readonly agent: Agent;
@@ -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>;
@@ -1,11 +1,18 @@
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 { PortListener } from './listener.ts';
9
+ export { type AgentWorkerOptions, type AgentWorkerScope, type KernelAttach, runAgentWorker, } from './main.ts';
10
+ export { type Transport, type TransportResponse, transportFetch } from './net.ts';
7
11
  export { AGENT_LOCK, type AgentOwner, type AgentWorker, type OwnerOptions, startAgent, } from './owner.ts';
12
+ export { applyPatches, patchServerAccept } from './patches.ts';
13
+ export { SliccPrompt } from './prompt.ts';
8
14
  export { AGENT_SESSION, AgentControl, AgentSessions, type AgentSettingsChange, AgentTranscript, type OperationError, type PromptResult, type SendMode, type SendRequest, type SendResponse, } from './services.ts';
15
+ export { type AccountState, AgentSettings, BEDROCK, createAgentSettings, createSliccModels, DEFAULT_MODEL, type ModelChoice, type SettingsState, sliccProviders, } from './settings.ts';
9
16
  export { AGENT_DIRECTORY, type OpfsSqliteOptions, openMemorySqliteStorage, openOpfsSqliteStorage, WasmSqliteDatabase, } from './sqlite.ts';
10
- export { PortChannel, type PortEndpoint, PortListener, withUnrefTimers } from './wire.ts';
17
+ export { PortChannel, type PortEndpoint, withUnrefTimers } from './wire.ts';
11
18
  export { kernelPort, serveConnections, type WorkerScope } from './worker.ts';
@@ -0,0 +1,11 @@
1
+ import type { ServerListener } from '@earendil-works/pi-server';
2
+ import { type PortEndpoint } from './wire.ts';
3
+ type ByteConnectionAcceptor = Parameters<ServerListener['start']>[0];
4
+ export declare class PortListener implements ServerListener {
5
+ #private;
6
+ constructor(serverId: string);
7
+ start(accept: ByteConnectionAcceptor): Promise<void>;
8
+ close(): Promise<void>;
9
+ connect(endpoint: PortEndpoint): void;
10
+ }
11
+ export {};
@@ -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,10 @@
1
+ declare const applied: unique symbol;
2
+ interface Patchable {
3
+ prototype: {
4
+ accept: (...args: unknown[]) => unknown;
5
+ };
6
+ [applied]?: true;
7
+ }
8
+ export declare function patchServerAccept(target: Patchable): void;
9
+ export declare function applyPatches(): void;
10
+ export {};
@@ -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 declare function createAgentModel(connection: AgentConnection): {
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
+ }
@@ -1,6 +1,4 @@
1
1
  import type { ByteTransportFactory } from '@earendil-works/pi-client';
2
- import type { ServerListener } from '@earendil-works/pi-server';
3
- type ByteConnectionAcceptor = Parameters<ServerListener['start']>[0];
4
2
  export interface PortEndpoint {
5
3
  postMessage(message: unknown, transfer?: Transferable[]): void;
6
4
  addEventListener(type: 'message', listener: (event: MessageEvent) => void): void;
@@ -8,20 +6,18 @@ export interface PortEndpoint {
8
6
  start?(): void;
9
7
  close?(): void;
10
8
  }
9
+ export type Frame = {
10
+ hello: string;
11
+ } | {
12
+ close: true;
13
+ } | Uint8Array;
14
+ export declare function post(endpoint: PortEndpoint, chunk: Uint8Array): void;
11
15
  export declare function withUnrefTimers<T>(run: () => T, scope?: {
12
16
  setTimeout: typeof setTimeout;
13
17
  }): T;
14
- export declare class PortListener implements ServerListener {
15
- #private;
16
- constructor(serverId: string);
17
- start(accept: ByteConnectionAcceptor): Promise<void>;
18
- close(): Promise<void>;
19
- connect(endpoint: PortEndpoint): void;
20
- }
21
18
  export declare class PortChannel {
22
19
  #private;
23
20
  readonly hello: Promise<string>;
24
21
  constructor(endpoint: PortEndpoint);
25
22
  readonly transport: ByteTransportFactory;
26
23
  }
27
- export {};
package/dist/wire.js CHANGED
@@ -25,72 +25,6 @@ function withUnrefTimers(run, scope = globalThis) {
25
25
  scope.setTimeout = original;
26
26
  }
27
27
  }
28
- class PortConnection {
29
- closed = false;
30
- #endpoint;
31
- #ended;
32
- constructor(endpoint, ended) {
33
- this.#endpoint = endpoint;
34
- this.#ended = ended;
35
- }
36
- async send(chunk) {
37
- if (this.closed) throw new Error("connection is closed");
38
- post(this.#endpoint, chunk);
39
- }
40
- close(finalChunk) {
41
- if (this.closed) return;
42
- if (finalChunk) post(this.#endpoint, finalChunk);
43
- this.closed = true;
44
- this.#endpoint.postMessage({ close: true });
45
- this.#endpoint.close?.();
46
- this.#ended();
47
- }
48
- end() {
49
- this.closed = true;
50
- this.#ended();
51
- }
52
- }
53
- class PortListener {
54
- #serverId;
55
- #connections = /* @__PURE__ */ new Set();
56
- #accept;
57
- constructor(serverId) {
58
- this.#serverId = serverId;
59
- }
60
- async start(accept) {
61
- this.#accept = accept;
62
- }
63
- async close() {
64
- for (const connection of [...this.#connections]) connection.close();
65
- this.#accept = void 0;
66
- }
67
- connect(endpoint) {
68
- const accept = this.#accept;
69
- if (!accept) throw new Error("agent host is not listening");
70
- const connection = new PortConnection(endpoint, () => this.#connections.delete(connection));
71
- this.#connections.add(connection);
72
- const handler = withUnrefTimers(() => accept(connection));
73
- endpoint.addEventListener("message", ({ data }) => {
74
- if (data instanceof Uint8Array) handler.onData(data);
75
- else if (data?.close) {
76
- connection.end();
77
- handler.onClose();
78
- }
79
- });
80
- const failed = (event) => {
81
- connection.end();
82
- handler.onError(new Error(`agent port ${event.type}`));
83
- };
84
- endpoint.addEventListener("messageerror", failed);
85
- endpoint.addEventListener("close", () => {
86
- if (connection.closed) return;
87
- connection.end();
88
- handler.onClose();
89
- });
90
- endpoint.start?.();
91
- endpoint.postMessage({ hello: this.#serverId });
92
- }
93
- }
94
28
  class PortChannel {
95
29
  hello;
96
30
  #endpoint;
@@ -158,7 +92,7 @@ class PortChannel {
158
92
  }
159
93
  export {
160
94
  PortChannel,
161
- PortListener,
95
+ post,
162
96
  withUnrefTimers
163
97
  };
164
98
  //# sourceMappingURL=wire.js.map