@ai-ecoverse/slicc-agent 3.18.0 → 3.19.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 CHANGED
@@ -87,7 +87,7 @@ const owner = await startAgent({
87
87
 
88
88
  **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`. Requests go to `us-west-2` unless the stored credential names another region (`AWS_REGION`, set by `connect`'s `region`). The default applies when the credential is read, so keys stored earlier get it too. The settings UI has no region field yet. Bedrock sends no CORS headers, so it needs a CORS-free transport, and its account says so (`needs: 'cors-free-transport'`).
89
89
 
90
- **Adobe.** `adobeProvider()` reaches Adobe's LLM proxy (`ADOBE_PROXY`) with the user's IMS token as a bearer. Its models come from the proxy's `/v1/config` once a token is stored: Anthropic-style models go through pi-ai's `anthropic-messages` API at the proxy root, `api: 'openai'` models through `openai-completions` under `/v1`, and hidden ones are skipped. Every request carries an `X-Session-Id` that is fixed for the worker. The account is a sign-in (`auth: 'oauth'`): `AgentSettings.signIn('adobe')` returns the IMS `clientId`, `scopes` and `imsEnvironment` from `/v1/config`, fetched in the worker through the transport. The page runs the IMS popup and passes the token to `connect`, so `createAgentModel(connection, { login })` takes a `login(providerId, signIn)` that returns a token. The adapter calls `login` before anything else in the click's task, so the page can open its popup while it still has the user's gesture, and `signIn()` then fetches the IMS options lazily. The weekly budget from `/v1/usage` is in the settings state as `budget` (refreshed on connect and every five minutes), and the `tray` adapter shows it in spectrum's TrayStatus. Until the proxy allows `*.sliccy.ai` (vibemigration#228), Adobe needs a CORS-free transport like Bedrock. An expired session's error card offers **Log in**.
90
+ **Adobe.** `adobeProvider()` reaches Adobe's LLM proxy (`ADOBE_PROXY`) with the user's IMS token as a bearer. Its models come from the proxy's `/v1/config` once a token is stored: Anthropic-style models go through pi-ai's `anthropic-messages` API at the proxy root, `api: 'openai'` models through `openai-completions` under `/v1`, and hidden ones are skipped. Every request carries an `X-Session-Id` that is fixed for the worker. The account is a sign-in (`auth: 'oauth'`): `AgentSettings.signIn('adobe')` returns the IMS `clientId`, `scopes` and `imsEnvironment` from `/v1/config`, fetched in the worker through the transport. The page runs the IMS popup and passes the token to `connect`, so `createAgentModel(connection, { login })` takes a `login(providerId, signIn, { signal })` that returns a token. While it runs, the account shows as `signing-in` (spectrum ≥ 1.34.0), and `SettingsPort.cancel(id)` aborts the signal; a cancelled sign-in never connects, even if the login resolves late. The adapter calls `login` before anything else in the click's task, so the page can open its popup while it still has the user's gesture, and `signIn()` then fetches the IMS options lazily. The weekly budget from `/v1/usage` is in the settings state as `budget` (refreshed on connect and every five minutes), and the `tray` adapter shows it in spectrum's TrayStatus. Until the proxy allows `*.sliccy.ai` (vibemigration#228), Adobe needs a CORS-free transport like Bedrock. An expired session's error card offers **Log in**.
91
91
 
92
92
  **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.
93
93
 
@@ -14,6 +14,7 @@ class SettingsAdapter extends Emitter {
14
14
  #agent;
15
15
  #storage;
16
16
  #login;
17
+ #signing = /* @__PURE__ */ new Map();
17
18
  #local;
18
19
  constructor(settings, agent, storage, login = null) {
19
20
  super();
@@ -57,18 +58,42 @@ class SettingsAdapter extends Emitter {
57
58
  }));
58
59
  }
59
60
  accounts() {
60
- return this.#state().accounts.map(
61
- ({ needs, ...account }) => needs ? { ...account, needs } : account
62
- );
61
+ return this.#state().accounts.map(({ needs, ...account }) => {
62
+ const shown = this.#signing.has(account.id) ? { ...account, status: "signing-in" } : account;
63
+ return needs ? { ...shown, needs } : shown;
64
+ });
63
65
  }
64
66
  async connect(id, secret, options = {}) {
65
67
  const account = this.#state().accounts.find((candidate) => candidate.id === id);
66
68
  const login = account?.auth === "oauth" ? this.#login : null;
67
- const key = secret ?? (login ? await login(id, () => this.#settings.signIn(id, BACKGROUND_CONTEXT)) : void 0);
69
+ const key = secret ?? (login ? await this.#signIn(id, login) : void 0);
68
70
  if (!key)
69
71
  throw new Error(`${id} needs ${account?.auth === "oauth" ? "a sign-in" : "an API key"}`);
70
72
  await this.#settings.connect(id, key, options.region ?? null, BACKGROUND_CONTEXT);
71
73
  }
74
+ async #signIn(id, login) {
75
+ const controller = new AbortController();
76
+ this.#signing.get(id)?.abort(new DOMException("A newer sign-in replaced this one.", "AbortError"));
77
+ this.#signing.set(id, controller);
78
+ this.emit("accounts", this.accounts());
79
+ try {
80
+ const key = await login(id, () => this.#settings.signIn(id, BACKGROUND_CONTEXT), {
81
+ signal: controller.signal
82
+ });
83
+ controller.signal.throwIfAborted();
84
+ return key;
85
+ } finally {
86
+ if (this.#signing.get(id) === controller) this.#signing.delete(id);
87
+ this.emit("accounts", this.accounts());
88
+ }
89
+ }
90
+ cancel(id) {
91
+ const controller = this.#signing.get(id);
92
+ if (!controller) return;
93
+ this.#signing.delete(id);
94
+ controller.abort(new DOMException("The sign-in was cancelled.", "AbortError"));
95
+ this.emit("accounts", this.accounts());
96
+ }
72
97
  disconnect(id) {
73
98
  void this.#settings.disconnect(id, BACKGROUND_CONTEXT);
74
99
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
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, SignIn } from '../services.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 type Login = (providerId: string, signIn: () => Promise<SignIn | null>) => Promise<string>;\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 readonly #login: Login | null;\n #local: Local;\n\n constructor(\n settings: AgentSettings,\n agent: AgentAdapter,\n storage: Pick<Storage, 'getItem' | 'setItem'> | null,\n login: Login | null = null\n ) {\n super();\n this.#settings = settings;\n this.#agent = agent;\n this.#storage = storage;\n this.#login = login;\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, images }) => ({\n id,\n label,\n provider,\n kind,\n reasoning,\n ...(images === undefined ? {} : { images }),\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 const account = this.#state().accounts.find((candidate) => candidate.id === id);\n const login = account?.auth === 'oauth' ? this.#login : null;\n const key =\n secret ??\n (login ? await login(id, () => this.#settings.signIn(id, BACKGROUND_CONTEXT)) : undefined);\n if (!key)\n throw new Error(`${id} needs ${account?.auth === 'oauth' ? 'a sign-in' : 'an API key'}`);\n await this.#settings.connect(id, key, 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": "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",
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, SignIn } from '../services.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 type Login = (\n providerId: string,\n signIn: () => Promise<SignIn | null>,\n options: { signal: AbortSignal }\n) => Promise<string>;\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 readonly #login: Login | null;\n readonly #signing = new Map<string, AbortController>();\n #local: Local;\n\n constructor(\n settings: AgentSettings,\n agent: AgentAdapter,\n storage: Pick<Storage, 'getItem' | 'setItem'> | null,\n login: Login | null = null\n ) {\n super();\n this.#settings = settings;\n this.#agent = agent;\n this.#storage = storage;\n this.#login = login;\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, images }) => ({\n id,\n label,\n provider,\n kind,\n reasoning,\n ...(images === undefined ? {} : { images }),\n }));\n }\n\n accounts(): readonly Account[] {\n return this.#state().accounts.map(({ needs, ...account }) => {\n const shown = this.#signing.has(account.id)\n ? { ...account, status: 'signing-in' as const }\n : account;\n return needs ? { ...shown, needs } : shown;\n });\n }\n\n async connect(id: string, secret?: string, options: { region?: string } = {}): Promise<void> {\n const account = this.#state().accounts.find((candidate) => candidate.id === id);\n const login = account?.auth === 'oauth' ? this.#login : null;\n const key = secret ?? (login ? await this.#signIn(id, login) : undefined);\n if (!key)\n throw new Error(`${id} needs ${account?.auth === 'oauth' ? 'a sign-in' : 'an API key'}`);\n await this.#settings.connect(id, key, options.region ?? null, BACKGROUND_CONTEXT);\n }\n\n async #signIn(id: string, login: Login): Promise<string> {\n const controller = new AbortController();\n this.#signing\n .get(id)\n ?.abort(new DOMException('A newer sign-in replaced this one.', 'AbortError'));\n this.#signing.set(id, controller);\n this.emit('accounts', this.accounts());\n try {\n const key = await login(id, () => this.#settings.signIn(id, BACKGROUND_CONTEXT), {\n signal: controller.signal,\n });\n controller.signal.throwIfAborted();\n return key;\n } finally {\n if (this.#signing.get(id) === controller) this.#signing.delete(id);\n this.emit('accounts', this.accounts());\n }\n }\n\n cancel(id: string): void {\n const controller = this.#signing.get(id);\n if (!controller) return;\n this.#signing.delete(id);\n controller.abort(new DOMException('The sign-in was cancelled.', 'AbortError'));\n this.emit('accounts', this.accounts());\n }\n\n disconnect(id: string): void {\n void this.#settings.disconnect(id, BACKGROUND_CONTEXT);\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -3,7 +3,9 @@ import type { AgentSettings, SignIn } from '../services.ts';
3
3
  import type { AgentAdapter } from './agent-port.ts';
4
4
  import { Emitter } from './emitter.ts';
5
5
  export declare const SETTINGS_KEY = "slicc-agent.settings";
6
- export type Login = (providerId: string, signIn: () => Promise<SignIn | null>) => Promise<string>;
6
+ export type Login = (providerId: string, signIn: () => Promise<SignIn | null>, options: {
7
+ signal: AbortSignal;
8
+ }) => Promise<string>;
7
9
  export declare class SettingsAdapter extends Emitter<SettingsEvents> implements SettingsPort {
8
10
  #private;
9
11
  constructor(settings: AgentSettings, agent: AgentAdapter, storage: Pick<Storage, 'getItem' | 'setItem'> | null, login?: Login | null);
@@ -14,5 +16,6 @@ export declare class SettingsAdapter extends Emitter<SettingsEvents> implements
14
16
  connect(id: string, secret?: string, options?: {
15
17
  region?: string;
16
18
  }): Promise<void>;
19
+ cancel(id: string): void;
17
20
  disconnect(id: string): void;
18
21
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-ecoverse/slicc-agent",
3
- "version": "3.18.0",
3
+ "version": "3.19.0",
4
4
  "description": "SLICC's agent core on pi durable: an agent worker, session storage, remoting and pi extensions",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -62,7 +62,7 @@
62
62
  },
63
63
  "devDependencies": {
64
64
  "@ai-ecoverse/slicc-shared-web": "1.10.0",
65
- "@ai-ecoverse/slicc-spectrum": "1.33.0",
65
+ "@ai-ecoverse/slicc-spectrum": "1.34.0",
66
66
  "@ai-ecoverse/wasm-bash": "5.3.0-8",
67
67
  "@ai-ecoverse/wasm-coreutils": "9.7.0-3",
68
68
  "@biomejs/biome": "2.5.15",
@@ -87,7 +87,7 @@
87
87
  "@sqlite.org/sqlite-wasm": "3.53.4-build2"
88
88
  },
89
89
  "peerDependencies": {
90
- "@ai-ecoverse/slicc-spectrum": "^1.28.0"
90
+ "@ai-ecoverse/slicc-spectrum": "^1.34.0"
91
91
  },
92
92
  "peerDependenciesMeta": {
93
93
  "@ai-ecoverse/slicc-spectrum": {