@ai-ecoverse/slicc-agent 3.37.1 → 3.39.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
@@ -30,7 +30,7 @@ await agent.prompt('What is in /home?');
30
30
  - `openOpfsSqliteStorage({ directory?, file? })` keeps the session in wasm SQLite ([`@sqlite.org/sqlite-wasm`](https://www.npmjs.com/package/@sqlite.org/sqlite-wasm)) in an `opfs-sahpool` pool, by default `/.slicc/agent/` in OPFS. It needs a dedicated worker. Only one worker holds a pool at a time: the opener takes a Web Lock per directory and waits until every file of the pool can be opened before sqlite-wasm installs it, because a failed install deletes the pool's directory. `openMemorySqliteStorage()` keeps the same database in memory.
31
31
  - `hostAgent(agent)` serves the agent with pi's protocol: a pi-server with one session, `agent`, whose Chord services are `slicc.agent.control` (send with `whenBusy` `steer`, `followUp` or `reject`, wait, withdraw, abort, compact) and `slicc.agent.transcript` (the conversation's durable view as replicated state, plus `deliveries`: how each user entry was delivered, `run`, `steer` or `follow-up`, derived by the host from where each send it accepted was placed: after a tool result it steered, queued first it's a follow-up or a late steer per its `whenBusy`, placed at once it started a run). `serveConnections(self, host)` hands it every `MessagePort` the page sends.
32
32
  - `@ai-ecoverse/slicc-agent/page` has what the page needs (`startAgent`, `connectAgent`) without the agent's runtime: no pi-durable, pi-ai, providers or SQLite, which load only in the worker. `@ai-ecoverse/slicc-agent/spectrum` is just as light, and a test keeps both that way.
33
- - `startAgent({ worker })` takes the Web Lock `slicc-agent`, so one tab at a time owns the agent worker, and waits while another tab holds it. `connect()` returns an `AgentConnection` (`control`, `transcript`, `prompt()`), `restart()` replaces the worker (durable resumes from SQLite), and `release()` stops it and lets the next tab take over. `port()` returns a raw `MessagePort` into the worker instead, for another tab: hand it over (through a SharedWorker, say), and that tab calls `connectAgent(port)`. A caller that already holds the lock passes `held: true`. A connection's `closed` resolves when its port ends (with the error, if any), and from then on its states keep their last values.
33
+ - `startAgent({ worker })` takes the Web Lock `slicc-agent`, so one tab at a time owns the agent worker, and waits while another tab holds it. `connect()` returns an `AgentConnection` (`control`, `transcript`, `prompt()`, and `webhook(name, { id?, headers?, body })`, which hands a webhook delivery, such as one from the tray hub, to the licks without a chord `Context`), `restart()` replaces the worker (durable resumes from SQLite), and `release()` stops it and lets the next tab take over. `port()` returns a raw `MessagePort` into the worker instead, for another tab: hand it over (through a SharedWorker, say), and that tab calls `connectAgent(port)`. A caller that already holds the lock passes `held: true`. A connection's `closed` resolves when its port ends (with the error, if any), and from then on its states keep their last values.
34
34
  - **Followers over a link** (PR 18): `port({ readOnly: true })` and `connect({ readOnly: true })` give a view-only connection.
35
35
  - **What a view-only connection can do:** it sees the transcript, the agents, settings state and remote-control `watch`, and may call `wait` and `changesOpen`.
36
36
  - **What it can't:** every other `AgentControl` method, settings action and remote-control `prompt` or `abort` is refused with `EACCES` ("this follower can watch, but not send, steer or abort"). Send and compact answer `accepted: false` with that code. The worker serves view-only ports from a second pi-server whose session gets these narrowed services.
@@ -111,6 +111,8 @@ const owner = await startAgent({
111
111
 
112
112
  **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**.
113
113
 
114
+ **Classifiers.** The Adobe provider also registers Cloudflare's Clef classifiers as `adobe/clef` and `adobe/clef-flash` (`adobeClassifiers()`): `type: 'classifier'` models on pi-ai's `cloudflare-workers-ai-system-one` API with `baseUrl: <proxy>/v1/ai`, so `models.classify(model, { state, questions })` posts `{ model: '@cf/cloudflare/clef', input }` to the proxy's `/v1/ai/run` with the IMS token as the bearer. The provider maps its short ids to the Workers AI names, and pi parses the answers and prices the usage ($0.24 per million input tokens for Clef, $0.09 for Clef Flash, nothing for output), which counts against the same weekly budget. They are classifiers only: `models.getModels()`, the settings `models` and the picker list chat models, and `models.getAvailableOfType('classifier', 'adobe')` returns them only while an Adobe token is stored.
115
+
114
116
  **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.
115
117
 
116
118
  **Settings.** The `slicc.agent.settings` service shows the models and accounts and takes `connect(providerId, apiKey)` and `disconnect(providerId)`.
@@ -511,7 +513,7 @@ The built-in `sprinkles` skill teaches the files, the bridge and the command.
511
513
 
512
514
  ## The kernel
513
515
 
514
- `@ai-ecoverse/slicc-kernel` is a peer dependency (`>=1.47.1 <2`, the first kernel with users and the H1 wasm commands; until 3.31.0 the floor was 1.26.3): the agent only calls `attachKernel`, the client end of the page kernel's port, so it must match the kernel the page runs. Seven chooses that version: slicc-bios pins the certified kernel next to the agent in `src/packages/agent/package.json`, and pnpm fills the peer from that pin. The devDependency is the lowest certified kernel the range allows (1.47.1), and the unit and integration tests run on it with the H1 wasm commands as devDependencies. A second CI job reruns the integration tests on the newest certified kernel (`NEWEST_CERTIFIED_KERNEL` in `.github/workflows/ci.yml`), with the wasm commands certified for it (`NEWEST_CERTIFIED_WASM`). Today the floor is 1.47.1 and the newest certified kernel 1.61.0; the second job moves by hand to each newer certified kernel, so both ends of the range are tested. If the port protocol ever breaks within 1.x, a patch release narrows the upper bound. Renovate opens PRs for the kernel, `wasi-pnpm`, the `wasm-*` packages and `slicc-cdp` but never merges them, because they move only after the homescoop coordinator certifies them.
516
+ `@ai-ecoverse/slicc-kernel` is a peer dependency (`>=1.47.1 <2`, the first kernel with users and the H1 wasm commands; until 3.31.0 the floor was 1.26.3): the agent only calls `attachKernel`, the client end of the page kernel's port, so it must match the kernel the page runs. Seven chooses that version: slicc-bios pins the certified kernel next to the agent in `src/packages/agent/package.json`, and pnpm fills the peer from that pin. The devDependency is the lowest certified kernel the range allows (1.47.1), and the unit and integration tests run on it with the H1 wasm commands as devDependencies. A second CI job reruns the integration tests on the newest certified kernel (`NEWEST_CERTIFIED_KERNEL` in `.github/workflows/ci.yml`), with the wasm commands certified for it (`NEWEST_CERTIFIED_WASM`). Today the floor is 1.47.1 and the newest certified kernel 1.62.3; the second job moves by hand to each newer certified kernel, so both ends of the range are tested. If the port protocol ever breaks within 1.x, a patch release narrows the upper bound. Renovate opens PRs for the kernel, `wasi-pnpm`, the `wasm-*` packages and `slicc-cdp` but never merges them, because they move only after the homescoop coordinator certifies them.
515
517
 
516
518
  ## Patched dependencies
517
519
 
package/dist/adobe.js CHANGED
@@ -1,9 +1,49 @@
1
1
  import { anthropicMessagesApi } from "@earendil-works/pi-ai/api/anthropic-messages.lazy";
2
+ import { cloudflareWorkersAISystemOneApi } from "@earendil-works/pi-ai/api/cloudflare-workers-ai-system-one.lazy";
2
3
  import { openAICompletionsApi } from "@earendil-works/pi-ai/api/openai-completions.lazy";
3
4
  import { createProvider } from "@earendil-works/pi-ai/models";
4
5
  const ADOBE = "adobe";
5
6
  const ADOBE_PROXY = "https://adobe-llm-proxy.paolo-moz.workers.dev";
6
7
  const free = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };
8
+ const CLASSIFIER_API = "cloudflare-workers-ai-system-one";
9
+ const WORKERS_AI = "@cf/cloudflare/";
10
+ const CLEF = [
11
+ { id: "clef", name: "Clef", input: 0.24 },
12
+ { id: "clef-flash", name: "Clef Flash", input: 0.09 }
13
+ ];
14
+ function adobeClassifiers(endpoint) {
15
+ return CLEF.map(({ id, name, input }) => ({
16
+ type: "classifier",
17
+ id,
18
+ name,
19
+ provider: ADOBE,
20
+ api: CLASSIFIER_API,
21
+ baseUrl: `${endpoint}/v1/ai`,
22
+ input: ["text"],
23
+ cost: { ...free, input },
24
+ contextWindow: 65536
25
+ }));
26
+ }
27
+ function bearer(headers = {}) {
28
+ const value = Object.entries(headers).find(
29
+ ([name]) => name.toLowerCase() === "authorization"
30
+ )?.[1];
31
+ return value?.replace(/^Bearer\s+/i, "");
32
+ }
33
+ function clef(fetcher) {
34
+ const transport = cloudflareWorkersAISystemOneApi();
35
+ return {
36
+ classify: (model, context, options = {}) => transport.classify(model, context, {
37
+ ...options,
38
+ fetch: options.fetch ?? fetcher,
39
+ apiKey: bearer(options.headers) ?? options.apiKey,
40
+ onPayload: async (payload, sent) => {
41
+ const wire = { ...payload, model: `${WORKERS_AI}${model.id}` };
42
+ return await options.onPayload?.(wire, sent) ?? wire;
43
+ }
44
+ })
45
+ };
46
+ }
7
47
  function adobeModel(info, endpoint) {
8
48
  const openai = info.api === "openai";
9
49
  return {
@@ -64,17 +104,20 @@ function adobeProvider({
64
104
  }
65
105
  }
66
106
  },
67
- models: [],
107
+ models: adobeClassifiers(endpoint),
68
108
  fetchModels: async () => (await adobeConfig(endpoint, fetcher)).models.filter((info) => !info.hidden).map((info) => adobeModel(info, endpoint)),
69
109
  api: {
70
110
  "anthropic-messages": anthropicMessagesApi(),
71
111
  "openai-completions": openAICompletionsApi()
72
- }
112
+ },
113
+ classifiers: { [CLASSIFIER_API]: clef(fetcher) }
73
114
  });
74
115
  }
