@ai-ecoverse/slicc-agent 3.43.1 → 3.44.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 (61) hide show
  1. package/README.md +12 -2
  2. package/dist/agent.js +1 -0
  3. package/dist/agent.js.map +2 -2
  4. package/dist/client.js +3 -1
  5. package/dist/client.js.map +2 -2
  6. package/dist/codemode/index.js +2 -1
  7. package/dist/codemode/index.js.map +2 -2
  8. package/dist/control.js +13 -3
  9. package/dist/control.js.map +2 -2
  10. package/dist/freezer/index.js +5 -4
  11. package/dist/freezer/index.js.map +2 -2
  12. package/dist/host.js +13 -2
  13. package/dist/host.js.map +2 -2
  14. package/dist/kernel/env.js +55 -4
  15. package/dist/kernel/env.js.map +2 -2
  16. package/dist/kernel/exec.js +84 -16
  17. package/dist/kernel/exec.js.map +3 -3
  18. package/dist/licks/licks.js +17 -1
  19. package/dist/licks/licks.js.map +2 -2
  20. package/dist/main.js +29 -10
  21. package/dist/main.js.map +2 -2
  22. package/dist/mcp/content.js +3 -1
  23. package/dist/mcp/content.js.map +2 -2
  24. package/dist/mcp/tools.js +2 -1
  25. package/dist/mcp/tools.js.map +2 -2
  26. package/dist/memory/prompt.js +3 -2
  27. package/dist/memory/prompt.js.map +2 -2
  28. package/dist/memory/store.js +5 -3
  29. package/dist/memory/store.js.map +2 -2
  30. package/dist/remote/host.js +21 -1
  31. package/dist/remote/host.js.map +2 -2
  32. package/dist/secrets/extension.js +150 -0
  33. package/dist/secrets/extension.js.map +7 -0
  34. package/dist/secrets/names.js +72 -0
  35. package/dist/secrets/names.js.map +7 -0
  36. package/dist/secrets/scrub.js +36 -0
  37. package/dist/secrets/scrub.js.map +7 -0
  38. package/dist/secrets/vault.js +161 -0
  39. package/dist/secrets/vault.js.map +7 -0
  40. package/dist/services.js.map +2 -2
  41. package/dist/skills/index.js +8 -1
  42. package/dist/skills/index.js.map +2 -2
  43. package/dist/spectrum/agent-port.js +6 -2
  44. package/dist/spectrum/agent-port.js.map +2 -2
  45. package/dist/types/agent.d.ts +1 -0
  46. package/dist/types/client.d.ts +2 -0
  47. package/dist/types/control.d.ts +2 -1
  48. package/dist/types/host.d.ts +9 -1
  49. package/dist/types/kernel/env.d.ts +6 -0
  50. package/dist/types/kernel/exec.d.ts +8 -1
  51. package/dist/types/licks/licks.d.ts +1 -0
  52. package/dist/types/mcp/content.d.ts +1 -1
  53. package/dist/types/remote/host.d.ts +5 -1
  54. package/dist/types/secrets/extension.d.ts +31 -0
  55. package/dist/types/secrets/names.d.ts +24 -0
  56. package/dist/types/secrets/scrub.d.ts +21 -0
  57. package/dist/types/secrets/vault.d.ts +30 -0
  58. package/dist/types/services.d.ts +3 -1
  59. package/dist/types/skills/index.d.ts +1 -0
  60. package/dist/types/spectrum/agent-port.d.ts +2 -0
  61. package/package.json +3 -3