75
116
  export {
76
117
  ADOBE,
77
118
  ADOBE_PROXY,
119
+ CLASSIFIER_API,
120
+ adobeClassifiers,
78
121
  adobeConfig,
79
122
  adobeModel,
80
123
  adobeProvider,
package/dist/adobe.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/adobe.ts"],
4
- "sourcesContent": ["import type { Provider } from '@earendil-works/pi-ai';\nimport { anthropicMessagesApi } from '@earendil-works/pi-ai/api/anthropic-messages.lazy';\nimport { openAICompletionsApi } from '@earendil-works/pi-ai/api/openai-completions.lazy';\nimport { createProvider } from '@earendil-works/pi-ai/models';\n\nexport const ADOBE = 'adobe';\nexport const ADOBE_PROXY = 'https://adobe-llm-proxy.paolo-moz.workers.dev';\n\nexport interface AdobeModelInfo {\n id: string;\n name: string;\n api?: 'anthropic' | 'openai';\n context_window?: number;\n max_tokens?: number;\n reasoning?: boolean;\n input?: string[];\n cost?: { input: number; output: number; cacheRead: number; cacheWrite: number };\n hidden?: boolean;\n}\n\nexport interface AdobeConfig {\n clientId: string;\n scopes: string;\n imsEnvironment: string;\n models: AdobeModelInfo[];\n}\n\nexport interface Budget {\n percent: number;\n window: 'weekly';\n resets: string;\n}\n\ntype Fetch = typeof fetch;\n\nconst free = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };\n\nexport function adobeModel(info: AdobeModelInfo, endpoint: string) {\n const openai = info.api === 'openai';\n return {\n id: info.id,\n name: info.name,\n provider: ADOBE,\n api: openai ? ('openai-completions' as const) : ('anthropic-messages' as const),\n baseUrl: openai ? `${endpoint}/v1` : endpoint,\n reasoning: info.reasoning ?? !openai,\n input: (info.input ?? ['text']).filter(\n (kind): kind is 'text' | 'image' => kind === 'text' || kind === 'image'\n ),\n cost: info.cost ?? free,\n contextWindow: info.context_window ?? 200000,\n maxTokens: info.max_tokens ?? 8192,\n ...(openai ? { compat: { supportsStore: false, supportsDeveloperRole: false } } : {}),\n };\n}\n\nexport async function adobeConfig(endpoint: string, fetcher: Fetch): Promise<AdobeConfig> {\n const response = await fetcher(`${endpoint}/v1/config`, {\n headers: { Accept: 'application/json' },\n });\n if (!response.ok) throw new Error(`the Adobe proxy answered /v1/config with ${response.status}`);\n return (await response.json()) as AdobeConfig;\n}\n\nexport async function adobeUsage(\n token: string,\n {\n endpoint = ADOBE_PROXY,\n fetch: fetcher = globalThis.fetch,\n }: { endpoint?: string; fetch?: Fetch } = {}\n): Promise<Budget | null> {\n const response = await fetcher(`${endpoint}/v1/usage`, {\n headers: { Accept: 'application/json', Authorization: `Bearer ${token}` },\n });\n if (!response.ok) return null;\n const weekly = (\n (await response.json()) as { usage?: { weekly?: { percent?: number; resetsAt?: string } } }\n ).usage?.weekly;\n if (typeof weekly?.percent !== 'number' || typeof weekly.resetsAt !== 'string') return null;\n return { percent: weekly.percent, window: 'weekly', resets: weekly.resetsAt };\n}\n\nexport function adobeProvider({\n endpoint = ADOBE_PROXY,\n session = crypto.randomUUID(),\n fetch: fetcher = (input, init) => globalThis.fetch(input, init),\n}: {\n endpoint?: string;\n session?: string;\n fetch?: Fetch;\n} = {}): Provider {\n return createProvider({\n id: ADOBE,\n name: 'Adobe',\n baseUrl: endpoint,\n headers: { 'X-Session-Id': session },\n auth: {\n apiKey: {\n name: 'Adobe IMS',\n resolve: async ({ credential, signal }) => {\n signal.throwIfAborted();\n if (!credential?.key) return undefined;\n return {\n auth: { headers: { Authorization: `Bearer ${credential.key}` } },\n source: 'Adobe IMS',\n };\n },\n },\n },\n models: [],\n fetchModels: async () =>\n (await adobeConfig(endpoint, fetcher)).models\n .filter((info) => !info.hidden)\n .map((info) => adobeModel(info, endpoint)),\n api: {\n 'anthropic-messages': anthropicMessagesApi(),\n 'openai-completions': openAICompletionsApi(),\n },\n }) as Provider;\n}\n"],
5
- "mappings": "AACA,SAAS,4BAA4B;AACrC,SAAS,4BAA4B;AACrC,SAAS,sBAAsB;AAExB,MAAM,QAAQ;AACd,MAAM,cAAc;AA6B3B,MAAM,OAAO,EAAE,OAAO,GAAG,QAAQ,GAAG,WAAW,GAAG,YAAY,EAAE;AAEzD,SAAS,WAAW,MAAsB,UAAkB;AACjE,QAAM,SAAS,KAAK,QAAQ;AAC5B,SAAO;AAAA,IACL,IAAI,KAAK;AAAA,IACT,MAAM,KAAK;AAAA,IACX,UAAU;AAAA,IACV,KAAK,SAAU,uBAAkC;AAAA,IACjD,SAAS,SAAS,GAAG,QAAQ,QAAQ;AAAA,IACrC,WAAW,KAAK,aAAa,CAAC;AAAA,IAC9B,QAAQ,KAAK,SAAS,CAAC,MAAM,GAAG;AAAA,MAC9B,CAAC,SAAmC,SAAS,UAAU,SAAS;AAAA,IAClE;AAAA,IACA,MAAM,KAAK,QAAQ;AAAA,IACnB,eAAe,KAAK,kBAAkB;AAAA,IACtC,WAAW,KAAK,cAAc;AAAA,IAC9B,GAAI,SAAS,EAAE,QAAQ,EAAE,eAAe,OAAO,uBAAuB,MAAM,EAAE,IAAI,CAAC;AAAA,EACrF;AACF;AAEA,eAAsB,YAAY,UAAkB,SAAsC;AACxF,QAAM,WAAW,MAAM,QAAQ,GAAG,QAAQ,cAAc;AAAA,IACtD,SAAS,EAAE,QAAQ,mBAAmB;AAAA,EACxC,CAAC;AACD,MAAI,CAAC,SAAS,GAAI,OAAM,IAAI,MAAM,4CAA4C,SAAS,MAAM,EAAE;AAC/F,SAAQ,MAAM,SAAS,KAAK;AAC9B;AAEA,eAAsB,WACpB,OACA;AAAA,EACE,WAAW;AAAA,EACX,OAAO,UAAU,WAAW;AAC9B,IAA0C,CAAC,GACnB;AACxB,QAAM,WAAW,MAAM,QAAQ,GAAG,QAAQ,aAAa;AAAA,IACrD,SAAS,EAAE,QAAQ,oBAAoB,eAAe,UAAU,KAAK,GAAG;AAAA,EAC1E,CAAC;AACD,MAAI,CAAC,SAAS,GAAI,QAAO;AACzB,QAAM,UACH,MAAM,SAAS,KAAK,GACrB,OAAO;AACT,MAAI,OAAO,QAAQ,YAAY,YAAY,OAAO,OAAO,aAAa,SAAU,QAAO;AACvF,SAAO,EAAE,SAAS,OAAO,SAAS,QAAQ,UAAU,QAAQ,OAAO,SAAS;AAC9E;AAEO,SAAS,cAAc;AAAA,EAC5B,WAAW;AAAA,EACX,UAAU,OAAO,WAAW;AAAA,EAC5B,OAAO,UAAU,CAAC,OAAO,SAAS,WAAW,MAAM,OAAO,IAAI;AAChE,IAII,CAAC,GAAa;AAChB,SAAO,eAAe;AAAA,IACpB,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,SAAS;AAAA,IACT,SAAS,EAAE,gBAAgB,QAAQ;AAAA,IACnC,MAAM;AAAA,MACJ,QAAQ;AAAA,QACN,MAAM;AAAA,QACN,SAAS,OAAO,EAAE,YAAY,OAAO,MAAM;AACzC,iBAAO,eAAe;AACtB,cAAI,CAAC,YAAY,IAAK,QAAO;AAC7B,iBAAO;AAAA,YACL,MAAM,EAAE,SAAS,EAAE,eAAe,UAAU,WAAW,GAAG,GAAG,EAAE;AAAA,YAC/D,QAAQ;AAAA,UACV;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,IACA,QAAQ,CAAC;AAAA,IACT,aAAa,aACV,MAAM,YAAY,UAAU,OAAO,GAAG,OACpC,OAAO,CAAC,SAAS,CAAC,KAAK,MAAM,EAC7B,IAAI,CAAC,SAAS,WAAW,MAAM,QAAQ,CAAC;AAAA,IAC7C,KAAK;AAAA,MACH,sBAAsB,qBAAqB;AAAA,MAC3C,sBAAsB,qBAAqB;AAAA,IAC7C;AAAA,EACF,CAAC;AACH;",
4
+ "sourcesContent": ["import type { ClassifierModel, Provider, ProviderClassifier } from '@earendil-works/pi-ai';\nimport { anthropicMessagesApi } from '@earendil-works/pi-ai/api/anthropic-messages.lazy';\nimport { cloudflareWorkersAISystemOneApi } from '@earendil-works/pi-ai/api/cloudflare-workers-ai-system-one.lazy';\nimport { openAICompletionsApi } from '@earendil-works/pi-ai/api/openai-completions.lazy';\nimport { createProvider } from '@earendil-works/pi-ai/models';\n\nexport const ADOBE = 'adobe';\nexport const ADOBE_PROXY = 'https://adobe-llm-proxy.paolo-moz.workers.dev';\n\nexport interface AdobeModelInfo {\n id: string;\n name: string;\n api?: 'anthropic' | 'openai';\n context_window?: number;\n max_tokens?: number;\n reasoning?: boolean;\n input?: string[];\n cost?: { input: number; output: number; cacheRead: number; cacheWrite: number };\n hidden?: boolean;\n}\n\nexport interface AdobeConfig {\n clientId: string;\n scopes: string;\n imsEnvironment: string;\n models: AdobeModelInfo[];\n}\n\nexport interface Budget {\n percent: number;\n window: 'weekly';\n resets: string;\n}\n\ntype Fetch = typeof fetch;\n\nconst free = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };\n\nexport const CLASSIFIER_API = 'cloudflare-workers-ai-system-one';\nconst WORKERS_AI = '@cf/cloudflare/';\n\nconst CLEF = [\n { id: 'clef', name: 'Clef', input: 0.24 },\n { id: 'clef-flash', name: 'Clef Flash', input: 0.09 },\n];\n\nexport function adobeClassifiers(endpoint: string): ClassifierModel<typeof CLASSIFIER_API>[] {\n return CLEF.map(({ id, name, input }) => ({\n type: 'classifier',\n id,\n name,\n provider: ADOBE,\n api: CLASSIFIER_API,\n baseUrl: `${endpoint}/v1/ai`,\n input: ['text'],\n cost: { ...free, input },\n contextWindow: 65536,\n }));\n}\n\nfunction bearer(headers: Record<string, string | null> = {}): string | undefined {\n const value = Object.entries(headers).find(\n ([name]) => name.toLowerCase() === 'authorization'\n )?.[1];\n return value?.replace(/^Bearer\\s+/i, '');\n}\n\nfunction clef(fetcher: Fetch): ProviderClassifier {\n const transport = cloudflareWorkersAISystemOneApi();\n return {\n classify: (model, context, options = {}) =>\n transport.classify(model, context, {\n ...options,\n fetch: options.fetch ?? fetcher,\n apiKey: bearer(options.headers) ?? options.apiKey,\n onPayload: async (payload, sent) => {\n const wire = { ...(payload as object), model: `${WORKERS_AI}${model.id}` };\n return (await options.onPayload?.(wire, sent)) ?? wire;\n },\n }),\n };\n}\n\nexport function adobeModel(info: AdobeModelInfo, endpoint: string) {\n const openai = info.api === 'openai';\n return {\n id: info.id,\n name: info.name,\n provider: ADOBE,\n api: openai ? ('openai-completions' as const) : ('anthropic-messages' as const),\n baseUrl: openai ? `${endpoint}/v1` : endpoint,\n reasoning: info.reasoning ?? !openai,\n input: (info.input ?? ['text']).filter(\n (kind): kind is 'text' | 'image' => kind === 'text' || kind === 'image'\n ),\n cost: info.cost ?? free,\n contextWindow: info.context_window ?? 200000,\n maxTokens: info.max_tokens ?? 8192,\n ...(openai ? { compat: { supportsStore: false, supportsDeveloperRole: false } } : {}),\n };\n}\n\nexport async function adobeConfig(endpoint: string, fetcher: Fetch): Promise<AdobeConfig> {\n const response = await fetcher(`${endpoint}/v1/config`, {\n headers: { Accept: 'application/json' },\n });\n if (!response.ok) throw new Error(`the Adobe proxy answered /v1/config with ${response.status}`);\n return (await response.json()) as AdobeConfig;\n}\n\nexport async function adobeUsage(\n token: string,\n {\n endpoint = ADOBE_PROXY,\n fetch: fetcher = globalThis.fetch,\n }: { endpoint?: string; fetch?: Fetch } = {}\n): Promise<Budget | null> {\n const response = await fetcher(`${endpoint}/v1/usage`, {\n headers: { Accept: 'application/json', Authorization: `Bearer ${token}` },\n });\n if (!response.ok) return null;\n const weekly = (\n (await response.json()) as { usage?: { weekly?: { percent?: number; resetsAt?: string } } }\n ).usage?.weekly;\n if (typeof weekly?.percent !== 'number' || typeof weekly.resetsAt !== 'string') return null;\n return { percent: weekly.percent, window: 'weekly', resets: weekly.resetsAt };\n}\n\nexport function adobeProvider({\n endpoint = ADOBE_PROXY,\n session = crypto.randomUUID(),\n fetch: fetcher = (input, init) => globalThis.fetch(input, init),\n}: {\n endpoint?: string;\n session?: string;\n fetch?: Fetch;\n} = {}): Provider {\n return createProvider({\n id: ADOBE,\n name: 'Adobe',\n baseUrl: endpoint,\n headers: { 'X-Session-Id': session },\n auth: {\n apiKey: {\n name: 'Adobe IMS',\n resolve: async ({ credential, signal }) => {\n signal.throwIfAborted();\n if (!credential?.key) return undefined;\n return {\n auth: { headers: { Authorization: `Bearer ${credential.key}` } },\n source: 'Adobe IMS',\n };\n },\n },\n },\n models: adobeClassifiers(endpoint),\n fetchModels: async () =>\n (await adobeConfig(endpoint, fetcher)).models\n .filter((info) => !info.hidden)\n .map((info) => adobeModel(info, endpoint)),\n api: {\n 'anthropic-messages': anthropicMessagesApi(),\n 'openai-completions': openAICompletionsApi(),\n },\n classifiers: { [CLASSIFIER_API]: clef(fetcher) },\n }) as Provider;\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
package/dist/client.js CHANGED
@@ -117,6 +117,13 @@ async function connectAgent(endpoint, options = {}) {
117
117
  settings: lastingSettings(settings, hold),
118
118
  remote,
119
119
  closed,
120
+ webhook(name, delivery) {
121
+ return control.webhook(
122
+ name,
123
+ { id: delivery.id ?? null, headers: delivery.headers ?? {}, body: delivery.body },
124
+ context
125
+ );
126
+ },
120
127
  async prompt(text, whenBusy = "followUp") {
121
128
  const sent = await control.send({ text, whenBusy, requestId: null }, context);
122
129
  if (!sent.accepted) throw new Error(`${sent.error.code}: ${sent.error.message}`);
@@ -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 type { ChangesView } from './changes/git.ts';\nimport type { FrozenCone } from './freezer/index.ts';\nimport type { MemoryEntry, MemoryScope } from './memory/format.ts';\nimport type { AgentRemote } from './remote/host.ts';\nimport {\n AGENT_SESSION,\n AgentControl,\n AgentRemoteService,\n AgentSessions,\n AgentSettings,\n type AgentsSummary,\n AgentTranscript,\n type Command,\n type Delivered,\n type MonitorFeed,\n type SendMode,\n} from './services.ts';\nimport type { Sprinkle } from './sprinkles/kind.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 deliveries: ReplicatedState<Record<string, Delivered>>;\n readonly agents?: ReplicatedState<AgentsSummary>;\n readonly views?: ReplicatedState<Record<string, ConversationView>>;\n readonly commands?: ReplicatedState<Command[]>;\n readonly sprinkles?: ReplicatedState<Sprinkle[]>;\n readonly memories?: ReplicatedState<MemoryEntry[]>;\n readonly memoryScopes?: ReplicatedState<MemoryScope[]>;\n readonly frozen?: ReplicatedState<FrozenCone[]>;\n readonly changes?: ReplicatedState<ChangesView>;\n readonly monitor?: ReplicatedState<MonitorFeed>;\n readonly settings: AgentSettings;\n readonly remote?: AgentRemote;\n readonly closed: Promise<Error | undefined>;\n prompt(text: string, whenBusy?: SendMode): Promise<string>;\n close(): Promise<void>;\n}\n\nexport interface Lasting<T> {\n readonly state: ReplicatedState<T>;\n freeze(): void;\n}\n\nexport function lasting<T>(state: ReplicatedState<T>): Lasting<T> {\n let last: T | undefined;\n let frozen = false;\n const read = () => {\n if (frozen) return last;\n try {\n last = state.value;\n } catch {}\n return last;\n };\n return {\n state: {\n get value() {\n return read();\n },\n subscribe: (listener) => (frozen ? () => undefined : state.subscribe(listener)),\n },\n freeze() {\n read();\n frozen = true;\n },\n };\n}\n\nfunction lastingSettings(\n settings: AgentSettings,\n hold: <T>(state: ReplicatedState<T>) => ReplicatedState<T>\n): AgentSettings {\n return {\n state: hold(settings.state),\n connect: (providerId, secret, region, context) =>\n settings.connect(providerId, secret, region, context),\n disconnect: (providerId, context) => settings.disconnect(providerId, context),\n signIn: (providerId, context) => settings.signIn(providerId, context),\n };\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, AgentRemoteService],\n transport: createClientServiceTransport(client, () => client.attachment),\n bound: true,\n });\n const control = session.use(AgentControl);\n const {\n state: transcript,\n deliveries,\n agents,\n views,\n commands,\n sprinkles,\n memories,\n memoryScopes,\n frozen,\n changes,\n monitor,\n } = session.use(AgentTranscript);\n const settings = session.use(AgentSettings);\n const remote = session.use(AgentRemoteService);\n await session.ready(context);\n const held: Lasting<unknown>[] = [];\n const hold = <T>(state: ReplicatedState<T>): ReplicatedState<T> => {\n const kept = lasting(state);\n held.push(kept as Lasting<unknown>);\n return kept.state;\n };\n const freeze = () => {\n for (const kept of held) kept.freeze();\n };\n const closed = channel.ended.then((reason) => {\n freeze();\n return reason;\n });\n return {\n serverId,\n control,\n transcript: hold(transcript),\n deliveries: hold(deliveries),\n agents: hold(agents),\n views: hold(views),\n commands: hold(commands),\n sprinkles: hold(sprinkles),\n memories: hold(memories),\n memoryScopes: hold(memoryScopes),\n frozen: hold(frozen),\n changes: hold(changes),\n monitor: hold(monitor),\n settings: lastingSettings(settings, hold),\n remote,\n closed,\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 freeze();\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": "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",
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 type { ChangesView } from './changes/git.ts';\nimport type { FrozenCone } from './freezer/index.ts';\nimport type { MemoryEntry, MemoryScope } from './memory/format.ts';\nimport type { AgentRemote } from './remote/host.ts';\nimport {\n AGENT_SESSION,\n AgentControl,\n AgentRemoteService,\n AgentSessions,\n AgentSettings,\n type AgentsSummary,\n AgentTranscript,\n type Command,\n type Delivered,\n type MonitorFeed,\n type SendMode,\n} from './services.ts';\nimport type { Sprinkle } from './sprinkles/kind.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 deliveries: ReplicatedState<Record<string, Delivered>>;\n readonly agents?: ReplicatedState<AgentsSummary>;\n readonly views?: ReplicatedState<Record<string, ConversationView>>;\n readonly commands?: ReplicatedState<Command[]>;\n readonly sprinkles?: ReplicatedState<Sprinkle[]>;\n readonly memories?: ReplicatedState<MemoryEntry[]>;\n readonly memoryScopes?: ReplicatedState<MemoryScope[]>;\n readonly frozen?: ReplicatedState<FrozenCone[]>;\n readonly changes?: ReplicatedState<ChangesView>;\n readonly monitor?: ReplicatedState<MonitorFeed>;\n readonly settings: AgentSettings;\n readonly remote?: AgentRemote;\n readonly closed: Promise<Error | undefined>;\n prompt(text: string, whenBusy?: SendMode): Promise<string>;\n webhook(\n name: string,\n delivery: { id?: string | null; headers?: Record<string, string>; body: string }\n ): Promise<{ delivered: boolean }>;\n close(): Promise<void>;\n}\n\nexport interface Lasting<T> {\n readonly state: ReplicatedState<T>;\n freeze(): void;\n}\n\nexport function lasting<T>(state: ReplicatedState<T>): Lasting<T> {\n let last: T | undefined;\n let frozen = false;\n const read = () => {\n if (frozen) return last;\n try {\n last = state.value;\n } catch {}\n return last;\n };\n return {\n state: {\n get value() {\n return read();\n },\n subscribe: (listener) => (frozen ? () => undefined : state.subscribe(listener)),\n },\n freeze() {\n read();\n frozen = true;\n },\n };\n}\n\nfunction lastingSettings(\n settings: AgentSettings,\n hold: <T>(state: ReplicatedState<T>) => ReplicatedState<T>\n): AgentSettings {\n return {\n state: hold(settings.state),\n connect: (providerId, secret, region, context) =>\n settings.connect(providerId, secret, region, context),\n disconnect: (providerId, context) => settings.disconnect(providerId, context),\n signIn: (providerId, context) => settings.signIn(providerId, context),\n };\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, AgentRemoteService],\n transport: createClientServiceTransport(client, () => client.attachment),\n bound: true,\n });\n const control = session.use(AgentControl);\n const {\n state: transcript,\n deliveries,\n agents,\n views,\n commands,\n sprinkles,\n memories,\n memoryScopes,\n frozen,\n changes,\n monitor,\n } = session.use(AgentTranscript);\n const settings = session.use(AgentSettings);\n const remote = session.use(AgentRemoteService);\n await session.ready(context);\n const held: Lasting<unknown>[] = [];\n const hold = <T>(state: ReplicatedState<T>): ReplicatedState<T> => {\n const kept = lasting(state);\n held.push(kept as Lasting<unknown>);\n return kept.state;\n };\n const freeze = () => {\n for (const kept of held) kept.freeze();\n };\n const closed = channel.ended.then((reason) => {\n freeze();\n return reason;\n });\n return {\n serverId,\n control,\n transcript: hold(transcript),\n deliveries: hold(deliveries),\n agents: hold(agents),\n views: hold(views),\n commands: hold(commands),\n sprinkles: hold(sprinkles),\n memories: hold(memories),\n memoryScopes: hold(memoryScopes),\n frozen: hold(frozen),\n changes: hold(changes),\n monitor: hold(monitor),\n settings: lastingSettings(settings, hold),\n remote,\n closed,\n webhook(name, delivery) {\n return control.webhook(\n name,\n { id: delivery.id ?? null, headers: delivery.headers ?? {}, body: delivery.body },\n context\n );\n },\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 freeze();\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": "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",
6
6
  "names": []
7
7
  }
package/dist/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  ADOBE,
3
3
  ADOBE_PROXY,
4
+ adobeClassifiers,
4
5
  adobeConfig,
5
6
  adobeModel,
6
7
  adobeProvider,
@@ -79,6 +80,7 @@ export {
79
80
  SliccPrompt,
80
81
  WasmSqliteDatabase,
81
82
  adminOver,
83
+ adobeClassifiers,
82
84
  adobeConfig,
83
85
  adobeModel,
84
86
  adobeProvider,
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 {\n ADOBE,\n ADOBE_PROXY,\n type AdobeConfig,\n type AdobeModelInfo,\n adobeConfig,\n adobeModel,\n adobeProvider,\n adobeUsage,\n type Budget,\n} from './adobe.ts';\nexport { type Agent, type AgentOptions, answerText, openAgent } from './agent.ts';\nexport { type AgentConnection, connectAgent } from './client.ts';\nexport { createAgentControl } from './control.ts';\nexport { CREDENTIALS_DATABASE, EncryptedCredentialStore } from './credentials.ts';\nexport { type AgentHost, hostAgent } from './host.ts';\nexport type {\n KernelClient,\n KernelFs,\n KernelProcess,\n KernelStat,\n SpawnOptions,\n} from './kernel/client.ts';\nexport { HOME, type KernelEnvOptions, kernelEnvironment, SliccKernelEnv } from './kernel/env.ts';\nexport {\n adminOver,\n type KernelAdmin,\n type KernelUser,\n type KernelUsers,\n serveAdmin,\n type UserClient,\n type UserClients,\n type UserConnect,\n type UserSpec,\n userClients,\n} from './kernel/users.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 KernelSource,\n type OwnerOptions,\n startAgent,\n} from './owner.ts';\nexport { applyPatches, patchServerAccept } from './patches.ts';\nexport { SliccPrompt, sliccPrompt } from './prompt.ts';\nexport {\n type AccountState,\n AGENT_SESSION,\n AgentControl,\n AgentSessions,\n AgentSettings,\n type AgentSettingsChange,\n AgentTranscript,\n type BudgetState,\n type ModelChoice,\n type OperationError,\n type PromptResult,\n type SendMode,\n type SendRequest,\n type SendResponse,\n type SettingsState,\n type SignIn,\n} from './services.ts';\nexport {\n BEDROCK,\n createAgentSettings,\n createSliccModels,\n DEFAULT_MODEL,\n DEFAULT_REGIONS,\n sliccProviders,\n withDefaultRegions,\n} from './settings.ts';\nexport {\n AGENT_DIRECTORY,\n type OpfsSqliteOptions,\n openMemorySqliteStorage,\n openOpfsSqliteStorage,\n WasmSqliteDatabase,\n} from './sqlite.ts';\nexport { type SystemFacts, systemSection } from './system.ts';\nexport { PortChannel, type PortEndpoint, withUnrefTimers } from './wire.ts';\nexport {\n type KernelPorts,\n kernelPort,\n kernelPorts,\n serveConnections,\n type WorkerScope,\n} from './worker.ts';\n"],
5
- "mappings": "AAAA;AAAA,EACE;AAAA,EACA;AAAA,EAGA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AACP,SAAwC,YAAY,iBAAiB;AACrE,SAA+B,oBAAoB;AACnD,SAAS,0BAA0B;AACnC,SAAS,sBAAsB,gCAAgC;AAC/D,SAAyB,iBAAiB;AAQ1C,SAAS,MAA6B,mBAAmB,sBAAsB;AAC/E;AAAA,EACE;AAAA,EAIA;AAAA,EAKA;AAAA,OACK;AACP,SAAS,oBAAoB;AAC7B;AAAA,EAIE;AAAA,OACK;AACP,SAAiD,sBAAsB;AACvE;AAAA,EACE;AAAA,EAKA;AAAA,OACK;AACP,SAAS,cAAc,yBAAyB;AAChD,SAAS,aAAa,mBAAmB;AACzC;AAAA,EAEE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAEA;AAAA,OAUK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP;AAAA,EACE;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAA2B,qBAAqB;AAChD,SAAS,aAAgC,uBAAuB;AAChE;AAAA,EAEE;AAAA,EACA;AAAA,EACA;AAAA,OAEK;",
4
+ "sourcesContent": ["export {\n ADOBE,\n ADOBE_PROXY,\n type AdobeConfig,\n type AdobeModelInfo,\n adobeClassifiers,\n adobeConfig,\n adobeModel,\n adobeProvider,\n adobeUsage,\n type Budget,\n} from './adobe.ts';\nexport { type Agent, type AgentOptions, answerText, openAgent } from './agent.ts';\nexport { type AgentConnection, connectAgent } from './client.ts';\nexport { createAgentControl } from './control.ts';\nexport { CREDENTIALS_DATABASE, EncryptedCredentialStore } from './credentials.ts';\nexport { type AgentHost, hostAgent } from './host.ts';\nexport type {\n KernelClient,\n KernelFs,\n KernelProcess,\n KernelStat,\n SpawnOptions,\n} from './kernel/client.ts';\nexport { HOME, type KernelEnvOptions, kernelEnvironment, SliccKernelEnv } from './kernel/env.ts';\nexport {\n adminOver,\n type KernelAdmin,\n type KernelUser,\n type KernelUsers,\n serveAdmin,\n type UserClient,\n type UserClients,\n type UserConnect,\n type UserSpec,\n userClients,\n} from './kernel/users.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 KernelSource,\n type OwnerOptions,\n startAgent,\n} from './owner.ts';\nexport { applyPatches, patchServerAccept } from './patches.ts';\nexport { SliccPrompt, sliccPrompt } from './prompt.ts';\nexport {\n type AccountState,\n AGENT_SESSION,\n AgentControl,\n AgentSessions,\n AgentSettings,\n type AgentSettingsChange,\n AgentTranscript,\n type BudgetState,\n type ModelChoice,\n type OperationError,\n type PromptResult,\n type SendMode,\n type SendRequest,\n type SendResponse,\n type SettingsState,\n type SignIn,\n} from './services.ts';\nexport {\n BEDROCK,\n createAgentSettings,\n createSliccModels,\n DEFAULT_MODEL,\n DEFAULT_REGIONS,\n sliccProviders,\n withDefaultRegions,\n} from './settings.ts';\nexport {\n AGENT_DIRECTORY,\n type OpfsSqliteOptions,\n openMemorySqliteStorage,\n openOpfsSqliteStorage,\n WasmSqliteDatabase,\n} from './sqlite.ts';\nexport { type SystemFacts, systemSection } from './system.ts';\nexport { PortChannel, type PortEndpoint, withUnrefTimers } from './wire.ts';\nexport {\n type KernelPorts,\n kernelPort,\n kernelPorts,\n serveConnections,\n type WorkerScope,\n} from './worker.ts';\n"],
5
+ "mappings": "AAAA;AAAA,EACE;AAAA,EACA;AAAA,EAGA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AACP,SAAwC,YAAY,iBAAiB;AACrE,SAA+B,oBAAoB;AACnD,SAAS,0BAA0B;AACnC,SAAS,sBAAsB,gCAAgC;AAC/D,SAAyB,iBAAiB;AAQ1C,SAAS,MAA6B,mBAAmB,sBAAsB;AAC/E;AAAA,EACE;AAAA,EAIA;AAAA,EAKA;AAAA,OACK;AACP,SAAS,oBAAoB;AAC7B;AAAA,EAIE;AAAA,OACK;AACP,SAAiD,sBAAsB;AACvE;AAAA,EACE;AAAA,EAKA;AAAA,OACK;AACP,SAAS,cAAc,yBAAyB;AAChD,SAAS,aAAa,mBAAmB;AACzC;AAAA,EAEE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAEA;AAAA,OAUK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP;AAAA,EACE;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAA2B,qBAAqB;AAChD,SAAS,aAAgC,uBAAuB;AAChE;AAAA,EAEE;AAAA,EACA;AAAA,EACA;AAAA,OAEK;",
6
6
  "names": []
7
7
  }
@@ -1,4 +1,4 @@
1
- import type { Provider } from '@earendil-works/pi-ai';
1
+ import type { ClassifierModel, Provider } from '@earendil-works/pi-ai';
2
2
  export declare const ADOBE = "adobe";
3
3
  export declare const ADOBE_PROXY = "https://adobe-llm-proxy.paolo-moz.workers.dev";
4
4
  export interface AdobeModelInfo {
@@ -29,6 +29,8 @@ export interface Budget {
29
29
  resets: string;
30
30
  }
31
31
  type Fetch = typeof fetch;
32
+ export declare const CLASSIFIER_API = "cloudflare-workers-ai-system-one";
33
+ export declare function adobeClassifiers(endpoint: string): ClassifierModel<typeof CLASSIFIER_API>[];
32
34
  export declare function adobeModel(info: AdobeModelInfo, endpoint: string): {
33
35
  id: string;
34
36
  name: string;
@@ -25,6 +25,13 @@ export interface AgentConnection {
25
25
  readonly remote?: AgentRemote;
26
26
  readonly closed: Promise<Error | undefined>;
27
27
  prompt(text: string, whenBusy?: SendMode): Promise<string>;
28
+ webhook(name: string, delivery: {
29
+ id?: string | null;
30
+ headers?: Record<string, string>;
31
+ body: string;
32
+ }): Promise<{
33
+ delivered: boolean;
34
+ }>;
28
35
  close(): Promise<void>;
29
36
  }
30
37
  export interface Lasting<T> {
@@ -1,4 +1,4 @@
1
- export { ADOBE, ADOBE_PROXY, type AdobeConfig, type AdobeModelInfo, adobeConfig, adobeModel, adobeProvider, adobeUsage, type Budget, } from './adobe.ts';
1
+ export { ADOBE, ADOBE_PROXY, type AdobeConfig, type AdobeModelInfo, adobeClassifiers, adobeConfig, adobeModel, adobeProvider, adobeUsage, type Budget, } from './adobe.ts';
2
2
  export { type Agent, type AgentOptions, answerText, openAgent } from './agent.ts';
3
3
  export { type AgentConnection, connectAgent } from './client.ts';
4
4
  export { createAgentControl } from './control.ts';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-ecoverse/slicc-agent",
3
- "version": "3.37.1",
3
+ "version": "3.39.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",
@@ -63,7 +63,7 @@
63
63
  "devDependencies": {
64
64
  "@ai-ecoverse/slicc-kernel": "1.47.1",
65
65
  "@ai-ecoverse/slicc-shared-web": "1.12.3",
66
- "@ai-ecoverse/slicc-spectrum": "1.58.0",
66
+ "@ai-ecoverse/slicc-spectrum": "1.58.2",
67
67
  "@ai-ecoverse/wasm-bash": "5.3.0-17",
68
68
  "@ai-ecoverse/wasm-coreutils": "9.12.0-5",
69
69
  "@ai-ecoverse/wasm-git": "2.55.0-15",