package/README.md CHANGED
@@ -113,7 +113,7 @@ const owner = await startAgent({
113
113
 
114
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
115
 
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.
116
+ **Model 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.
117
117
 
118
118
  **Settings.** The `slicc.agent.settings` service shows the models and accounts and takes `connect(providerId, apiKey)` and `disconnect(providerId)`.
119
119
 
@@ -537,9 +537,19 @@ It prints the tab's stdout and stderr on their own streams and exits with its co
537
537
  - **What leaves the worker:** tool summaries of at most 200 characters (the tool's name and main argument), result summaries (a line count, or an error's first line), secrets redacted; never tool output.
538
538
  - **Bounds:** a stream nobody polls for two minutes is dropped, and one more than 10 000 events behind ends with `{ t: 'end', reason: 'error' }`.
539
539
 
540
+ ### Credentials
541
+
542
+ The agent never holds a secret's value. Values live in the vault (`vault.sliccy.ai`); the agent sees names and placeholders (`fnox_proxy_…`), and every text that could reach the model is scrubbed through the vault first. The design is secrets rev 4 (§3.15–§3.18), and this part is AGENT-S1.
543
+
544
+ - **The port.** bios posts `{ kernel, admin, vault, scrub }` to the worker, where `vault` is a `MessagePort` to the vault frame (role `agent`) and `scrub` the last-known `{ needed, version }`, or `null` when no vault ever connected. On a vault reload it posts `{ vault, scrub }` again, and the worker resends its unanswered ops. Without a port, or with `needed: false`, nothing is sent and every scrub is the identity. A `version` newer than the last pair read counts as `needed` until the new pair arrives.
545
+ - **The wire.** Requests are `{ id, op, ... }` and answers `{ id, ok }` or `{ id, error }`, in request order: `redact { texts }` (strings and `Uint8Array`s, answered in the same order and types, with `version`), and the stream ops `redactStream`, `push { chunk }`, `end` and `drop`, each with the worker's `stream` id. The vault may push `{ scrub }` and `{ locked }` at any time.
546
+ - **`slicc-secrets`**, a built-in extension modelled on [pi-fnox](https://github.com/Bucurenciu-Cristian/pi-fnox) (MIT, © 2026 Kicky), with its hooks mapped to pi-durable: `secret list --json` in the home env at start and whenever `version` changes (pi-fnox's `fnox export`; nothing goes into the worker's environment); an `afterTool` hook scrubbing every result's text, diagnostics and string `details` (pi-fnox's `tool_result`); a `secrets` system section with the names, placeholders, where each works and how to use them (`before_agent_start`); and `/secrets`, answered locally as a `slicc.secrets` entry (`/fnox-list`; reloading is automatic). When at least one secret is `shell = true`, every conversation command runs as `fnox exec --shell-grants -- <argv>` (pi-fnox's `spawnHook`). slicc-agent doesn't depend on `@kickythrust/pi-fnox`. Every conversation keeps the extension: new ones are pinned at creation, and conversations stored with an extension list that lacks it get it back at start.
547
+ - **Where text is scrubbed before anything keeps or cuts it:** command output, per stream, before the bash tool's tail window, the spill file and the live slot; `read`'s bytes (images aren't, and files over 8 MiB stream in 1 MiB chunks); MCP results before their middle cut and progress text; codemode output before its cut; user and remote sends after skill expansion; every lick (sprinkle sends and scoop results included) before triage and the outbox; and memory writes, before the pattern redaction. Remote-control summaries are built from stored entries only.
548
+ - **The hold.** A vault that doesn't answer within 2 s reads as `waiting`. Nothing unscrubbed is appended: tool results, sends and licks wait in memory, model requests wait before they start, and command output held past 32 MiB kills the command with "output held: waiting for the vault". The state is the transcript's `vault` field (`{ port, needed, version, locked, held }`), and remote `watch` streams get a `notice` "waiting for the vault" and one when it answers again.
549
+
540
550
  ## The kernel
541
551
 
542
- `@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.
552
+ `@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.64.2; 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.
543
553
 
544
554
  ## Patched dependencies
545
555
 
package/dist/agent.js CHANGED
@@ -33,6 +33,7 @@ async function openAgent(options) {
33
33
  );
34
34
  const root = await harness.root(context, { agent: { model: options.model } });
35
35
  const agents = await openAgents(harness, root, context);
36
+ await options.beforeResume?.(harness, context);
36
37
  harness.resume();
37
38
  return {
38
39
  harness,
package/dist/agent.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/agent.ts"],
4
- "sourcesContent": ["import type { Context } from '@earendil-works/chord';\nimport { BACKGROUND_CONTEXT } from '@earendil-works/chord/context';\nimport type { Models } from '@earendil-works/pi-ai/models';\nimport {\n AssistantEntry,\n type Conversation,\n createRegistry,\n type EntryId,\n Harness,\n type HarnessOptions,\n MemoryStorage,\n type ModelRef,\n type Registry,\n type Storage,\n} from '@earendil-works/pi-durable';\nimport { type Agents, openAgents } from './agents.ts';\nimport type { Cones } from './cone.ts';\n\nexport interface AgentOptions {\n models: Models;\n model: ModelRef;\n storage?: Storage;\n registry?: Registry;\n settings?: HarnessOptions['settings'];\n env?: HarnessOptions['env'];\n context?: Context;\n}\n\nexport interface Agent extends Cones {\n readonly harness: Harness;\n readonly root: Conversation;\n readonly agents: Agents;\n onCone(listener: (conversation: Conversation) => void | Promise<void>): () => void;\n prompt(text: string): Promise<string>;\n close(): Promise<void>;\n}\n\ninterface Block {\n type: string;\n text?: string;\n}\n\nexport function answerText(content: unknown): string {\n if (typeof content === 'string') return content;\n if (!Array.isArray(content)) return '';\n return (content as Block[])\n .filter((block) => block.type === 'text')\n .map((block) => block.text ?? '')\n .join('');\n}\n\nasync function prompt(root: Conversation, text: string, context: Context): Promise<string> {\n const submission = await root.submit({ type: 'input', content: text }, context);\n const settled = await submission.wait(context);\n const { answer, reason } = settled as { answer?: EntryId; reason?: string };\n if (answer === undefined) throw new Error(`unanswered: ${reason}`);\n const entry = await root.commit((tx) => tx.entry(AssistantEntry, answer), context);\n return answerText(entry?.model?.[0]?.content);\n}\n\nexport async function openAgent(options: AgentOptions): Promise<Agent> {\n const context = options.context ?? BACKGROUND_CONTEXT;\n const harness = await Harness.open(\n options.storage ?? new MemoryStorage(),\n {\n models: options.models,\n registry: options.registry ?? createRegistry(),\n ...(options.settings ? { settings: options.settings } : {}),\n ...(options.env ? { env: options.env } : {}),\n },\n context\n );\n const root = await harness.root(context, { agent: { model: options.model } });\n const agents = await openAgents(harness, root, context);\n harness.resume();\n return {\n harness,\n root,\n agents,\n cone: () => agents.cone(),\n switchCone: (conversation, switching) => agents.switchCone(conversation, switching),\n onCone: (listener) => agents.onCone(listener),\n prompt: (text) => prompt(agents.cone(), text, context),\n close: () => harness.close(context),\n };\n}\n"],
5
- "mappings": "AACA,SAAS,0BAA0B;AAEnC;AAAA,EACE;AAAA,EAEA;AAAA,EAEA;AAAA,EAEA;AAAA,OAIK;AACP,SAAsB,kBAAkB;AA2BjC,SAAS,WAAW,SAA0B;AACnD,MAAI,OAAO,YAAY,SAAU,QAAO;AACxC,MAAI,CAAC,MAAM,QAAQ,OAAO,EAAG,QAAO;AACpC,SAAQ,QACL,OAAO,CAAC,UAAU,MAAM,SAAS,MAAM,EACvC,IAAI,CAAC,UAAU,MAAM,QAAQ,EAAE,EAC/B,KAAK,EAAE;AACZ;AAEA,eAAe,OAAO,MAAoB,MAAc,SAAmC;AACzF,QAAM,aAAa,MAAM,KAAK,OAAO,EAAE,MAAM,SAAS,SAAS,KAAK,GAAG,OAAO;AAC9E,QAAM,UAAU,MAAM,WAAW,KAAK,OAAO;AAC7C,QAAM,EAAE,QAAQ,OAAO,IAAI;AAC3B,MAAI,WAAW,OAAW,OAAM,IAAI,MAAM,eAAe,MAAM,EAAE;AACjE,QAAM,QAAQ,MAAM,KAAK,OAAO,CAAC,OAAO,GAAG,MAAM,gBAAgB,MAAM,GAAG,OAAO;AACjF,SAAO,WAAW,OAAO,QAAQ,CAAC,GAAG,OAAO;AAC9C;AAEA,eAAsB,UAAU,SAAuC;AACrE,QAAM,UAAU,QAAQ,WAAW;AACnC,QAAM,UAAU,MAAM,QAAQ;AAAA,IAC5B,QAAQ,WAAW,IAAI,cAAc;AAAA,IACrC;AAAA,MACE,QAAQ,QAAQ;AAAA,MAChB,UAAU,QAAQ,YAAY,eAAe;AAAA,MAC7C,GAAI,QAAQ,WAAW,EAAE,UAAU,QAAQ,SAAS,IAAI,CAAC;AAAA,MACzD,GAAI,QAAQ,MAAM,EAAE,KAAK,QAAQ,IAAI,IAAI,CAAC;AAAA,IAC5C;AAAA,IACA;AAAA,EACF;AACA,QAAM,OAAO,MAAM,QAAQ,KAAK,SAAS,EAAE,OAAO,EAAE,OAAO,QAAQ,MAAM,EAAE,CAAC;AAC5E,QAAM,SAAS,MAAM,WAAW,SAAS,MAAM,OAAO;AACtD,UAAQ,OAAO;AACf,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA,MAAM,MAAM,OAAO,KAAK;AAAA,IACxB,YAAY,CAAC,cAAc,cAAc,OAAO,WAAW,cAAc,SAAS;AAAA,IAClF,QAAQ,CAAC,aAAa,OAAO,OAAO,QAAQ;AAAA,IAC5C,QAAQ,CAAC,SAAS,OAAO,OAAO,KAAK,GAAG,MAAM,OAAO;AAAA,IACrD,OAAO,MAAM,QAAQ,MAAM,OAAO;AAAA,EACpC;AACF;",
4
+ "sourcesContent": ["import type { Context } from '@earendil-works/chord';\nimport { BACKGROUND_CONTEXT } from '@earendil-works/chord/context';\nimport type { Models } from '@earendil-works/pi-ai/models';\nimport {\n AssistantEntry,\n type Conversation,\n createRegistry,\n type EntryId,\n Harness,\n type HarnessOptions,\n MemoryStorage,\n type ModelRef,\n type Registry,\n type Storage,\n} from '@earendil-works/pi-durable';\nimport { type Agents, openAgents } from './agents.ts';\nimport type { Cones } from './cone.ts';\n\nexport interface AgentOptions {\n models: Models;\n model: ModelRef;\n storage?: Storage;\n registry?: Registry;\n settings?: HarnessOptions['settings'];\n env?: HarnessOptions['env'];\n context?: Context;\n beforeResume?: (harness: Harness, context: Context) => Promise<unknown>;\n}\n\nexport interface Agent extends Cones {\n readonly harness: Harness;\n readonly root: Conversation;\n readonly agents: Agents;\n onCone(listener: (conversation: Conversation) => void | Promise<void>): () => void;\n prompt(text: string): Promise<string>;\n close(): Promise<void>;\n}\n\ninterface Block {\n type: string;\n text?: string;\n}\n\nexport function answerText(content: unknown): string {\n if (typeof content === 'string') return content;\n if (!Array.isArray(content)) return '';\n return (content as Block[])\n .filter((block) => block.type === 'text')\n .map((block) => block.text ?? '')\n .join('');\n}\n\nasync function prompt(root: Conversation, text: string, context: Context): Promise<string> {\n const submission = await root.submit({ type: 'input', content: text }, context);\n const settled = await submission.wait(context);\n const { answer, reason } = settled as { answer?: EntryId; reason?: string };\n if (answer === undefined) throw new Error(`unanswered: ${reason}`);\n const entry = await root.commit((tx) => tx.entry(AssistantEntry, answer), context);\n return answerText(entry?.model?.[0]?.content);\n}\n\nexport async function openAgent(options: AgentOptions): Promise<Agent> {\n const context = options.context ?? BACKGROUND_CONTEXT;\n const harness = await Harness.open(\n options.storage ?? new MemoryStorage(),\n {\n models: options.models,\n registry: options.registry ?? createRegistry(),\n ...(options.settings ? { settings: options.settings } : {}),\n ...(options.env ? { env: options.env } : {}),\n },\n context\n );\n const root = await harness.root(context, { agent: { model: options.model } });\n const agents = await openAgents(harness, root, context);\n await options.beforeResume?.(harness, context);\n harness.resume();\n return {\n harness,\n root,\n agents,\n cone: () => agents.cone(),\n switchCone: (conversation, switching) => agents.switchCone(conversation, switching),\n onCone: (listener) => agents.onCone(listener),\n prompt: (text) => prompt(agents.cone(), text, context),\n close: () => harness.close(context),\n };\n}\n"],
5
+ "mappings": "AACA,SAAS,0BAA0B;AAEnC;AAAA,EACE;AAAA,EAEA;AAAA,EAEA;AAAA,EAEA;AAAA,OAIK;AACP,SAAsB,kBAAkB;AA4BjC,SAAS,WAAW,SAA0B;AACnD,MAAI,OAAO,YAAY,SAAU,QAAO;AACxC,MAAI,CAAC,MAAM,QAAQ,OAAO,EAAG,QAAO;AACpC,SAAQ,QACL,OAAO,CAAC,UAAU,MAAM,SAAS,MAAM,EACvC,IAAI,CAAC,UAAU,MAAM,QAAQ,EAAE,EAC/B,KAAK,EAAE;AACZ;AAEA,eAAe,OAAO,MAAoB,MAAc,SAAmC;AACzF,QAAM,aAAa,MAAM,KAAK,OAAO,EAAE,MAAM,SAAS,SAAS,KAAK,GAAG,OAAO;AAC9E,QAAM,UAAU,MAAM,WAAW,KAAK,OAAO;AAC7C,QAAM,EAAE,QAAQ,OAAO,IAAI;AAC3B,MAAI,WAAW,OAAW,OAAM,IAAI,MAAM,eAAe,MAAM,EAAE;AACjE,QAAM,QAAQ,MAAM,KAAK,OAAO,CAAC,OAAO,GAAG,MAAM,gBAAgB,MAAM,GAAG,OAAO;AACjF,SAAO,WAAW,OAAO,QAAQ,CAAC,GAAG,OAAO;AAC9C;AAEA,eAAsB,UAAU,SAAuC;AACrE,QAAM,UAAU,QAAQ,WAAW;AACnC,QAAM,UAAU,MAAM,QAAQ;AAAA,IAC5B,QAAQ,WAAW,IAAI,cAAc;AAAA,IACrC;AAAA,MACE,QAAQ,QAAQ;AAAA,MAChB,UAAU,QAAQ,YAAY,eAAe;AAAA,MAC7C,GAAI,QAAQ,WAAW,EAAE,UAAU,QAAQ,SAAS,IAAI,CAAC;AAAA,MACzD,GAAI,QAAQ,MAAM,EAAE,KAAK,QAAQ,IAAI,IAAI,CAAC;AAAA,IAC5C;AAAA,IACA;AAAA,EACF;AACA,QAAM,OAAO,MAAM,QAAQ,KAAK,SAAS,EAAE,OAAO,EAAE,OAAO,QAAQ,MAAM,EAAE,CAAC;AAC5E,QAAM,SAAS,MAAM,WAAW,SAAS,MAAM,OAAO;AACtD,QAAM,QAAQ,eAAe,SAAS,OAAO;AAC7C,UAAQ,OAAO;AACf,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA,MAAM,MAAM,OAAO,KAAK;AAAA,IACxB,YAAY,CAAC,cAAc,cAAc,OAAO,WAAW,cAAc,SAAS;AAAA,IAClF,QAAQ,CAAC,aAAa,OAAO,OAAO,QAAQ;AAAA,IAC5C,QAAQ,CAAC,SAAS,OAAO,OAAO,KAAK,GAAG,MAAM,OAAO;AAAA,IACrD,OAAO,MAAM,QAAQ,MAAM,OAAO;AAAA,EACpC;AACF;",
6
6
  "names": []
7
7
  }
package/dist/client.js CHANGED
@@ -83,7 +83,8 @@ async function connectAgent(endpoint, options = {}) {
83
83
  memoryScopes,
84
84
  frozen,
85
85
  changes,
86
- monitor
86
+ monitor,
87
+ vault
87
88
  } = session.use(AgentTranscript);
88
89
  const settings = session.use(AgentSettings);
89
90
  const remote = session.use(AgentRemoteService);
@@ -116,6 +117,7 @@ async function connectAgent(endpoint, options = {}) {
116
117
  frozen: hold(frozen),
117
118
  changes: hold(changes),
118
119
  monitor: hold(monitor),
120
+ vault: hold(vault),
119
121
  settings: lastingSettings(settings, hold),
120
122
  remote,
121
123
  pages,
@@ -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 type { AgentPages } from './remote/pages.ts';\nimport {\n AGENT_SESSION,\n AgentControl,\n AgentPagesService,\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 pages?: AgentPages;\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, AgentPagesService],\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 const pages = session.use(AgentPagesService);\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 pages,\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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",
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 type { AgentPages } from './remote/pages.ts';\nimport type { VaultState } from './secrets/vault.ts';\nimport {\n AGENT_SESSION,\n AgentControl,\n AgentPagesService,\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 vault?: ReplicatedState<VaultState>;\n readonly settings: AgentSettings;\n readonly remote?: AgentRemote;\n readonly pages?: AgentPages;\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, AgentPagesService],\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 vault,\n } = session.use(AgentTranscript);\n const settings = session.use(AgentSettings);\n const remote = session.use(AgentRemoteService);\n const pages = session.use(AgentPagesService);\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 vault: hold(vault),\n settings: lastingSettings(settings, hold),\n remote,\n pages,\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
  }
@@ -12,6 +12,7 @@ import {
12
12
  defineExtension,
13
13
  defineTool
14
14
  } from "@earendil-works/pi-durable";
15
+ import { scrubItems } from "../secrets/scrub.js";
15
16
  const CODEMODE = "codemode";
16
17
  const DEFAULT_MAX_OUTPUT_TOKENS = 1e4;
17
18
  const MEMORY_LIMIT_BYTES = 256 * 1024 * 1024;
@@ -217,7 +218,7 @@ function codemodeTool(options) {
217
218
  ${formatError(result.error, result.calls)}`
218
219
  });
219
220
  const cut = truncate(
220
- joinText(items),
221
+ await scrubItems(joinText(items)),
221
222
  parsed.options.maxOutputTokens ?? DEFAULT_MAX_OUTPUT_TOKENS
222
223
  );
223
224
  const path = cut.full === null ? "" : await spill(api, cut.full, context);
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/codemode/index.ts"],
4
- "sourcesContent": ["import type { Context, JsonValue } from '@earendil-works/chord';\nimport { withAbortSignal } from '@earendil-works/chord/context';\nimport { Type } from '@earendil-works/pi-ai';\nimport { validateToolArguments } from '@earendil-works/pi-ai/utils/validation';\nimport {\n type CodemodeError,\n type CodemodeJsonSchema,\n type CodemodeOutputItem,\n type CodemodeResult,\n CodemodeSandbox,\n type CodemodeSandboxOptions,\n type CodemodeTool,\n loadQuickJSWasm,\n parseCodemodeSource,\n renderDeclarations,\n} from '@earendil-works/pi-codemode';\nimport {\n type Agent,\n defineDoc,\n defineExtension,\n defineTool,\n type Extension,\n type ToolExecutionApi,\n type ToolRegistration,\n} from '@earendil-works/pi-durable';\n\nexport const CODEMODE = 'codemode';\nexport const DEFAULT_MAX_OUTPUT_TOKENS = 10_000;\nexport const MEMORY_LIMIT_BYTES = 256 * 1024 * 1024;\nconst CHARS_PER_TOKEN = 4;\n\nexport const CodemodeDoc = defineDoc<{ store: Record<string, JsonValue> }>({\n kind: 'slicc.codemode',\n version: 1,\n scope: 'conversation',\n history: 'rewindable',\n fork: 'asOf',\n initial: () => ({ store: {} }),\n});\n\nexport interface Sandbox {\n execute(\n code: string,\n options: { signal?: AbortSignal; store?: Record<string, unknown> }\n ): Promise<CodemodeResult>;\n close(): Promise<void>;\n}\n\nexport type SandboxFactory = (options: CodemodeSandboxOptions) => Sandbox;\n\nexport interface CodemodeExtra {\n tools: CodemodeTool[];\n globals: CodemodeTool[];\n}\n\nexport interface CodemodeOptions {\n sandbox: SandboxFactory;\n declared: readonly ToolRegistration[];\n extra?: (api: ToolExecutionApi, agent: Agent, context: Context) => Promise<CodemodeExtra>;\n}\n\nconst INTRO = `Run JavaScript that calls other tools. The input is raw JavaScript (not JSON, no code fence), run as an async function body in a QuickJS sandbox: top-level \\`await\\` and \\`return\\` work. No Node, file system, network, or timers.\n- \\`await tools.<name>({ ...args })\\` resolves to a string, or an object if the tool's declaration says so, and rejects with an Error on failure. Calls still running when the script ends are cancelled.\n- Optional first line: \\`// @options: {\"max_output_tokens\": 10000, \"timeout_ms\": 60000}\\``;\n\nconst GLOBALS = [\n 'Globals:',\n '- `text(value)`, `image(dataUrlOrImageBlock)`, `console.log(...)`, and top-level `return` add output; `exit()` ends the script. With several text items, each starts with a `==> text N/M <==` line, and `console` lines follow the other output in one `<console_output>` block.',\n '- `store(key, value)` and `load(key)` keep JSON values across codemode calls in this conversation.',\n '- `ALL_TOOLS` lists every tool scripts can call.',\n].join('\\n');\n\nconst DISCOVERY =\n '- `await searchTools(query, { limit?, namespace? })`, `await describeTool(name)`, `await describeNamespace(name)`: find unlisted tools, such as MCP tools.';\n\nconst BASH_OUTPUT: CodemodeJsonSchema = {\n type: 'object',\n properties: { output: { type: 'string' }, exit_code: { type: 'number' } },\n required: ['output', 'exit_code'],\n};\n\nfunction scriptTool(tool: ToolRegistration): Omit<CodemodeTool, 'execute'> {\n return {\n name: tool.name,\n description: tool.description,\n inputSchema: tool.parameters as CodemodeJsonSchema,\n ...(tool.name === 'bash' ? { outputSchema: BASH_OUTPUT } : {}),\n };\n}\n\nexport function codemodeDescription(\n declared: readonly ToolRegistration[],\n discovery = false\n): string {\n const tools = declared\n .filter((tool) => tool.name !== CODEMODE)\n .map((tool) => ({ ...scriptTool(tool), execute: () => undefined }));\n const sections = [INTRO, discovery ? `${GLOBALS}\\n${DISCOVERY}` : GLOBALS];\n if (tools.length) sections.push(`Nested tools:\\n${renderDeclarations({ tools })}`);\n return sections.join('\\n\\n');\n}\n\nfunction textOf(content: readonly { type: string; text?: string }[] | undefined): string {\n return (content ?? [])\n .filter((part) => part.type === 'text')\n .map((part) => part.text)\n .join('\\n');\n}\n\nexport async function callNested(\n tool: ToolRegistration,\n args: unknown,\n api: ToolExecutionApi,\n context: Context,\n id: string\n): Promise<unknown> {\n const prepared = tool.prepareArguments ? tool.prepareArguments(args) : args;\n const valid = validateToolArguments(tool, {\n type: 'toolCall',\n id,\n name: tool.name,\n arguments: prepared as never,\n });\n const decoder = new TextDecoder();\n let output = '';\n const nested: ToolExecutionApi = {\n ...api,\n callId: id,\n outputWindow: undefined,\n output: (chunk) => {\n output += typeof chunk === 'string' ? chunk : decoder.decode(chunk, { stream: true });\n },\n diagnostic: () => undefined,\n details: async () => undefined,\n };\n const bash = tool.name === 'bash';\n try {\n const result = await tool.execute(valid, nested, context);\n const text = result.content ? textOf(result.content) : output;\n if (result.isError) throw new Error(text || `Tool \"${tool.name}\" failed`);\n return bash ? { output: text, exit_code: 0 } : text;\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n const exit = /exited with code (\\d+)/.exec(message);\n if (bash && exit) return { output, exit_code: Number(exit[1]) };\n throw new Error(message);\n }\n}\n\nfunction valueText(value: unknown): string {\n return typeof value === 'string' ? value : (JSON.stringify(value) ?? String(value));\n}\n\nexport function formatOutput(output: readonly CodemodeOutputItem[]): CodemodeOutputItem[] {\n const total = output.filter((item) => item.type === 'text' && !item.console).length;\n const items: CodemodeOutputItem[] = [];\n const lines: string[] = [];\n let index = 0;\n for (const item of output) {\n if (item.type === 'image') items.push(item);\n else if (item.console) lines.push(item.text);\n else {\n index++;\n items.push({\n type: 'text',\n text: total > 1 ? `==> text ${index}/${total} <==\\n${item.text}` : item.text,\n });\n }\n }\n if (lines.length)\n items.push({ type: 'text', text: `<console_output>\\n${lines.join('\\n')}\\n</console_output>` });\n return items;\n}\n\nexport function joinText(items: readonly CodemodeOutputItem[]): CodemodeOutputItem[] {\n const joined: CodemodeOutputItem[] = [];\n for (const item of items) {\n const last = joined.at(-1);\n if (item.type === 'text' && last?.type === 'text') {\n const separator = last.text === '' || last.text.endsWith('\\n') ? '' : '\\n';\n joined[joined.length - 1] = { type: 'text', text: `${last.text}${separator}${item.text}` };\n } else joined.push(item);\n }\n return joined;\n}\n\nexport function formatError(error: CodemodeError, calls: CodemodeResult['calls']): string {\n const heads: Record<string, string> = {\n timeout: `Script timed out: ${error.message}`,\n aborted: `Script aborted: ${error.message}`,\n sandbox: `Script sandbox failed: ${error.message}`,\n };\n const head =\n error.kind === 'script'\n ? (error.stack ?? `${error.name ?? 'Error'}: ${error.message}`)\n : heads[error.kind];\n const summary = calls.length\n ? `Tool calls made before the failure (they are not undone): ${calls.map((call) => `${call.name} (${call.status})`).join(', ')}`\n : 'No tool calls were made.';\n return `${head}\\n\\n${summary}`;\n}\n\nexport function truncate(\n items: readonly CodemodeOutputItem[],\n maxTokens: number\n): { items: CodemodeOutputItem[]; full: string | null } {\n const text = items\n .filter((item) => item.type === 'text')\n .map((item) => item.text)\n .join('\\n');\n const limit = maxTokens * CHARS_PER_TOKEN;\n if (text.length <= limit) return { items: [...items], full: null };\n const half = Math.floor(limit / 2);\n const kept = `${text.slice(0, half)}\\n\\n[\u2026 ${text.length - 2 * half} characters omitted \u2026]\\n\\n${text.slice(-half)}`;\n return {\n items: [{ type: 'text', text: kept }, ...items.filter((item) => item.type === 'image')],\n full: text,\n };\n}\n\nasync function spill(api: ToolExecutionApi, text: string, context: Context): Promise<string> {\n const path = `/tmp/slicc-codemode-${api.callId.replace(/[^\\w-]/g, '_')}.txt`;\n const written = await api.env?.writeFile(path, text, context);\n return written?.ok ? path : '';\n}\n\nasync function saveStore(\n api: ToolExecutionApi,\n result: CodemodeResult,\n context: Context\n): Promise<void> {\n if (!result.ok) return;\n const { set, delete: removed } = result.storeWrites;\n if (!Object.keys(set).length && !removed.length) return;\n await api.commit(async (tx) => {\n const doc = await tx.doc(CodemodeDoc, api.conversationId);\n for (const key of removed) delete doc.store[key];\n Object.assign(doc.store, set);\n }, context);\n}\n\nexport function codemodeTool(options: CodemodeOptions): ToolRegistration {\n return defineTool({\n name: CODEMODE,\n description: codemodeDescription(options.declared, options.extra !== undefined),\n parameters: Type.Object({ code: Type.String({ description: 'Raw JavaScript source.' }) }),\n replay: 'unsafe',\n async execute({ code }, api, context) {\n const started = performance.now();\n const parsed = parseCodemodeSource(code);\n const agent = await api.agent(context);\n const callable = agent.tools.filter((tool) => tool.name !== CODEMODE);\n let count = 0;\n const tools: CodemodeTool[] = callable.map((tool) => ({\n ...scriptTool(tool),\n execute: (args, { signal }) =>\n callNested(tool, args, api, withAbortSignal(signal, context), `${api.callId}:${++count}`),\n }));\n const extra = options.extra\n ? await options.extra(api, agent, context)\n : { tools: [], globals: [] };\n const replaced = new Set(extra.tools.map((tool) => tool.name));\n const scripted = [...tools.filter((tool) => !replaced.has(tool.name)), ...extra.tools];\n const saved = await api.snapshot(CodemodeDoc, api.conversationId, context);\n const sandbox = options.sandbox({\n tools: scripted,\n ...(extra.globals.length ? { globals: extra.globals } : {}),\n timeoutMs: parsed.options.timeoutMs ?? Number.POSITIVE_INFINITY,\n memoryLimitBytes: MEMORY_LIMIT_BYTES,\n });\n let result: CodemodeResult;\n try {\n result = await sandbox.execute(parsed.code, {\n signal: context.abortSignal as AbortSignal,\n store: { ...saved?.store },\n });\n } finally {\n await sandbox.close();\n }\n await saveStore(api, result, context);\n const output = [...result.output];\n if (result.ok && result.value !== undefined)\n output.push({ type: 'text', text: valueText(result.value) });\n const items = formatOutput(output);\n if (!result.ok)\n items.push({\n type: 'text',\n text: `Script error:\\n${formatError(result.error, result.calls)}`,\n });\n const cut = truncate(\n joinText(items),\n parsed.options.maxOutputTokens ?? DEFAULT_MAX_OUTPUT_TOKENS\n );\n const path = cut.full === null ? '' : await spill(api, cut.full, context);\n const note = path ? [{ type: 'text' as const, text: `Full output: ${path}` }] : [];\n const seconds = ((performance.now() - started) / 1000).toFixed(1);\n const header = `${result.ok ? 'Script completed' : 'Script failed'}\\nWall time ${seconds} seconds\\nOutput:\\n`;\n return {\n content: [{ type: 'text', text: header }, ...joinText([...cut.items, ...note])],\n ...(result.ok ? {} : { isError: true }),\n };\n },\n }) as ToolRegistration;\n}\n\nexport function codemodeExtension(tools: readonly ToolRegistration[]): Extension {\n return defineExtension({ name: 'slicc-codemode', tools });\n}\n\nexport function disabledBySettings(text: string | undefined): boolean {\n if (!text) return false;\n try {\n const settings = JSON.parse(text) as { defaultTools?: unknown };\n return Array.isArray(settings.defaultTools) && settings.defaultTools.includes(`-${CODEMODE}`);\n } catch {\n return false;\n }\n}\n\nexport type Fetcher = (url: string) => Promise<Response>;\n\nexport function wasmCandidates(from: URL): string[] {\n const out: string[] = [];\n let dir = new URL('.', from);\n for (;;) {\n out.push(new URL('node_modules/quickjs-wasi/quickjs.wasm', dir).href);\n if (dir.pathname === '/') return out;\n dir = new URL('..', dir);\n }\n}\n\nexport async function locateWasm(\n fetcher: Fetcher,\n from: URL\n): Promise<WebAssembly.Module | undefined> {\n for (const url of wasmCandidates(from)) {\n const response = await fetcher(url).catch(() => undefined);\n if (response?.ok) return WebAssembly.compile(await response.arrayBuffer());\n }\n return undefined;\n}\n\nexport function sandboxFactory(\n wasm: () => Promise<WebAssembly.Module | undefined>,\n workerUrl?: string | URL\n): SandboxFactory {\n let found: Promise<WebAssembly.Module | undefined> | undefined;\n return (options) => {\n found ??= wasm().catch(() => undefined);\n return new CodemodeSandbox({\n ...options,\n ...(workerUrl ? { workerUrl } : {}),\n wasm: found.then((module) => module ?? loadQuickJSWasm()),\n });\n };\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import type { Context, JsonValue } from '@earendil-works/chord';\nimport { withAbortSignal } from '@earendil-works/chord/context';\nimport { Type } from '@earendil-works/pi-ai';\nimport { validateToolArguments } from '@earendil-works/pi-ai/utils/validation';\nimport {\n type CodemodeError,\n type CodemodeJsonSchema,\n type CodemodeOutputItem,\n type CodemodeResult,\n CodemodeSandbox,\n type CodemodeSandboxOptions,\n type CodemodeTool,\n loadQuickJSWasm,\n parseCodemodeSource,\n renderDeclarations,\n} from '@earendil-works/pi-codemode';\nimport {\n type Agent,\n defineDoc,\n defineExtension,\n defineTool,\n type Extension,\n type ToolExecutionApi,\n type ToolRegistration,\n} from '@earendil-works/pi-durable';\nimport { scrubItems } from '../secrets/scrub.ts';\n\nexport const CODEMODE = 'codemode';\nexport const DEFAULT_MAX_OUTPUT_TOKENS = 10_000;\nexport const MEMORY_LIMIT_BYTES = 256 * 1024 * 1024;\nconst CHARS_PER_TOKEN = 4;\n\nexport const CodemodeDoc = defineDoc<{ store: Record<string, JsonValue> }>({\n kind: 'slicc.codemode',\n version: 1,\n scope: 'conversation',\n history: 'rewindable',\n fork: 'asOf',\n initial: () => ({ store: {} }),\n});\n\nexport interface Sandbox {\n execute(\n code: string,\n options: { signal?: AbortSignal; store?: Record<string, unknown> }\n ): Promise<CodemodeResult>;\n close(): Promise<void>;\n}\n\nexport type SandboxFactory = (options: CodemodeSandboxOptions) => Sandbox;\n\nexport interface CodemodeExtra {\n tools: CodemodeTool[];\n globals: CodemodeTool[];\n}\n\nexport interface CodemodeOptions {\n sandbox: SandboxFactory;\n declared: readonly ToolRegistration[];\n extra?: (api: ToolExecutionApi, agent: Agent, context: Context) => Promise<CodemodeExtra>;\n}\n\nconst INTRO = `Run JavaScript that calls other tools. The input is raw JavaScript (not JSON, no code fence), run as an async function body in a QuickJS sandbox: top-level \\`await\\` and \\`return\\` work. No Node, file system, network, or timers.\n- \\`await tools.<name>({ ...args })\\` resolves to a string, or an object if the tool's declaration says so, and rejects with an Error on failure. Calls still running when the script ends are cancelled.\n- Optional first line: \\`// @options: {\"max_output_tokens\": 10000, \"timeout_ms\": 60000}\\``;\n\nconst GLOBALS = [\n 'Globals:',\n '- `text(value)`, `image(dataUrlOrImageBlock)`, `console.log(...)`, and top-level `return` add output; `exit()` ends the script. With several text items, each starts with a `==> text N/M <==` line, and `console` lines follow the other output in one `<console_output>` block.',\n '- `store(key, value)` and `load(key)` keep JSON values across codemode calls in this conversation.',\n '- `ALL_TOOLS` lists every tool scripts can call.',\n].join('\\n');\n\nconst DISCOVERY =\n '- `await searchTools(query, { limit?, namespace? })`, `await describeTool(name)`, `await describeNamespace(name)`: find unlisted tools, such as MCP tools.';\n\nconst BASH_OUTPUT: CodemodeJsonSchema = {\n type: 'object',\n properties: { output: { type: 'string' }, exit_code: { type: 'number' } },\n required: ['output', 'exit_code'],\n};\n\nfunction scriptTool(tool: ToolRegistration): Omit<CodemodeTool, 'execute'> {\n return {\n name: tool.name,\n description: tool.description,\n inputSchema: tool.parameters as CodemodeJsonSchema,\n ...(tool.name === 'bash' ? { outputSchema: BASH_OUTPUT } : {}),\n };\n}\n\nexport function codemodeDescription(\n declared: readonly ToolRegistration[],\n discovery = false\n): string {\n const tools = declared\n .filter((tool) => tool.name !== CODEMODE)\n .map((tool) => ({ ...scriptTool(tool), execute: () => undefined }));\n const sections = [INTRO, discovery ? `${GLOBALS}\\n${DISCOVERY}` : GLOBALS];\n if (tools.length) sections.push(`Nested tools:\\n${renderDeclarations({ tools })}`);\n return sections.join('\\n\\n');\n}\n\nfunction textOf(content: readonly { type: string; text?: string }[] | undefined): string {\n return (content ?? [])\n .filter((part) => part.type === 'text')\n .map((part) => part.text)\n .join('\\n');\n}\n\nexport async function callNested(\n tool: ToolRegistration,\n args: unknown,\n api: ToolExecutionApi,\n context: Context,\n id: string\n): Promise<unknown> {\n const prepared = tool.prepareArguments ? tool.prepareArguments(args) : args;\n const valid = validateToolArguments(tool, {\n type: 'toolCall',\n id,\n name: tool.name,\n arguments: prepared as never,\n });\n const decoder = new TextDecoder();\n let output = '';\n const nested: ToolExecutionApi = {\n ...api,\n callId: id,\n outputWindow: undefined,\n output: (chunk) => {\n output += typeof chunk === 'string' ? chunk : decoder.decode(chunk, { stream: true });\n },\n diagnostic: () => undefined,\n details: async () => undefined,\n };\n const bash = tool.name === 'bash';\n try {\n const result = await tool.execute(valid, nested, context);\n const text = result.content ? textOf(result.content) : output;\n if (result.isError) throw new Error(text || `Tool \"${tool.name}\" failed`);\n return bash ? { output: text, exit_code: 0 } : text;\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n const exit = /exited with code (\\d+)/.exec(message);\n if (bash && exit) return { output, exit_code: Number(exit[1]) };\n throw new Error(message);\n }\n}\n\nfunction valueText(value: unknown): string {\n return typeof value === 'string' ? value : (JSON.stringify(value) ?? String(value));\n}\n\nexport function formatOutput(output: readonly CodemodeOutputItem[]): CodemodeOutputItem[] {\n const total = output.filter((item) => item.type === 'text' && !item.console).length;\n const items: CodemodeOutputItem[] = [];\n const lines: string[] = [];\n let index = 0;\n for (const item of output) {\n if (item.type === 'image') items.push(item);\n else if (item.console) lines.push(item.text);\n else {\n index++;\n items.push({\n type: 'text',\n text: total > 1 ? `==> text ${index}/${total} <==\\n${item.text}` : item.text,\n });\n }\n }\n if (lines.length)\n items.push({ type: 'text', text: `<console_output>\\n${lines.join('\\n')}\\n</console_output>` });\n return items;\n}\n\nexport function joinText(items: readonly CodemodeOutputItem[]): CodemodeOutputItem[] {\n const joined: CodemodeOutputItem[] = [];\n for (const item of items) {\n const last = joined.at(-1);\n if (item.type === 'text' && last?.type === 'text') {\n const separator = last.text === '' || last.text.endsWith('\\n') ? '' : '\\n';\n joined[joined.length - 1] = { type: 'text', text: `${last.text}${separator}${item.text}` };\n } else joined.push(item);\n }\n return joined;\n}\n\nexport function formatError(error: CodemodeError, calls: CodemodeResult['calls']): string {\n const heads: Record<string, string> = {\n timeout: `Script timed out: ${error.message}`,\n aborted: `Script aborted: ${error.message}`,\n sandbox: `Script sandbox failed: ${error.message}`,\n };\n const head =\n error.kind === 'script'\n ? (error.stack ?? `${error.name ?? 'Error'}: ${error.message}`)\n : heads[error.kind];\n const summary = calls.length\n ? `Tool calls made before the failure (they are not undone): ${calls.map((call) => `${call.name} (${call.status})`).join(', ')}`\n : 'No tool calls were made.';\n return `${head}\\n\\n${summary}`;\n}\n\nexport function truncate(\n items: readonly CodemodeOutputItem[],\n maxTokens: number\n): { items: CodemodeOutputItem[]; full: string | null } {\n const text = items\n .filter((item) => item.type === 'text')\n .map((item) => item.text)\n .join('\\n');\n const limit = maxTokens * CHARS_PER_TOKEN;\n if (text.length <= limit) return { items: [...items], full: null };\n const half = Math.floor(limit / 2);\n const kept = `${text.slice(0, half)}\\n\\n[\u2026 ${text.length - 2 * half} characters omitted \u2026]\\n\\n${text.slice(-half)}`;\n return {\n items: [{ type: 'text', text: kept }, ...items.filter((item) => item.type === 'image')],\n full: text,\n };\n}\n\nasync function spill(api: ToolExecutionApi, text: string, context: Context): Promise<string> {\n const path = `/tmp/slicc-codemode-${api.callId.replace(/[^\\w-]/g, '_')}.txt`;\n const written = await api.env?.writeFile(path, text, context);\n return written?.ok ? path : '';\n}\n\nasync function saveStore(\n api: ToolExecutionApi,\n result: CodemodeResult,\n context: Context\n): Promise<void> {\n if (!result.ok) return;\n const { set, delete: removed } = result.storeWrites;\n if (!Object.keys(set).length && !removed.length) return;\n await api.commit(async (tx) => {\n const doc = await tx.doc(CodemodeDoc, api.conversationId);\n for (const key of removed) delete doc.store[key];\n Object.assign(doc.store, set);\n }, context);\n}\n\nexport function codemodeTool(options: CodemodeOptions): ToolRegistration {\n return defineTool({\n name: CODEMODE,\n description: codemodeDescription(options.declared, options.extra !== undefined),\n parameters: Type.Object({ code: Type.String({ description: 'Raw JavaScript source.' }) }),\n replay: 'unsafe',\n async execute({ code }, api, context) {\n const started = performance.now();\n const parsed = parseCodemodeSource(code);\n const agent = await api.agent(context);\n const callable = agent.tools.filter((tool) => tool.name !== CODEMODE);\n let count = 0;\n const tools: CodemodeTool[] = callable.map((tool) => ({\n ...scriptTool(tool),\n execute: (args, { signal }) =>\n callNested(tool, args, api, withAbortSignal(signal, context), `${api.callId}:${++count}`),\n }));\n const extra = options.extra\n ? await options.extra(api, agent, context)\n : { tools: [], globals: [] };\n const replaced = new Set(extra.tools.map((tool) => tool.name));\n const scripted = [...tools.filter((tool) => !replaced.has(tool.name)), ...extra.tools];\n const saved = await api.snapshot(CodemodeDoc, api.conversationId, context);\n const sandbox = options.sandbox({\n tools: scripted,\n ...(extra.globals.length ? { globals: extra.globals } : {}),\n timeoutMs: parsed.options.timeoutMs ?? Number.POSITIVE_INFINITY,\n memoryLimitBytes: MEMORY_LIMIT_BYTES,\n });\n let result: CodemodeResult;\n try {\n result = await sandbox.execute(parsed.code, {\n signal: context.abortSignal as AbortSignal,\n store: { ...saved?.store },\n });\n } finally {\n await sandbox.close();\n }\n await saveStore(api, result, context);\n const output = [...result.output];\n if (result.ok && result.value !== undefined)\n output.push({ type: 'text', text: valueText(result.value) });\n const items = formatOutput(output);\n if (!result.ok)\n items.push({\n type: 'text',\n text: `Script error:\\n${formatError(result.error, result.calls)}`,\n });\n const cut = truncate(\n await scrubItems(joinText(items)),\n parsed.options.maxOutputTokens ?? DEFAULT_MAX_OUTPUT_TOKENS\n );\n const path = cut.full === null ? '' : await spill(api, cut.full, context);\n const note = path ? [{ type: 'text' as const, text: `Full output: ${path}` }] : [];\n const seconds = ((performance.now() - started) / 1000).toFixed(1);\n const header = `${result.ok ? 'Script completed' : 'Script failed'}\\nWall time ${seconds} seconds\\nOutput:\\n`;\n return {\n content: [{ type: 'text', text: header }, ...joinText([...cut.items, ...note])],\n ...(result.ok ? {} : { isError: true }),\n };\n },\n }) as ToolRegistration;\n}\n\nexport function codemodeExtension(tools: readonly ToolRegistration[]): Extension {\n return defineExtension({ name: 'slicc-codemode', tools });\n}\n\nexport function disabledBySettings(text: string | undefined): boolean {\n if (!text) return false;\n try {\n const settings = JSON.parse(text) as { defaultTools?: unknown };\n return Array.isArray(settings.defaultTools) && settings.defaultTools.includes(`-${CODEMODE}`);\n } catch {\n return false;\n }\n}\n\nexport type Fetcher = (url: string) => Promise<Response>;\n\nexport function wasmCandidates(from: URL): string[] {\n const out: string[] = [];\n let dir = new URL('.', from);\n for (;;) {\n out.push(new URL('node_modules/quickjs-wasi/quickjs.wasm', dir).href);\n if (dir.pathname === '/') return out;\n dir = new URL('..', dir);\n }\n}\n\nexport async function locateWasm(\n fetcher: Fetcher,\n from: URL\n): Promise<WebAssembly.Module | undefined> {\n for (const url of wasmCandidates(from)) {\n const response = await fetcher(url).catch(() => undefined);\n if (response?.ok) return WebAssembly.compile(await response.arrayBuffer());\n }\n return undefined;\n}\n\nexport function sandboxFactory(\n wasm: () => Promise<WebAssembly.Module | undefined>,\n workerUrl?: string | URL\n): SandboxFactory {\n let found: Promise<WebAssembly.Module | undefined> | undefined;\n return (options) => {\n found ??= wasm().catch(() => undefined);\n return new CodemodeSandbox({\n ...options,\n ...(workerUrl ? { workerUrl } : {}),\n wasm: found.then((module) => module ?? loadQuickJSWasm()),\n });\n };\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
package/dist/control.js CHANGED
@@ -4,6 +4,8 @@ import {
4
4
  } from "@earendil-works/pi-durable";
5
5
  import { answerText } from "./agent.js";
6
6
  import { LICK_STATE_KIND } from "./licks/state.js";
7
+ import { pinned, SECRETS_COMMAND, secretsEntry } from "./secrets/extension.js";
8
+ import { scrubText } from "./secrets/scrub.js";
7
9
  function readable(out) {
8
10
  const text = out.replace(/^(?:sub)?agent: /, "").trim();
9
11
  const sentence = text.charAt(0).toUpperCase() + text.slice(1);
@@ -143,7 +145,7 @@ async function forkAt(harness, conversation, found, context) {
143
145
  instructions: agent.instructions ?? null,
144
146
  cwd: agent.cwd ?? null
145
147
  };
146
- return harness.createConversation({ ownership, agent: change }, context);
148
+ return harness.createConversation({ ownership, agent: pinned(change) }, context);
147
149
  }
148
150
  async function rewindAgent(deps, agentId, messageId, context) {
149
151
  const { harness, agents, cone, scoops } = deps;
@@ -167,7 +169,7 @@ async function rewindAgent(deps, agentId, messageId, context) {
167
169
  else await cone.switchCone(fork, context);
168
170
  return { done: true, text: found.turn.text, reason: null };
169
171
  }
170
- function createAgentControl(harness, target, deliveries, licks, scoops, skills, sprinkles, memory, freezer, changes, monitor) {
172
+ function createAgentControl(harness, target, deliveries, licks, scoops, skills, sprinkles, memory, freezer, changes, monitor, secrets) {
171
173
  const cone = cones(target);
172
174
  const current = () => cone.cone();
173
175
  const agents = target.agents;
@@ -224,7 +226,15 @@ function createAgentControl(harness, target, deliveries, licks, scoops, skills,
224
226
  return {
225
227
  send(request, context) {
226
228
  return serial(async () => {
227
- const text = skills ? await skills.expand(request.text, context) : request.text;
229
+ if (secrets && request.text.trim() === SECRETS_COMMAND)
230
+ return accepted(
231
+ async () => (await conversationFor(request.agentId, context)).submit(
232
+ { type: "write", entry: secretsEntry(secrets()) },
233
+ context
234
+ )
235
+ );
236
+ const expanded = skills ? await skills.expand(request.text, context) : request.text;
237
+ const text = await scrubText(expanded);
228
238
  const response = await accepted(
229
239
  async () => (await conversationFor(request.agentId, context)).submit(
230
240
  {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/control.ts"],
4
- "sourcesContent": ["import type { Context } from '@earendil-works/chord';\nimport {\n type AgentChange,\n AssistantEntry,\n type Conversation,\n ConversationBusy,\n type ConversationView,\n type EntryId,\n type EntryRecord,\n type Harness,\n type SubmissionId,\n} from '@earendil-works/pi-durable';\nimport { answerText } from './agent.ts';\nimport type { Agents } from './agents.ts';\nimport type { ChangesRuntime } from './changes/index.ts';\nimport type { Cones } from './cone.ts';\nimport type { Deliveries } from './deliveries.ts';\nimport type { FreezerRuntime } from './freezer/index.ts';\nimport type { LickSources, Licks } from './licks/index.ts';\nimport { LICK_STATE_KIND } from './licks/state.ts';\nimport type { MemoryRuntime } from './memory/index.ts';\nimport type { Monitor } from './monitor/index.ts';\nimport type { Scoops, ScoopsRuntime } from './scoops/index.ts';\nimport type {\n AgentControl,\n Created,\n LickResolved,\n OperationError,\n Rewound,\n SendResponse,\n} from './services.ts';\nimport type { SkillsRuntime } from './skills/index.ts';\nimport type { SprinklesRuntime } from './sprinkles/index.ts';\n\nexport interface HostLicks {\n licks: Licks;\n sources: LickSources;\n}\n\nexport interface HostScoops {\n scoops: Scoops;\n runtime: ScoopsRuntime;\n}\n\ntype WithAgents = { agents?: Agents };\n\nexport function readable(out: string): string {\n const text = out.replace(/^(?:sub)?agent: /, '').trim();\n const sentence = text.charAt(0).toUpperCase() + text.slice(1);\n return /[.!?]$/.test(sentence) ? sentence : `${sentence}.`;\n}\n\nfunction created(run: () => Promise<string>): Promise<Created> {\n return run().then(\n (id) => ({ id, error: null }),\n (error: Error) => ({ id: null, error: error.message })\n );\n}\n\nfunction freezerControl(\n freezer: Pick<FreezerRuntime, 'freeze' | 'newChat' | 'thaw' | 'discard'> | undefined\n): Pick<AgentControl, 'freeze' | 'newChat' | 'thaw' | 'discard'> {\n const needed = () => {\n if (!freezer) throw new Error('This agent has no freezer.');\n return freezer;\n };\n return {\n freeze: (agentId, context) => created(async () => needed().freeze(agentId, context)),\n newChat: (agentId, context) =>\n created(async () => (await needed().newChat(agentId, context)) ?? ''),\n thaw: (id, context) => created(async () => needed().thaw(id, context)),\n discard: (id, context) =>\n created(async () => {\n await needed().discard(id, context);\n return id;\n }),\n };\n}\n\nfunction changesControl(\n changes: Pick<ChangesRuntime, 'open' | 'accept' | 'revert'> | undefined\n): Pick<AgentControl, 'changesOpen' | 'changeAccept' | 'changeRevert'> {\n const needed = () => {\n if (!changes) throw new Error('This agent tracks no changes.');\n return changes;\n };\n const done = (path: string, run: (runtime: NonNullable<typeof changes>) => Promise<void>) =>\n created(async () => {\n await run(needed());\n return path;\n });\n return {\n changesOpen: async (context) => changes?.open(context),\n changeAccept: (path, context) => done(path, (runtime) => runtime.accept(path, context)),\n changeRevert: (path, context) => done(path, (runtime) => runtime.revert(path, context)),\n };\n}\n\nfunction memoryControl(\n memory: Pick<MemoryRuntime, 'save' | 'remove'> | undefined\n): Pick<AgentControl, 'memorySave' | 'memoryRemove'> {\n return {\n async memorySave(draft, context) {\n if (!memory) throw new Error('This agent has no memory.');\n const { id, ...rest } = draft;\n return memory.save({ ...rest, ...(id ? { id } : {}) }, context);\n },\n async memoryRemove(id, context) {\n return { removed: memory ? await memory.remove(id, context) : false };\n },\n };\n}\n\nfunction sprinkleControl(\n sprinkles: Pick<SprinklesRuntime, 'send' | 'call'> | undefined\n): Pick<AgentControl, 'sprinkleSend' | 'sprinkleCall'> {\n return {\n sprinkleSend: async (id, payload, context) =>\n sprinkles ? sprinkles.send(id, payload, context) : { delivered: false },\n async sprinkleCall(id, method, args, context) {\n if (!sprinkles) throw new Error('This agent has no sprinkles.');\n return sprinkles.call(id, method, args, context);\n },\n };\n}\n\nexport function submissionId(value: string): SubmissionId | undefined {\n const id = Number(value);\n return /^[1-9][0-9]*$/.test(value) && Number.isSafeInteger(id) ? (id as SubmissionId) : undefined;\n}\n\nfunction operationError(error: unknown): OperationError {\n if (error instanceof ConversationBusy) return { code: 'busy', message: error.message };\n return { code: 'failed', message: error instanceof Error ? error.message : String(error) };\n}\n\nasync function accepted(operation: () => Promise<{ id: number } | number>): Promise<SendResponse> {\n try {\n const result = await operation();\n const id = typeof result === 'number' ? result : result.id;\n return { accepted: true, submissionId: String(id), error: null };\n } catch (error) {\n return { accepted: false, submissionId: null, error: operationError(error) };\n }\n}\n\nfunction cones(target: Conversation | Cones): Cones {\n if ('cone' in target) return target;\n return {\n cone: () => target,\n switchCone: async () => {\n throw new Error('this conversation has no cone to rewind');\n },\n };\n}\n\ninterface Turn {\n text: string;\n at: EntryId | null;\n files: boolean;\n}\n\ntype Block = { type?: string; name?: string };\n\nconst WRITERS = ['write', 'edit', 'bash', 'codemode'];\n\nfunction writesIn(entries: readonly EntryRecord[]): boolean {\n return entries.some((entry) =>\n (entry.model ?? []).some(\n (message) =>\n Array.isArray(message.content) &&\n (message.content as Block[]).some(\n (block) => block.type === 'toolCall' && WRITERS.includes(String(block.name))\n )\n )\n );\n}\n\nfunction lastTurn(view: ConversationView, messageId: string | null): Turn | null {\n const { entries } = view;\n const target = entries.findIndex((entry) => `e${entry.id}` === messageId);\n if (target < 0) return null;\n const turn = entries.slice(0, target).findLastIndex((entry) => entry.kind === 'pi.user');\n if (turn < 0) return null;\n const user = entries[turn] as EntryRecord;\n return {\n text: answerText(user.model?.[0]?.content),\n at: entries[turn - 1]?.id ?? null,\n files: writesIn(entries.slice(turn)),\n };\n}\n\nfunction busy(view: ConversationView): boolean {\n const live = view.docs['pi.live'] as { run?: unknown } | undefined;\n const inbox = view.docs['pi.inbox'] as { items?: unknown[] } | undefined;\n return Boolean(live?.run) || Boolean(inbox?.items?.length);\n}\n\ntype RewindDeps = {\n harness: Harness;\n agents?: Agents;\n cone: Cones;\n scoops?: HostScoops;\n};\n\nasync function turnIn(\n harness: Harness,\n conversation: Conversation,\n messageId: string | null,\n context: Context\n): Promise<{ turn: Turn; view: ConversationView } | Rewound> {\n const attached = await conversation.viewState(context);\n const view = attached.value;\n attached.dispose();\n const pending = (await harness.inspect(context)).submissions.some(\n (submission) => submission.conversationId === conversation.id\n );\n if (pending || busy(view)) return { done: false, text: null, reason: 'busy' };\n const turn = lastTurn(view, messageId);\n return turn ? { turn, view } : { done: false, text: null, reason: 'no-turn' };\n}\n\nasync function forkAt(\n harness: Harness,\n conversation: Conversation,\n found: { turn: Turn },\n context: Context\n): Promise<Conversation> {\n const ownership = { kind: 'ownerless' } as const;\n if (found.turn.at !== null) return conversation.fork(found.turn.at, { ownership }, context);\n const agent = await conversation.agent(context);\n const change: AgentChange = {\n model: agent.model ?? null,\n thinkingLevel: agent.thinkingLevel,\n extensions: agent.extensions,\n tools: agent.tools,\n instructions: agent.instructions ?? null,\n cwd: agent.cwd ?? null,\n };\n return harness.createConversation({ ownership, agent: change }, context);\n}\n\nasync function rewindAgent(\n deps: RewindDeps,\n agentId: string | null,\n messageId: string | null,\n context: Context\n): Promise<Rewound> {\n const { harness, agents, cone, scoops } = deps;\n const scoop = agentId && agents ? agents.state().scoops[agentId] : undefined;\n if (agentId && agents && !scoop && agentId !== agents.activeCone())\n await agents.selectCone(agentId, context);\n const conversation =\n scoop && agents\n ? ((await agents.conversation(agentId as string, context)) as Conversation)\n : cone.cone();\n const found = await turnIn(harness, conversation, messageId, context);\n if ('reason' in found) return found;\n const fork = await forkAt(harness, conversation, found, context);\n const changed =\n scoops && agents && !scoop\n ? await scoops.scoops.rewound(agents.activeCone(), fork, context)\n : { stopped: [], restored: [] };\n const files = found.turn.files;\n await fork.submit(\n { type: 'write', entry: { kind: 'slicc.rewound', data: { turns: 1, ...changed, files } } },\n context\n );\n if (scoop && agents)\n await agents.update((_tx, state) => {\n (state.scoops[agentId as string] as { conversation: number }).conversation = fork.id;\n }, context);\n else await cone.switchCone(fork, context);\n return { done: true, text: found.turn.text, reason: null };\n}\n\nexport function createAgentControl(\n harness: Harness,\n target: Conversation | Cones,\n deliveries?: Deliveries,\n licks?: HostLicks,\n scoops?: HostScoops,\n skills?: Pick<SkillsRuntime, 'expand'>,\n sprinkles?: Pick<SprinklesRuntime, 'send' | 'call'>,\n memory?: Pick<MemoryRuntime, 'save' | 'remove'>,\n freezer?: Pick<FreezerRuntime, 'freeze' | 'newChat' | 'thaw' | 'discard'>,\n changes?: Pick<ChangesRuntime, 'open' | 'accept' | 'revert'>,\n monitor?: Pick<Monitor, 'open' | 'close'>\n): AgentControl {\n const cone = cones(target);\n const current = () => cone.cone();\n const agents = (target as WithAgents).agents;\n const conversationFor = async (agentId: string | null | undefined, context: Context) => {\n if (!agentId || !agents) return current();\n const found = await agents.conversation(agentId, context);\n if (!found) throw new Error(`There is no agent ${agentId}.`);\n return found;\n };\n const withdraw = async (conversation: Conversation, id: string, context: Context) => {\n const parsed = submissionId(id);\n if (parsed === undefined) return { outcome: 'not_found' as const };\n const result = await harness.abortSubmission(parsed, context, conversation.id);\n if (result === 'aborted') return { outcome: 'withdrawn' as const };\n return {\n outcome: result === 'not_found' ? ('not_found' as const) : ('already_placed' as const),\n };\n };\n let lock: Promise<unknown> = Promise.resolve();\n const serial = <T>(operation: () => Promise<T>): Promise<T> => {\n const run = lock.then(operation, operation);\n lock = run.catch(() => undefined);\n return run;\n };\n const rewindIn = (agentId: string | null, messageId: string | null, context: Context) =>\n serial(() => rewindAgent({ harness, agents, cone, scoops }, agentId, messageId, context));\n const decide = (\n agentId: string | null,\n lickId: string,\n state: 'confirmed' | 'dismissed',\n context: Context\n ): Promise<LickResolved> =>\n serial(async () => {\n if (!licks) return { done: false, text: null, error: 'this agent has no licks' };\n const action = state === 'confirmed' ? 'confirm' : 'dismiss';\n try {\n const conversation = await conversationFor(agentId, context);\n const text = await licks.licks.decide(conversation, lickId, action, undefined, context);\n await conversation.submit(\n {\n type: 'write',\n entry: {\n kind: LICK_STATE_KIND,\n data: { lick: lickId, state, by: 'user' },\n model: [\n {\n role: 'user',\n content: `The user ${state} lick ${lickId}: ${text}`,\n timestamp: Date.now(),\n },\n ],\n },\n },\n context\n );\n return { done: true, text, error: null };\n } catch (error) {\n return { done: false, text: null, error: (error as Error).message };\n }\n });\n return {\n send(request, context) {\n return serial(async () => {\n const text = skills ? await skills.expand(request.text, context) : request.text;\n const response = await accepted(async () =>\n (await conversationFor(request.agentId, context)).submit(\n {\n type: 'input',\n content: text,\n whenBusy: request.whenBusy,\n ...(request.requestId ? { requestId: request.requestId } : {}),\n },\n context\n )\n );\n const id = response.submissionId === null ? undefined : submissionId(response.submissionId);\n if (id !== undefined) deliveries?.expect(id, request.whenBusy);\n return response;\n });\n },\n rewind: (messageId, context) => rewindIn(null, messageId, context),\n rewindAgent: (agentId, messageId, context) => rewindIn(agentId, messageId, context),\n\n async wait(id, context) {\n const parsed = submissionId(id);\n const submission =\n parsed === undefined ? undefined : await harness.submission(parsed, context);\n if (!submission) throw new Error(`unknown submission ${id}`);\n const settled = await submission.wait(context);\n const { answer, reason } = settled as { answer?: EntryId; reason?: string };\n if (answer === undefined) return { status: 'unanswered', text: null, reason: String(reason) };\n const entry = await harness.commit((tx) => tx.entry(AssistantEntry, answer), context);\n return { status: 'done', text: answerText(entry?.model?.[0]?.content), reason: null };\n },\n withdraw: (id, context) => withdraw(current(), id, context),\n ...sprinkleControl(sprinkles),\n ...memoryControl(memory),\n ...freezerControl(freezer),\n ...changesControl(changes),\n monitorOpen: async (lease, resync, context) =>\n monitor ? monitor.open(lease, resync, context) : { lease: '', ttlMs: 0 },\n monitorClose: async (lease, context) => monitor?.close(lease, context),\n async unqueue(agentId, id, context) {\n return withdraw(await conversationFor(agentId, context), id, context);\n },\n abort: (context) => current().abort(context),\n compact: (instructions, context) =>\n accepted(() => current().compact(instructions ?? undefined, context)),\n compactAgent: (agentId, instructions, context) =>\n accepted(async () =>\n (await conversationFor(agentId, context)).compact(instructions ?? undefined, context)\n ),\n reset: (handoff, context) => current().reset(handoff ?? undefined, context),\n resolveLick: (lickId, state, context) => decide(null, lickId, state, context),\n resolveAgentLick: (agentId, lickId, state, context) => decide(agentId, lickId, state, context),\n async webhook(name, delivery, context) {\n const delivered = licks\n ? await licks.sources.webhook(\n name,\n {\n ...(delivery.id ? { id: delivery.id } : {}),\n headers: delivery.headers,\n body: delivery.body,\n },\n context\n )\n : false;\n return { delivered };\n },\n async stopAgent(agentId, context) {\n await (await conversationFor(agentId, context)).abort(context);\n },\n async selectCone(agentId, context) {\n await agents?.selectCone(agentId, context);\n },\n createCone(name, context) {\n return created(async () => {\n if (!agents) throw new Error('This agent has a single cone.');\n return agents.createCone(name, context);\n });\n },\n createScoop(parentId, name, context) {\n return created(async () => {\n if (!scoops) throw new Error('This agent has no scoops.');\n const roles = await scoops.runtime.roles(context);\n const answer = await scoops.scoops.spawn(\n { cone: parentId, name, prompts: [], fromAgent: false, limits: roles.limits },\n context\n );\n if (answer.code !== 0) throw new Error(readable(answer.out));\n return `scoop:${answer.out.trim()}`;\n });\n },\n drop(agentId, context) {\n return created(async () => {\n if (!scoops) throw new Error('This agent has no scoops.');\n const answer = await scoops.scoops.stop(agentId, false, context);\n if (answer.code !== 0) throw new Error(readable(answer.out));\n return agentId;\n });\n },\n configure: async (change, context) =>\n (await conversationFor(change.agentId, context)).configure(\n {\n ...(change.model ? { model: change.model } : {}),\n ...(change.thinkingLevel ? { thinkingLevel: change.thinkingLevel } : {}),\n },\n context\n ),\n };\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import type { Context } from '@earendil-works/chord';\nimport {\n type AgentChange,\n AssistantEntry,\n type Conversation,\n ConversationBusy,\n type ConversationView,\n type EntryId,\n type EntryRecord,\n type Harness,\n type SubmissionId,\n} from '@earendil-works/pi-durable';\nimport { answerText } from './agent.ts';\nimport type { Agents } from './agents.ts';\nimport type { ChangesRuntime } from './changes/index.ts';\nimport type { Cones } from './cone.ts';\nimport type { Deliveries } from './deliveries.ts';\nimport type { FreezerRuntime } from './freezer/index.ts';\nimport type { LickSources, Licks } from './licks/index.ts';\nimport { LICK_STATE_KIND } from './licks/state.ts';\nimport type { MemoryRuntime } from './memory/index.ts';\nimport type { Monitor } from './monitor/index.ts';\nimport type { Scoops, ScoopsRuntime } from './scoops/index.ts';\nimport { pinned, SECRETS_COMMAND, secretsEntry } from './secrets/extension.ts';\nimport type { SecretName } from './secrets/names.ts';\nimport { scrubText } from './secrets/scrub.ts';\nimport type {\n AgentControl,\n Created,\n LickResolved,\n OperationError,\n Rewound,\n SendResponse,\n} from './services.ts';\nimport type { SkillsRuntime } from './skills/index.ts';\nimport type { SprinklesRuntime } from './sprinkles/index.ts';\n\nexport interface HostLicks {\n licks: Licks;\n sources: LickSources;\n}\n\nexport interface HostScoops {\n scoops: Scoops;\n runtime: ScoopsRuntime;\n}\n\ntype WithAgents = { agents?: Agents };\n\nexport function readable(out: string): string {\n const text = out.replace(/^(?:sub)?agent: /, '').trim();\n const sentence = text.charAt(0).toUpperCase() + text.slice(1);\n return /[.!?]$/.test(sentence) ? sentence : `${sentence}.`;\n}\n\nfunction created(run: () => Promise<string>): Promise<Created> {\n return run().then(\n (id) => ({ id, error: null }),\n (error: Error) => ({ id: null, error: error.message })\n );\n}\n\nfunction freezerControl(\n freezer: Pick<FreezerRuntime, 'freeze' | 'newChat' | 'thaw' | 'discard'> | undefined\n): Pick<AgentControl, 'freeze' | 'newChat' | 'thaw' | 'discard'> {\n const needed = () => {\n if (!freezer) throw new Error('This agent has no freezer.');\n return freezer;\n };\n return {\n freeze: (agentId, context) => created(async () => needed().freeze(agentId, context)),\n newChat: (agentId, context) =>\n created(async () => (await needed().newChat(agentId, context)) ?? ''),\n thaw: (id, context) => created(async () => needed().thaw(id, context)),\n discard: (id, context) =>\n created(async () => {\n await needed().discard(id, context);\n return id;\n }),\n };\n}\n\nfunction changesControl(\n changes: Pick<ChangesRuntime, 'open' | 'accept' | 'revert'> | undefined\n): Pick<AgentControl, 'changesOpen' | 'changeAccept' | 'changeRevert'> {\n const needed = () => {\n if (!changes) throw new Error('This agent tracks no changes.');\n return changes;\n };\n const done = (path: string, run: (runtime: NonNullable<typeof changes>) => Promise<void>) =>\n created(async () => {\n await run(needed());\n return path;\n });\n return {\n changesOpen: async (context) => changes?.open(context),\n changeAccept: (path, context) => done(path, (runtime) => runtime.accept(path, context)),\n changeRevert: (path, context) => done(path, (runtime) => runtime.revert(path, context)),\n };\n}\n\nfunction memoryControl(\n memory: Pick<MemoryRuntime, 'save' | 'remove'> | undefined\n): Pick<AgentControl, 'memorySave' | 'memoryRemove'> {\n return {\n async memorySave(draft, context) {\n if (!memory) throw new Error('This agent has no memory.');\n const { id, ...rest } = draft;\n return memory.save({ ...rest, ...(id ? { id } : {}) }, context);\n },\n async memoryRemove(id, context) {\n return { removed: memory ? await memory.remove(id, context) : false };\n },\n };\n}\n\nfunction sprinkleControl(\n sprinkles: Pick<SprinklesRuntime, 'send' | 'call'> | undefined\n): Pick<AgentControl, 'sprinkleSend' | 'sprinkleCall'> {\n return {\n sprinkleSend: async (id, payload, context) =>\n sprinkles ? sprinkles.send(id, payload, context) : { delivered: false },\n async sprinkleCall(id, method, args, context) {\n if (!sprinkles) throw new Error('This agent has no sprinkles.');\n return sprinkles.call(id, method, args, context);\n },\n };\n}\n\nexport function submissionId(value: string): SubmissionId | undefined {\n const id = Number(value);\n return /^[1-9][0-9]*$/.test(value) && Number.isSafeInteger(id) ? (id as SubmissionId) : undefined;\n}\n\nfunction operationError(error: unknown): OperationError {\n if (error instanceof ConversationBusy) return { code: 'busy', message: error.message };\n return { code: 'failed', message: error instanceof Error ? error.message : String(error) };\n}\n\nasync function accepted(operation: () => Promise<{ id: number } | number>): Promise<SendResponse> {\n try {\n const result = await operation();\n const id = typeof result === 'number' ? result : result.id;\n return { accepted: true, submissionId: String(id), error: null };\n } catch (error) {\n return { accepted: false, submissionId: null, error: operationError(error) };\n }\n}\n\nfunction cones(target: Conversation | Cones): Cones {\n if ('cone' in target) return target;\n return {\n cone: () => target,\n switchCone: async () => {\n throw new Error('this conversation has no cone to rewind');\n },\n };\n}\n\ninterface Turn {\n text: string;\n at: EntryId | null;\n files: boolean;\n}\n\ntype Block = { type?: string; name?: string };\n\nconst WRITERS = ['write', 'edit', 'bash', 'codemode'];\n\nfunction writesIn(entries: readonly EntryRecord[]): boolean {\n return entries.some((entry) =>\n (entry.model ?? []).some(\n (message) =>\n Array.isArray(message.content) &&\n (message.content as Block[]).some(\n (block) => block.type === 'toolCall' && WRITERS.includes(String(block.name))\n )\n )\n );\n}\n\nfunction lastTurn(view: ConversationView, messageId: string | null): Turn | null {\n const { entries } = view;\n const target = entries.findIndex((entry) => `e${entry.id}` === messageId);\n if (target < 0) return null;\n const turn = entries.slice(0, target).findLastIndex((entry) => entry.kind === 'pi.user');\n if (turn < 0) return null;\n const user = entries[turn] as EntryRecord;\n return {\n text: answerText(user.model?.[0]?.content),\n at: entries[turn - 1]?.id ?? null,\n files: writesIn(entries.slice(turn)),\n };\n}\n\nfunction busy(view: ConversationView): boolean {\n const live = view.docs['pi.live'] as { run?: unknown } | undefined;\n const inbox = view.docs['pi.inbox'] as { items?: unknown[] } | undefined;\n return Boolean(live?.run) || Boolean(inbox?.items?.length);\n}\n\ntype RewindDeps = {\n harness: Harness;\n agents?: Agents;\n cone: Cones;\n scoops?: HostScoops;\n};\n\nasync function turnIn(\n harness: Harness,\n conversation: Conversation,\n messageId: string | null,\n context: Context\n): Promise<{ turn: Turn; view: ConversationView } | Rewound> {\n const attached = await conversation.viewState(context);\n const view = attached.value;\n attached.dispose();\n const pending = (await harness.inspect(context)).submissions.some(\n (submission) => submission.conversationId === conversation.id\n );\n if (pending || busy(view)) return { done: false, text: null, reason: 'busy' };\n const turn = lastTurn(view, messageId);\n return turn ? { turn, view } : { done: false, text: null, reason: 'no-turn' };\n}\n\nasync function forkAt(\n harness: Harness,\n conversation: Conversation,\n found: { turn: Turn },\n context: Context\n): Promise<Conversation> {\n const ownership = { kind: 'ownerless' } as const;\n if (found.turn.at !== null) return conversation.fork(found.turn.at, { ownership }, context);\n const agent = await conversation.agent(context);\n const change: AgentChange = {\n model: agent.model ?? null,\n thinkingLevel: agent.thinkingLevel,\n extensions: agent.extensions,\n tools: agent.tools,\n instructions: agent.instructions ?? null,\n cwd: agent.cwd ?? null,\n };\n return harness.createConversation({ ownership, agent: pinned(change) }, context);\n}\n\nasync function rewindAgent(\n deps: RewindDeps,\n agentId: string | null,\n messageId: string | null,\n context: Context\n): Promise<Rewound> {\n const { harness, agents, cone, scoops } = deps;\n const scoop = agentId && agents ? agents.state().scoops[agentId] : undefined;\n if (agentId && agents && !scoop && agentId !== agents.activeCone())\n await agents.selectCone(agentId, context);\n const conversation =\n scoop && agents\n ? ((await agents.conversation(agentId as string, context)) as Conversation)\n : cone.cone();\n const found = await turnIn(harness, conversation, messageId, context);\n if ('reason' in found) return found;\n const fork = await forkAt(harness, conversation, found, context);\n const changed =\n scoops && agents && !scoop\n ? await scoops.scoops.rewound(agents.activeCone(), fork, context)\n : { stopped: [], restored: [] };\n const files = found.turn.files;\n await fork.submit(\n { type: 'write', entry: { kind: 'slicc.rewound', data: { turns: 1, ...changed, files } } },\n context\n );\n if (scoop && agents)\n await agents.update((_tx, state) => {\n (state.scoops[agentId as string] as { conversation: number }).conversation = fork.id;\n }, context);\n else await cone.switchCone(fork, context);\n return { done: true, text: found.turn.text, reason: null };\n}\n\nexport function createAgentControl(\n harness: Harness,\n target: Conversation | Cones,\n deliveries?: Deliveries,\n licks?: HostLicks,\n scoops?: HostScoops,\n skills?: Pick<SkillsRuntime, 'expand'>,\n sprinkles?: Pick<SprinklesRuntime, 'send' | 'call'>,\n memory?: Pick<MemoryRuntime, 'save' | 'remove'>,\n freezer?: Pick<FreezerRuntime, 'freeze' | 'newChat' | 'thaw' | 'discard'>,\n changes?: Pick<ChangesRuntime, 'open' | 'accept' | 'revert'>,\n monitor?: Pick<Monitor, 'open' | 'close'>,\n secrets?: () => readonly SecretName[]\n): AgentControl {\n const cone = cones(target);\n const current = () => cone.cone();\n const agents = (target as WithAgents).agents;\n const conversationFor = async (agentId: string | null | undefined, context: Context) => {\n if (!agentId || !agents) return current();\n const found = await agents.conversation(agentId, context);\n if (!found) throw new Error(`There is no agent ${agentId}.`);\n return found;\n };\n const withdraw = async (conversation: Conversation, id: string, context: Context) => {\n const parsed = submissionId(id);\n if (parsed === undefined) return { outcome: 'not_found' as const };\n const result = await harness.abortSubmission(parsed, context, conversation.id);\n if (result === 'aborted') return { outcome: 'withdrawn' as const };\n return {\n outcome: result === 'not_found' ? ('not_found' as const) : ('already_placed' as const),\n };\n };\n let lock: Promise<unknown> = Promise.resolve();\n const serial = <T>(operation: () => Promise<T>): Promise<T> => {\n const run = lock.then(operation, operation);\n lock = run.catch(() => undefined);\n return run;\n };\n const rewindIn = (agentId: string | null, messageId: string | null, context: Context) =>\n serial(() => rewindAgent({ harness, agents, cone, scoops }, agentId, messageId, context));\n const decide = (\n agentId: string | null,\n lickId: string,\n state: 'confirmed' | 'dismissed',\n context: Context\n ): Promise<LickResolved> =>\n serial(async () => {\n if (!licks) return { done: false, text: null, error: 'this agent has no licks' };\n const action = state === 'confirmed' ? 'confirm' : 'dismiss';\n try {\n const conversation = await conversationFor(agentId, context);\n const text = await licks.licks.decide(conversation, lickId, action, undefined, context);\n await conversation.submit(\n {\n type: 'write',\n entry: {\n kind: LICK_STATE_KIND,\n data: { lick: lickId, state, by: 'user' },\n model: [\n {\n role: 'user',\n content: `The user ${state} lick ${lickId}: ${text}`,\n timestamp: Date.now(),\n },\n ],\n },\n },\n context\n );\n return { done: true, text, error: null };\n } catch (error) {\n return { done: false, text: null, error: (error as Error).message };\n }\n });\n return {\n send(request, context) {\n return serial(async () => {\n if (secrets && request.text.trim() === SECRETS_COMMAND)\n return accepted(async () =>\n (await conversationFor(request.agentId, context)).submit(\n { type: 'write', entry: secretsEntry(secrets()) },\n context\n )\n );\n const expanded = skills ? await skills.expand(request.text, context) : request.text;\n const text = await scrubText(expanded);\n const response = await accepted(async () =>\n (await conversationFor(request.agentId, context)).submit(\n {\n type: 'input',\n content: text,\n whenBusy: request.whenBusy,\n ...(request.requestId ? { requestId: request.requestId } : {}),\n },\n context\n )\n );\n const id = response.submissionId === null ? undefined : submissionId(response.submissionId);\n if (id !== undefined) deliveries?.expect(id, request.whenBusy);\n return response;\n });\n },\n rewind: (messageId, context) => rewindIn(null, messageId, context),\n rewindAgent: (agentId, messageId, context) => rewindIn(agentId, messageId, context),\n\n async wait(id, context) {\n const parsed = submissionId(id);\n const submission =\n parsed === undefined ? undefined : await harness.submission(parsed, context);\n if (!submission) throw new Error(`unknown submission ${id}`);\n const settled = await submission.wait(context);\n const { answer, reason } = settled as { answer?: EntryId; reason?: string };\n if (answer === undefined) return { status: 'unanswered', text: null, reason: String(reason) };\n const entry = await harness.commit((tx) => tx.entry(AssistantEntry, answer), context);\n return { status: 'done', text: answerText(entry?.model?.[0]?.content), reason: null };\n },\n withdraw: (id, context) => withdraw(current(), id, context),\n ...sprinkleControl(sprinkles),\n ...memoryControl(memory),\n ...freezerControl(freezer),\n ...changesControl(changes),\n monitorOpen: async (lease, resync, context) =>\n monitor ? monitor.open(lease, resync, context) : { lease: '', ttlMs: 0 },\n monitorClose: async (lease, context) => monitor?.close(lease, context),\n async unqueue(agentId, id, context) {\n return withdraw(await conversationFor(agentId, context), id, context);\n },\n abort: (context) => current().abort(context),\n compact: (instructions, context) =>\n accepted(() => current().compact(instructions ?? undefined, context)),\n compactAgent: (agentId, instructions, context) =>\n accepted(async () =>\n (await conversationFor(agentId, context)).compact(instructions ?? undefined, context)\n ),\n reset: (handoff, context) => current().reset(handoff ?? undefined, context),\n resolveLick: (lickId, state, context) => decide(null, lickId, state, context),\n resolveAgentLick: (agentId, lickId, state, context) => decide(agentId, lickId, state, context),\n async webhook(name, delivery, context) {\n const delivered = licks\n ? await licks.sources.webhook(\n name,\n {\n ...(delivery.id ? { id: delivery.id } : {}),\n headers: delivery.headers,\n body: delivery.body,\n },\n context\n )\n : false;\n return { delivered };\n },\n async stopAgent(agentId, context) {\n await (await conversationFor(agentId, context)).abort(context);\n },\n async selectCone(agentId, context) {\n await agents?.selectCone(agentId, context);\n },\n createCone(name, context) {\n return created(async () => {\n if (!agents) throw new Error('This agent has a single cone.');\n return agents.createCone(name, context);\n });\n },\n createScoop(parentId, name, context) {\n return created(async () => {\n if (!scoops) throw new Error('This agent has no scoops.');\n const roles = await scoops.runtime.roles(context);\n const answer = await scoops.scoops.spawn(\n { cone: parentId, name, prompts: [], fromAgent: false, limits: roles.limits },\n context\n );\n if (answer.code !== 0) throw new Error(readable(answer.out));\n return `scoop:${answer.out.trim()}`;\n });\n },\n drop(agentId, context) {\n return created(async () => {\n if (!scoops) throw new Error('This agent has no scoops.');\n const answer = await scoops.scoops.stop(agentId, false, context);\n if (answer.code !== 0) throw new Error(readable(answer.out));\n return agentId;\n });\n },\n configure: async (change, context) =>\n (await conversationFor(change.agentId, context)).configure(\n {\n ...(change.model ? { model: change.model } : {}),\n ...(change.thinkingLevel ? { thinkingLevel: change.thinkingLevel } : {}),\n },\n context\n ),\n };\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -6,6 +6,7 @@ import {
6
6
  } from "../agents.js";
7
7
  import { HOME } from "../kernel/env.js";
8
8
  import { SCOOPS_ROOT, workspace } from "../scoops/service.js";
9
+ import { pinned } from "../secrets/extension.js";
9
10
  const THAWED_KIND = "slicc.thawed";
10
11
  const USAGE = `usage:
11
12
  freezer list every conversation: id, kind, name, title, messages, when
@@ -189,14 +190,14 @@ async function freshLike(harness, conversation, context) {
189
190
  return harness.createConversation(
190
191
  {
191
192
  ownership: { kind: "ownerless" },
192
- agent: {
193
+ agent: pinned({
193
194
  model: agent.model,
194
195
  thinkingLevel: agent.thinkingLevel,
195
196
  extensions: agent.extensions,
196
197
  tools: agent.tools,
197
198
  instructions: agent.instructions ?? null,
198
199
  cwd: agent.cwd ?? null
199
- }
200
+ })
200
201
  },
201
202
  context
202
203
  );
@@ -217,14 +218,14 @@ async function thawScoop(options, id, scoop, context) {
217
218
  const cone = await (await activeCone(agents, context)).agent(context);
218
219
  const created = {
219
220
  ownership: { kind: "ownerless" },
220
- agent: {
221
+ agent: pinned({
221
222
  model: agent.model,
222
223
  thinkingLevel: agent.thinkingLevel,
223
224
  extensions: cone.extensions,
224
225
  tools: cone.tools,
225
226
  instructions: cone.instructions ?? null,
226
227
  cwd: HOME
227
- }
228
+ })
228
229
  };
229
230
  const fork = last ? await conversation.fork(last.id, created, context) : await harness.createConversation(created, context);
230
231
  const folder = workspace(scoop.folder);