agents 0.25.0 → 0.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{harnesses → harness}/pi/index.d.ts +84 -88
- package/dist/{harnesses → harness}/pi/index.js +196 -77
- package/dist/harness/pi/index.js.map +1 -0
- package/dist/models/pi-ai/index.d.ts +14 -14
- package/dist/models/pi-ai/index.js +5 -5
- package/dist/models/pi-ai/index.js.map +1 -1
- package/docs/harnesses/pi.md +114 -32
- package/docs/index.md +2 -2
- package/docs/models-pi-ai.md +5 -5
- package/package.json +10 -10
- package/dist/harnesses/pi/index.js.map +0 -1
package/docs/harnesses/pi.md
CHANGED
|
@@ -1,40 +1,37 @@
|
|
|
1
1
|
---
|
|
2
|
-
title: Pi harness (
|
|
2
|
+
title: Pi harness (Beta)
|
|
3
3
|
pcx_content_type: get-started
|
|
4
|
-
description: Host pi-durable sessions in a Durable Object with the
|
|
4
|
+
description: Host pi-durable sessions in a Durable Object with the beta PiHarness lifecycle capability. Connect a pi-ai model, add tools and skills, and keep sessions running across eviction.
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
`PiHarness` hosts [pi-durable](https://github.com/earendil-works/pi/tree/main/packages/durable) in a Durable Object. It
|
|
7
|
+
`PiHarness` hosts [pi-durable](https://github.com/earendil-works/pi/tree/main/packages/durable) in a Durable Object. It opens Pi over the object's SQLite database and connects Pi's sessions to the Agents SDK lifecycle, which wakes sessions with work after eviction. The API is in beta and may change.
|
|
8
8
|
|
|
9
|
-
`PiHarness` does not provide a chat protocol or user interface. Your application chooses how clients reach sessions, such as
|
|
9
|
+
Pi owns everything about a run: the transcript, the inbox of steers and follow-ups, generation, tool calls, retries, and crash recovery. `PiHarness` supplies the storage and the wake. It does not provide a chat protocol or user interface. Your application chooses how clients reach sessions, such as WebSockets, HTTP, or RPC.
|
|
10
10
|
|
|
11
|
-
## Install the
|
|
12
|
-
|
|
13
|
-
Install `agents` with pi-durable and pi-ai:
|
|
11
|
+
## Install the Pi packages
|
|
14
12
|
|
|
15
13
|
```sh
|
|
16
14
|
npm install agents @earendil-works/pi-durable @earendil-works/pi-ai
|
|
17
15
|
```
|
|
18
16
|
|
|
19
|
-
Both
|
|
17
|
+
Both Pi packages are optional peer dependencies of `agents`, at `^1.0.0`. The examples use Workers AI through the `AI` binding. To configure the binding and choose other models, refer to [Models for pi-ai](../models-pi-ai.md).
|
|
20
18
|
|
|
21
19
|
## Create the harness
|
|
22
20
|
|
|
23
|
-
|
|
21
|
+
`PiHarness` uses a factory function to construct Pi's `Harness` so it can be instantiated lazily:
|
|
24
22
|
|
|
25
23
|
```ts
|
|
26
|
-
import { DurableObject } from "cloudflare:workers";
|
|
27
24
|
import { createModels } from "@earendil-works/pi-ai/models";
|
|
28
25
|
import { createRegistry, Harness } from "@earendil-works/pi-durable";
|
|
29
|
-
import {
|
|
30
|
-
import {
|
|
31
|
-
import {
|
|
26
|
+
import { Agent } from "agents";
|
|
27
|
+
import { PiHarness } from "agents/harness/pi";
|
|
28
|
+
import { createAI } from "agents/models/pi-ai";
|
|
32
29
|
|
|
33
|
-
export class Assistant extends
|
|
34
|
-
|
|
35
|
-
|
|
30
|
+
export class Assistant extends Agent<Env> {
|
|
31
|
+
ai = createAI({ binding: this.env.AI });
|
|
32
|
+
registry = createRegistry();
|
|
36
33
|
|
|
37
|
-
|
|
34
|
+
harness = new PiHarness({
|
|
38
35
|
harness: ({ storage, context }) => {
|
|
39
36
|
const models = createModels();
|
|
40
37
|
models.setProvider(this.ai.provider);
|
|
@@ -45,47 +42,132 @@ export class Assistant extends DurableObject<Env> {
|
|
|
45
42
|
);
|
|
46
43
|
},
|
|
47
44
|
defaults: {
|
|
48
|
-
model:
|
|
49
|
-
|
|
50
|
-
modelId: "@cf/zai-org/glm-4.7-flash"
|
|
51
|
-
}
|
|
45
|
+
model: this.ai("@cf/zai-org/glm-4.7-flash"),
|
|
46
|
+
thinkingLevel: "low"
|
|
52
47
|
}
|
|
53
48
|
});
|
|
54
49
|
|
|
55
|
-
|
|
50
|
+
constructor(ctx: DurableObjectState, env: Env) {
|
|
51
|
+
super(ctx, env);
|
|
52
|
+
this.lifecycle.use(this.harness);
|
|
53
|
+
}
|
|
56
54
|
|
|
57
|
-
async prompt
|
|
58
|
-
return this.harness.prompt(
|
|
55
|
+
async ask(prompt: string) {
|
|
56
|
+
return (await this.harness.prompt(prompt)).text;
|
|
59
57
|
}
|
|
60
58
|
}
|
|
61
59
|
```
|
|
62
60
|
|
|
63
|
-
|
|
61
|
+
| Option | What it is |
|
|
62
|
+
| ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
63
|
+
| `harness` | Required. Receives `{ storage, context }` and returns Pi's `Harness`, usually from `Harness.open`. Models, the registry, `settings`, `env` and `onReport` are all yours to build here. |
|
|
64
|
+
| `defaults` | What a new session starts with: `model`, a pi-ai `Model` such as `ai("@cf/…")`, and `thinkingLevel`. Without a model, a session's prompts end unanswered (`no_model`) until one is set. |
|
|
65
|
+
|
|
66
|
+
The factory runs as part of startup, once per isolate. If it throws the operation that triggered it fails and the next operation tries again.
|
|
67
|
+
|
|
68
|
+
A model in `defaults` or `session.setModel()` is stored by its provider and id only. Pi resolves it at each request against the `Models` the factory opened Pi with, so it must be a model those `Models` list. Options passed to `ai(id, options)` there, such as `fallback`, are not applied.
|
|
69
|
+
|
|
70
|
+
## Add tools and prompt sections
|
|
71
|
+
|
|
72
|
+
Tools and system prompt sections are Pi extensions. An extension is a plain object with a `name`, `tools` and `sections`:
|
|
73
|
+
|
|
74
|
+
```ts
|
|
75
|
+
import { Type } from "@earendil-works/pi-ai";
|
|
76
|
+
import {
|
|
77
|
+
createRegistry,
|
|
78
|
+
type ToolRegistration
|
|
79
|
+
} from "@earendil-works/pi-durable";
|
|
80
|
+
|
|
81
|
+
const WordCount = Type.Object({ text: Type.String() });
|
|
82
|
+
|
|
83
|
+
const wordCount: ToolRegistration<typeof WordCount> = {
|
|
84
|
+
name: "word_count",
|
|
85
|
+
description: "Count the words in a text.",
|
|
86
|
+
parameters: WordCount,
|
|
87
|
+
// Pi may run it again after an eviction interrupted it.
|
|
88
|
+
replay: "safe",
|
|
89
|
+
// `text` is typed from `parameters` and is validated by Pi.
|
|
90
|
+
async execute({ text }) {
|
|
91
|
+
const words = text.split(/\s+/).filter(Boolean).length;
|
|
92
|
+
return { content: [{ type: "text", text: String(words) }] };
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
const registry = createRegistry();
|
|
97
|
+
registry.install({
|
|
98
|
+
name: "writing",
|
|
99
|
+
sections: [
|
|
100
|
+
{ key: "preamble", render: () => "You are an editor.", tag: false }
|
|
101
|
+
],
|
|
102
|
+
tools: [wordCount]
|
|
103
|
+
});
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
- **Tool arguments are typed from the schema.** Type a tool as `ToolRegistration<typeof Parameters>`; a bare `ToolRegistration` types its arguments as `unknown`.
|
|
107
|
+
- **Replay safety.** `replay: "safe"` lets Pi run a call again after an eviction cut it off. Otherwise the model gets an interrupted result instead of a second run. The default is `"unsafe"`.
|
|
108
|
+
- **What a running call can use.** `execute(args, api, context)` gets Pi's operations for the call: `api.output()` for running output, `api.details()` for a UI, and `api.memo()` for values that survive an eviction. `context.abortSignal` is aborted when the call is.
|
|
109
|
+
- **Sections.** A section's `render` runs before each request, with the conversation, its agent and offered tools, and committed reads. It is wrapped in `<key>` tags unless `tag` is `false`.
|
|
110
|
+
|
|
111
|
+
Pi's extensions can do more: hooks on model requests and tool calls (`hook(ToolTask, { beforeTool })`), durable tasks, wrapping another extension's tools, and choosing extensions per conversation. Refer to the [pi-durable README](https://github.com/earendil-works/pi/tree/main/packages/durable) for each. They all work on the registry `PiHarness` opens Pi with.
|
|
112
|
+
|
|
113
|
+
### Skills
|
|
64
114
|
|
|
65
|
-
`
|
|
115
|
+
`skills(sources)` turns `agents/skills` sources (refer to [Agent Skills](../../think/index.md#agent-skills)) into a Pi extension named `agents.skills`. It has two tools, `activate_skill` and `read_skill_resource`, and a `skills` section that lists the skills. Install it in the factory, since it reads the sources:
|
|
116
|
+
|
|
117
|
+
```ts
|
|
118
|
+
import { skills } from "agents/harness/pi";
|
|
119
|
+
|
|
120
|
+
harness: async ({ storage, context }) => {
|
|
121
|
+
this.registry.install(await skills(sources));
|
|
122
|
+
return Harness.open(storage, { models, registry: this.registry }, context);
|
|
123
|
+
};
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
The existing `@cloudflare/think` skills work out-of-the-box.
|
|
66
127
|
|
|
67
128
|
## Work with sessions
|
|
68
129
|
|
|
69
|
-
|
|
130
|
+
A session is a Pi conversation. Each has its own transcript, inbox, model and run, and they can run at the same time.
|
|
70
131
|
|
|
71
132
|
```ts
|
|
133
|
+
// The root session.
|
|
134
|
+
const { text } = await this.harness.prompt("What is 47 × 19?");
|
|
135
|
+
|
|
136
|
+
// Another session, on a cheaper model.
|
|
72
137
|
const session = await this.harness.sessions.create();
|
|
138
|
+
await session.setModel(this.ai("@cf/zai-org/glm-4.7-flash"));
|
|
139
|
+
|
|
140
|
+
// Durable once it returns; the same operation id twice is one submission.
|
|
73
141
|
const receipt = await session.submit("Summarize the latest report", {
|
|
74
142
|
operationId: "report-summary-42"
|
|
75
143
|
});
|
|
76
144
|
const result = await session.wait(receipt.operationId);
|
|
77
145
|
```
|
|
78
146
|
|
|
79
|
-
|
|
147
|
+
| Call | What it does |
|
|
148
|
+
| ------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
149
|
+
| `prompt(input)` | Submits and waits: the answer, and the transcript after it. |
|
|
150
|
+
| `submit(input, { operationId, whenBusy })` | Returns once Pi has durably accepted the input, before the model runs. A busy session queues it as a follow-up; `whenBusy: "steer"` joins the running work after its current tool round. |
|
|
151
|
+
| `wait(operationId, signal?)` | The operation's result once Pi settles it. Aborting `signal` stops only the wait, not the work. |
|
|
152
|
+
| `steer(input)` | `submit` with `whenBusy: "steer"`. |
|
|
153
|
+
| `abort(operationId?)` | Withdraws a queued operation, or with no id, stops everything running in the session. |
|
|
154
|
+
| `pending()` | Operations Pi has not settled yet: queued, or part of the running work. |
|
|
155
|
+
| `messages()` | Pi's transcript entries since the newest reset. |
|
|
156
|
+
| `events()` | Pi's agent events: a `snapshot`, then one batch per commit. |
|
|
157
|
+
| `reset(handoff?)` | Starts a new context, optionally from a handoff note. |
|
|
158
|
+
| `setModel(model)` | Changes this session's model. |
|
|
159
|
+
| `busy()` | Whether a run is going. |
|
|
160
|
+
|
|
161
|
+
`harness.prompt()`, `submit()`, `wait()`, `abort()`, `messages()` and `pending()` act on the root session, or on `{ session }`. `harness.sessions` has `create()`, `fork(from)`, `get(id)` and `list()`, which includes sessions subagents created. `ROOT_SESSION` is the root's id.
|
|
80
162
|
|
|
81
|
-
|
|
163
|
+
`messages()` and `events()` are Pi's own records, not a UI-ready chat transcript. The example below folds them into one.
|
|
82
164
|
|
|
83
165
|
## How recovery works
|
|
84
166
|
|
|
85
|
-
The harness schedules one lifecycle job
|
|
167
|
+
The harness schedules one lifecycle job per session with work. The job waits on Pi's tasks, refreshes itself as a heartbeat while they run, and completes when they settle. If the object is evicted or crashes, the job is still due, so its alarm restarts the object. Pi reopens its stored state and resumes the session's work: a replay-safe tool call runs again, and an unsafe one is reported to the model as interrupted.
|
|
86
168
|
|
|
87
|
-
|
|
169
|
+
Every operation waits for the object's startup, which runs the factory. A call over RPC that arrives first waits for it rather than opening Pi on its own.
|
|
88
170
|
|
|
89
171
|
## Run the example
|
|
90
172
|
|
|
91
|
-
The [Pi harness example](https://github.com/cloudflare/agents/tree/main/examples/next/harnesses/pi)
|
|
173
|
+
The [Pi harness example](https://github.com/cloudflare/agents/tree/main/examples/next/harnesses/pi) streams `session.events()` over WebSockets and folds Pi's entries into a browser transcript. Its tools come from a `Workspace` from `@cloudflare/computer`: files, `exec` for JavaScript in a Dynamic Worker, and git. It uses a Workers AI model.
|
package/docs/index.md
CHANGED
|
@@ -80,8 +80,8 @@ The differentiator is not "we have durable state" — it is what happens when a
|
|
|
80
80
|
- [Server-Driven Messages](./server-driven-messages.md) - Autonomous agent workflows: scheduled follow-ups, queue processing, webhooks, chained reasoning
|
|
81
81
|
- TODO: [Using AI Models](./using-ai-models.md) - OpenAI, Anthropic, Workers AI, and other providers
|
|
82
82
|
- [Models (Experimental)](./models.md) - `createAI` — one AI SDK provider for Workers AI and third-party catalog models, same string space
|
|
83
|
-
- [Models for pi-ai (
|
|
84
|
-
- [Pi harness (
|
|
83
|
+
- [Models for pi-ai (Beta)](./models-pi-ai.md) - `createAI` for pi-ai: Workers AI ids and third-party models through AI Gateway, as a pi-ai provider
|
|
84
|
+
- [Pi harness (Beta)](./harnesses/pi.md) - Host pi-durable sessions in a Durable Object with durable storage and lifecycle wakeups
|
|
85
85
|
- TODO: [RAG (Retrieval Augmented Generation)](./rag.md) - Vector search with Vectorize
|
|
86
86
|
- [Sessions (Experimental)](./sessions.md) - Durable message trees, streamed history, compaction, search, and lossless attachment offload
|
|
87
87
|
- [Context (Experimental)](./context.md) - System-prompt blocks, frozen prompts, writable/searchable/loadable providers, and their tools
|
package/docs/models-pi-ai.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Models for pi-ai (
|
|
1
|
+
# Models for pi-ai (Beta)
|
|
2
2
|
|
|
3
3
|
`agents/models/pi-ai` is the [pi-ai](https://github.com/earendil-works/pi/tree/main/packages/ai)
|
|
4
4
|
twin of [`agents/models/ai-sdk`](./models.md): the same `createAI` factory, the same options,
|
|
@@ -45,7 +45,7 @@ design: a model this package cannot name exactly is yours to construct.
|
|
|
45
45
|
store on the gateway (BYOK) — so nothing vendor-shaped needs a secret in your Worker.
|
|
46
46
|
4. **The binding is the only way in.** Workers AI goes through `env.AI.run`, vendor models
|
|
47
47
|
through `env.AI.gateway(id).run`; there is no HTTP transport and no API token to hold.
|
|
48
|
-
5. Everything here is
|
|
48
|
+
5. Everything here is in beta and may change in a minor release.
|
|
49
49
|
|
|
50
50
|
## Quick start
|
|
51
51
|
|
|
@@ -311,10 +311,10 @@ Image generation is Workers AI only. The knobs a model takes are the model's:
|
|
|
311
311
|
in a `cloudflare-compat` diagnostic on the result rather than sent and ignored.
|
|
312
312
|
Every other model in the catalog takes the full set.
|
|
313
313
|
|
|
314
|
-
##
|
|
314
|
+
## Beta
|
|
315
315
|
|
|
316
|
-
This subpath needs `@earendil-works/pi-ai@^0.
|
|
317
|
-
takes no vendor package as a dependency, optional or otherwise. The surface is
|
|
316
|
+
This subpath needs `@earendil-works/pi-ai@^1.0.0`, an optional peer of `agents`. `agents`
|
|
317
|
+
takes no vendor package as a dependency, optional or otherwise. The surface is in beta
|
|
318
318
|
and may change in a minor release. An unlisted `@cf/` id resolves with default metadata (a
|
|
319
319
|
128k context window, 8192 output tokens, zero cost); pass overrides when you know better.
|
|
320
320
|
|
package/package.json
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"durable objects"
|
|
10
10
|
],
|
|
11
11
|
"type": "module",
|
|
12
|
-
"version": "0.
|
|
12
|
+
"version": "0.26.0",
|
|
13
13
|
"license": "MIT",
|
|
14
14
|
"repository": {
|
|
15
15
|
"directory": "packages/agents",
|
|
@@ -40,8 +40,8 @@
|
|
|
40
40
|
"@ai-sdk/react": "^4.0.0",
|
|
41
41
|
"@ai-sdk/valibot": "3.0.6",
|
|
42
42
|
"@cloudflare/codemode": "^0.5.3",
|
|
43
|
-
"@earendil-works/pi-ai": "^0.
|
|
44
|
-
"@earendil-works/pi-durable": "^0.
|
|
43
|
+
"@earendil-works/pi-ai": "^1.0.0",
|
|
44
|
+
"@earendil-works/pi-durable": "^1.0.0",
|
|
45
45
|
"@modelcontextprotocol/client": "2.0.0",
|
|
46
46
|
"@modelcontextprotocol/conformance-v2": "npm:@modelcontextprotocol/conformance@0.2.0-alpha.10",
|
|
47
47
|
"@modelcontextprotocol/sdk": "1.30.0",
|
|
@@ -64,8 +64,8 @@
|
|
|
64
64
|
"@ai-sdk/provider": "^4.0.0",
|
|
65
65
|
"@ai-sdk/react": "^3.0.0 || ^4.0.0",
|
|
66
66
|
"@cloudflare/codemode": ">=0.5.0",
|
|
67
|
-
"@earendil-works/pi-ai": "^0.
|
|
68
|
-
"@earendil-works/pi-durable": "^0.
|
|
67
|
+
"@earendil-works/pi-ai": "^1.0.0",
|
|
68
|
+
"@earendil-works/pi-durable": "^1.0.0",
|
|
69
69
|
"@modelcontextprotocol/client": "2.0.0",
|
|
70
70
|
"@modelcontextprotocol/sdk": "1.30.0",
|
|
71
71
|
"@modelcontextprotocol/server": "2.0.0",
|
|
@@ -167,10 +167,10 @@
|
|
|
167
167
|
"import": "./dist/lifecycle/index.js",
|
|
168
168
|
"require": "./dist/lifecycle/index.js"
|
|
169
169
|
},
|
|
170
|
-
"./
|
|
171
|
-
"types": "./dist/
|
|
172
|
-
"import": "./dist/
|
|
173
|
-
"require": "./dist/
|
|
170
|
+
"./harness/pi": {
|
|
171
|
+
"types": "./dist/harness/pi/index.d.ts",
|
|
172
|
+
"import": "./dist/harness/pi/index.js",
|
|
173
|
+
"require": "./dist/harness/pi/index.js"
|
|
174
174
|
},
|
|
175
175
|
"./agent-tools": {
|
|
176
176
|
"types": "./dist/agent-tools.d.ts",
|
|
@@ -471,7 +471,7 @@
|
|
|
471
471
|
"test:browser": "vitest run --config src/browser-tests/vitest.config.ts",
|
|
472
472
|
"test:workers": "vitest --project workers",
|
|
473
473
|
"test:chat": "vitest --project chat",
|
|
474
|
-
"test:
|
|
474
|
+
"test:harness:pi": "vitest --project harness-pi",
|
|
475
475
|
"test:webmcp": "vitest --project webmcp",
|
|
476
476
|
"test:x402": "vitest --project x402",
|
|
477
477
|
"test:e2e": "vitest --run -c src/e2e-tests/vitest.config.ts",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../src/harnesses/pi/context.ts","../../../src/harnesses/pi/session-store.ts","../../../src/harnesses/pi/harness.ts","../../../src/harnesses/pi/skills.ts"],"sourcesContent":["import type { Harness } from \"@earendil-works/pi-durable\";\n\n/**\n * pi's invocation context, as `@earendil-works/chord` defines it.\n *\n * pi-durable takes a chord `Context` on every call but does not re-export\n * the type or its constructors. The harness needs only a background context\n * and a way to add an abort signal, so both are inlined here instead of\n * depending on chord directly. A chord `Context` is a plain structural\n * interface (an abort signal, keyed values, and a name), so these interoperate\n * with chord's own contexts inside pi.\n *\n * One limit: chord's own derived contexts read the abort signal through a\n * private key rather than `abortSignal`, so a chord `withContextValue`\n * wrapped around one of these would not see its signal. pi 0.99.2 never\n * wraps a caller's context that way; `withAbortSignal` and `withCancel`\n * read `abortSignal` and work.\n *\n * If pi-durable starts re-exporting chord's context helpers, replace this\n * file with those.\n */\nexport type Context = Parameters<Harness[\"close\"]>[0];\n\n/** chord's `BACKGROUND_CONTEXT`: no values, never cancelled. */\nexport const BACKGROUND_CONTEXT: Context = Object.freeze({\n abortSignal: undefined,\n value: () => undefined,\n toString: () => \"[Context pi-harness background]\"\n});\n\n/**\n * chord's `withAbortSignal`: a context cancelled by either the parent's\n * signal or `signal`, carrying the parent's values.\n */\nexport function withAbortSignal(signal: AbortSignal, parent: Context): Context {\n const abortSignal =\n parent.abortSignal === undefined\n ? signal\n : AbortSignal.any([parent.abortSignal, signal]);\n return Object.freeze({\n abortSignal,\n value: parent.value.bind(parent),\n toString: () => `${parent}.WithAbortSignal`\n });\n}\n","import {\n SQLITE_MIGRATIONS,\n SqliteStorage,\n type SqliteDatabase,\n type SqliteStatement,\n type SqliteValue\n} from \"@earendil-works/pi-durable/storage/sqlite\";\n\n/**\n * pi's session store on a Durable Object's SQLite database.\n *\n * pi owns its sessions: conversations, entries, tasks, submissions, and\n * documents live in pi's own schema, created and migrated by pi's portable\n * `SqliteStorage`. This file only supplies the synchronous database facade\n * pi asks for, over `ctx.storage.sql`, and moves pi's tables under a prefix\n * so they cannot collide with the SDK's or the host's tables in the same\n * object.\n *\n * It is the Durable Object counterpart of `agents/sessions` for a harness\n * that brings its own session model, and has nothing pi-harness specific in\n * it: any harness built on pi-durable can open its storage with it.\n */\nexport type PiSessionStoreOptions = {\n /**\n * Prefix for every table and index pi creates. Must not start with `_cf_`,\n * which Durable Objects reserve. Default `pi_`.\n */\n readonly prefix?: string;\n};\n\nconst DEFAULT_PREFIX = \"pi_\";\n\n/** Open pi-durable's storage over this object's SQLite database. */\nexport function openPiSessionStore(\n storage: DurableObjectStorage,\n options: PiSessionStoreOptions = {}\n): Promise<SqliteStorage> {\n return SqliteStorage.open(new DurableObjectSqliteDatabase(storage, options));\n}\n\n/** Names pi's migrations create: every table and index, in any version. */\nfunction schemaNames(): readonly string[] {\n const names = new Set<string>([\"durable_schema\"]);\n const pattern =\n /\\bCREATE\\s+(?:UNIQUE\\s+)?(?:TABLE|INDEX)\\s+(?:IF\\s+NOT\\s+EXISTS\\s+)?([A-Za-z_][A-Za-z0-9_]*)/gi;\n for (const migration of SQLITE_MIGRATIONS) {\n for (const statement of migration.statements) {\n for (const match of statement.matchAll(pattern)) names.add(match[1]);\n }\n }\n return [...names];\n}\n\n/**\n * Rewrites pi's schema identifiers outside string literals. Identifiers are\n * matched on word boundaries, so column names such as `record_type` or\n * `document_id` are left alone.\n */\nclass Prefixer {\n readonly #pattern: RegExp;\n readonly #prefix: string;\n readonly #cache = new Map<string, string>();\n\n constructor(prefix: string) {\n if (!/^[A-Za-z][A-Za-z0-9_]*$/.test(prefix)) {\n throw new Error(\n `Invalid pi session store prefix ${JSON.stringify(prefix)}`\n );\n }\n if (prefix.startsWith(\"_cf_\")) {\n throw new Error(\"The pi session store prefix must not start with _cf_\");\n }\n this.#prefix = prefix;\n this.#pattern = new RegExp(`\\\\b(${schemaNames().join(\"|\")})\\\\b`, \"g\");\n }\n\n rewrite(sql: string): string {\n const cached = this.#cache.get(sql);\n if (cached !== undefined) return cached;\n // Split on single-quoted literals ('' escapes stay inside a literal).\n const rewritten = sql\n .split(/('(?:[^']|'')*')/)\n .map((part, index) =>\n index % 2 === 1\n ? part\n : part.replace(this.#pattern, (name) => `${this.#prefix}${name}`)\n )\n .join(\"\");\n this.#cache.set(sql, rewritten);\n return rewritten;\n }\n}\n\n/** Durable Objects bind strings, numbers, null, and ArrayBuffers. */\nfunction binding(value: SqliteValue): SqlStorageValue {\n if (typeof value === \"bigint\") {\n if (\n value > BigInt(Number.MAX_SAFE_INTEGER) ||\n value < BigInt(Number.MIN_SAFE_INTEGER)\n ) {\n throw new RangeError(`SQLite integer ${value} is outside the safe range`);\n }\n return Number(value);\n }\n if (value instanceof Uint8Array) {\n return value.buffer.slice(\n value.byteOffset,\n value.byteOffset + value.byteLength\n ) as ArrayBuffer;\n }\n return value;\n}\n\n/** Blobs come back as ArrayBuffers; pi's contract reads Uint8Arrays. */\nfunction row<T extends object>(raw: Record<string, SqlStorageValue>): T {\n for (const key of Object.keys(raw)) {\n const value = raw[key];\n if (value instanceof ArrayBuffer) {\n (raw as Record<string, unknown>)[key] = new Uint8Array(value);\n }\n }\n return raw as T;\n}\n\nclass DurableObjectSqliteStatement implements SqliteStatement {\n readonly #sql: SqlStorage;\n readonly #query: string;\n\n constructor(sql: SqlStorage, query: string) {\n this.#sql = sql;\n this.#query = query;\n }\n\n run(...params: SqliteValue[]): void {\n this.#sql.exec(this.#query, ...params.map(binding));\n }\n\n get<T extends object>(...params: SqliteValue[]): T | undefined {\n const cursor = this.#sql.exec(this.#query, ...params.map(binding));\n const first = cursor.next();\n return first.done ? undefined : row<T>(first.value);\n }\n\n all<T extends object>(...params: SqliteValue[]): T[] {\n return this.#sql\n .exec(this.#query, ...params.map(binding))\n .toArray()\n .map((raw) => row<T>(raw));\n }\n}\n\n/**\n * pi's `SqliteDatabase` facade over `DurableObjectStorage`.\n *\n * Durable Objects reject `BEGIN`, so transactions go through\n * `transactionSync`, which rolls back when the callback throws and rethrows\n * the same error, as pi's contract requires. Durable Objects have no\n * prepared statements either; a statement is the query text, executed on\n * each call.\n */\nexport class DurableObjectSqliteDatabase implements SqliteDatabase {\n readonly #storage: DurableObjectStorage;\n readonly #prefixer: Prefixer;\n\n constructor(\n storage: DurableObjectStorage,\n options: PiSessionStoreOptions = {}\n ) {\n this.#storage = storage;\n this.#prefixer = new Prefixer(options.prefix ?? DEFAULT_PREFIX);\n }\n\n exec(sql: string): void {\n this.#storage.sql.exec(this.#prefixer.rewrite(sql));\n }\n\n prepare(sql: string): SqliteStatement {\n return new DurableObjectSqliteStatement(\n this.#storage.sql,\n this.#prefixer.rewrite(sql)\n );\n }\n\n transaction<T>(callback: () => T): T {\n return this.#storage.transactionSync(callback);\n }\n\n /** The object owns the database; there is nothing to close. */\n close(): void {}\n}\n","import type { ModelThinkingLevel } from \"@earendil-works/pi-ai\";\nimport {\n ConversationConfig,\n LiveDoc,\n ROOT_CONVERSATION_ID,\n watchEvents,\n type AgentEventStream,\n type Conversation,\n type Harness,\n type ConversationId,\n type ConversationRetryPolicy,\n type EntryRecord,\n type ModelRef,\n type SettledSubmissionRecord,\n type Tx,\n type UserInput\n} from \"@earendil-works/pi-durable\";\nimport type { SqliteStorage } from \"@earendil-works/pi-durable/storage/sqlite\";\nimport {\n LifecycleCapability,\n type CapabilityStartContext,\n type LifecycleJobContext,\n type LifecycleJobOutcome\n} from \"../../lifecycle\";\nimport { BACKGROUND_CONTEXT, withAbortSignal, type Context } from \"./context\";\nimport {\n openPiSessionStore,\n type PiSessionStoreOptions\n} from \"./session-store\";\nimport type {\n PiOperationResult,\n PiPendingOperation,\n PiPromptResponse,\n PiReceipt,\n PiSessionId,\n PiSessionInfo,\n PiSessionOptions,\n PiSubmitOptions\n} from \"./types\";\n\nconst BG = BACKGROUND_CONTEXT;\n\n/** The root session's id. */\nexport const ROOT_SESSION: PiSessionId = String(ROOT_CONVERSATION_ID);\n\n/**\n * Defaults for the three wake timings; a host overrides them with\n * `timing`, which is what the tests do to avoid the real heartbeat.\n *\n * A pi long wait further away than this is handed to the alarm, so the\n * alarm, not pi's in-memory timer, is what wakes the object.\n */\nconst SLEEP_THRESHOLD_MS = 60_000;\n\n/**\n * Longest one wake waits on pi. It waits inside an alarm invocation, which\n * has a 15 minute wall-time limit, so a longer run is waited on across\n * several alarms.\n */\nconst WAIT_BUDGET_MS = 10 * 60_000;\n\n/**\n * The wake job's heartbeat while it waits, and how often it re-checks work\n * it cannot wait on, such as background tasks. If the object is evicted, the\n * job is still due and its alarm restarts the object.\n */\nconst HEARTBEAT_MS = 30_000;\n\nconst WAKE_FN = \"wake\";\n\nfunction wakeJobId(session: PiSessionId): string {\n return `pi-wake:${session}`;\n}\n\nfunction sessionOfJob(payload: unknown): PiSessionId | undefined {\n return typeof payload === \"object\" &&\n payload !== null &&\n \"session\" in payload &&\n typeof payload.session === \"string\"\n ? payload.session\n : undefined;\n}\n\n/**\n * What the harness factory is handed. The store is already open and pi's\n * migrations have run, so a factory only has to decide how to call\n * `Harness.open` — or call something else that satisfies the same contract.\n */\nexport type PiHarnessContext = {\n /** pi's storage over this object's SQLite, tables under the store prefix. */\n readonly storage: SqliteStorage;\n /** Background context, for the open itself. */\n readonly context: Context;\n};\n\n/**\n * Builds pi's `Harness`. Return value is adopted as-is: the caller owns the\n * registry (tools, system prompt, hooks, skills), `models`, `env`,\n * `onReport` and anything else `HarnessOptions` grows.\n *\n * ```ts\n * harness: ({ storage, context }) =>\n * Harness.open(storage, { models, registry }, context)\n * ```\n */\nexport type PiHarnessFactory = (\n context: PiHarnessContext\n) => Harness | Promise<Harness>;\n\n/**\n * Applied to a session the first time it is created. Without a model, a\n * session's generation fails as unanswered until `session.setModel` sets one.\n */\nexport type PiSessionDefaults = {\n /** Model for new sessions. Change one session's with `session.setModel`. */\n readonly model?: ModelRef;\n readonly thinkingLevel?: ModelThinkingLevel;\n /** pi's generation retries for new sessions. */\n readonly retry?: ConversationRetryPolicy;\n};\n\n/**\n * How long the wake waits and when it hands a wait to the alarm. Defaults\n * suit a real deployment; a test shortens them so a suite does not sit on\n * the real heartbeat.\n */\nexport type PiWakeTiming = {\n /** A pi wait further away than this goes to the alarm. Default 60_000. */\n readonly sleepThresholdMs?: number;\n /** Longest one wake waits inside an alarm. Default 600_000. */\n readonly waitBudgetMs?: number;\n /** Heartbeat while waiting, and the re-check for background work. Default 30_000. */\n readonly heartbeatMs?: number;\n};\n\n/** `PiHarness`'s options. Only `harness`, which opens pi, is required. */\nexport type PiHarnessOptions = {\n /** Opens pi's `Harness` over the store this object prepared. */\n readonly harness: PiHarnessFactory;\n /** Applied to new sessions. */\n readonly defaults?: PiSessionDefaults;\n readonly store?: PiSessionStoreOptions;\n readonly timing?: PiWakeTiming;\n};\n\ntype Opened = {\n readonly pi: Harness;\n readonly storage: SqliteStorage;\n};\n\nfunction conversationId(session: PiSessionId): ConversationId {\n const id = Number(session);\n if (!Number.isSafeInteger(id) || id < 1) {\n throw new Error(`Invalid pi session ${JSON.stringify(session)}`);\n }\n return id as ConversationId;\n}\n\n/** The text of an assistant entry, for an operation's result. */\nfunction assistantText(entry: EntryRecord | undefined): string {\n const message = entry?.model?.[0];\n if (message?.role !== \"assistant\") return \"\";\n return message.content\n .map((part) => (part.type === \"text\" ? part.text : \"\"))\n .join(\"\");\n}\n\nfunction signalContext(signal: AbortSignal | undefined): Context {\n return signal ? withAbortSignal(signal, BG) : BG;\n}\n\n/**\n * pi-durable hosted in a Durable Object, behind a small harness interface:\n * `harness.prompt()`, `harness.sessions`, `harness.session(id)`. How a session reaches a\n * client (sockets, SSE, RPC) is the host's glue, built on `session.events()`.\n *\n * pi owns everything about a run: the transcript, the inbox of steers and\n * follow-ups, generation and tool tasks, retries, crash recovery, and the\n * live view. It keeps all of it in its own tables in this object's SQLite\n * database (see `session-store.ts`).\n *\n * What pi cannot do on a Durable Object is wake itself: its scheduler runs\n * in memory, and an evicted object has no memory. The harness is that wake,\n * with one Lifecycle job per session. Input goes to pi once, in `submit()`,\n * after the session's job is scheduled. The job waits while pi has live\n * tasks in the session, rescheduling itself as a heartbeat, and completes\n * when there are none. An eviction mid-run leaves the job due, so its alarm\n * restarts the object, pi reopens and resumes its own tasks, and the job\n * waits again.\n *\n * @experimental The API may change between releases.\n */\nexport class PiHarness extends LifecycleCapability {\n readonly sessions: PiSessions;\n readonly #options: PiHarnessOptions;\n /** In-memory waits on pi, per session, each inside an alarm's work. */\n readonly #waits = new Map<PiSessionId, Promise<void>>();\n /** Submissions between their wake and pi's admission, per session. */\n readonly #admitting = new Map<PiSessionId, number>();\n readonly #sleepThresholdMs: number;\n readonly #waitBudgetMs: number;\n readonly #heartbeatMs: number;\n #opening: Promise<Opened> | undefined;\n\n constructor(options: PiHarnessOptions) {\n super(\"pi-harness\");\n this.#options = options;\n this.#sleepThresholdMs =\n options.timing?.sleepThresholdMs ?? SLEEP_THRESHOLD_MS;\n this.#waitBudgetMs = options.timing?.waitBudgetMs ?? WAIT_BUDGET_MS;\n this.#heartbeatMs = options.timing?.heartbeatMs ?? HEARTBEAT_MS;\n for (const [name, value] of [\n [\"sleepThresholdMs\", this.#sleepThresholdMs],\n [\"waitBudgetMs\", this.#waitBudgetMs],\n [\"heartbeatMs\", this.#heartbeatMs]\n ] as const) {\n if (!Number.isFinite(value) || value <= 0) {\n throw new Error(`PiHarness timing.${name} must be a positive number`);\n }\n }\n this.sessions = new PiSessions(this);\n }\n\n // ── Lifecycle ────────────────────────────────────────────────────────────\n\n override async onStart(_context: CapabilityStartContext): Promise<void> {\n const { pi } = await this.#open();\n // Every session with live work gets a wake, including ones whose wake\n // failed out or that a subagent created without going through submit().\n const inspection = await pi.inspect(BG);\n const sessions = new Set(\n inspection.tasks.map((task) => String(task.record.conversationId))\n );\n for (const session of sessions) await this.#wake(session);\n }\n\n async onJob(\n context: LifecycleJobContext\n ): Promise<LifecycleJobOutcome | void> {\n if (context.job.fn !== WAKE_FN) return;\n const session = sessionOfJob(context.job.payload);\n if (session !== undefined) return this.#wakeStep(session);\n }\n\n /** Close pi's in-memory resources. Durable state is untouched. */\n async dispose(): Promise<void> {\n const opening = this.#opening;\n this.#opening = undefined;\n const opened = await opening?.catch(() => undefined);\n await opened?.pi.close(BG);\n }\n\n // ── The harness interface ────────────────────────────────────────────────\n\n /** A handle on one session. No I/O until you call it. */\n session(id: PiSessionId = ROOT_SESSION): PiSession {\n return new PiSession(this, id);\n }\n\n /** Submit a prompt and wait for its answer. */\n prompt(\n input: UserInput,\n options: PiSubmitOptions = {}\n ): Promise<PiPromptResponse> {\n return this.session(options.session).prompt(input, options);\n }\n\n /** Durably submit a prompt. Resolves before the model runs. */\n submit(input: UserInput, options: PiSubmitOptions = {}): Promise<PiReceipt> {\n return this.session(options.session).submit(input, options);\n }\n\n /** Stop one operation, or everything running in a session. */\n abort(\n options: PiSessionOptions & { readonly operationId?: string } = {}\n ): Promise<boolean> {\n return this.session(options.session).abort(options.operationId);\n }\n\n wait(\n operationId: string,\n options: PiSessionOptions & { readonly signal?: AbortSignal } = {}\n ): Promise<PiOperationResult> {\n return this.session(options.session).wait(operationId, options.signal);\n }\n\n /** The session's active transcript, as pi's entries. */\n messages(options: PiSessionOptions = {}): Promise<EntryRecord[]> {\n return this.session(options.session).messages();\n }\n\n /** Submissions pi has not settled yet, oldest first. */\n async pending(options: PiSessionOptions = {}): Promise<PiPendingOperation[]> {\n const { pi } = await this.#open();\n const id =\n options.session === undefined\n ? undefined\n : conversationId(options.session);\n return (await pi.inspect(BG)).submissions\n .filter(\n (record) =>\n record.requestId !== undefined &&\n (id === undefined || record.conversationId === id)\n )\n .map((record) => ({\n operationId: record.requestId as string,\n session: String(record.conversationId),\n status: record.status === \"queued\" ? \"queued\" : \"running\"\n }));\n }\n\n /** The opened pi Harness, for anything the interface does not cover. */\n async pi(): Promise<Harness> {\n return (await this.#open()).pi;\n }\n\n // ── Used by PiSession and PiSessions ─────────────────────────────────────\n\n /** @internal */\n async conversation(session: PiSessionId): Promise<Conversation> {\n const { pi } = await this.#open();\n const conversation = await pi.conversation(conversationId(session), BG);\n if (!conversation) throw new Error(`Unknown pi session ${session}`);\n return conversation;\n }\n\n /** @internal */\n async storage(): Promise<SqliteStorage> {\n return (await this.#open()).storage;\n }\n\n /** @internal Configure a new session like the root. */\n initSession(tx: Tx, id: ConversationId): Promise<void> {\n return this.#init(tx, id);\n }\n\n /** @internal */\n async enqueue(\n session: PiSessionId,\n input: UserInput,\n options: PiSubmitOptions\n ): Promise<PiReceipt> {\n const operationId = options.operationId ?? crypto.randomUUID();\n const { storage } = await this.#open();\n const conversation = await this.conversation(session);\n this.#admitting.set(session, (this.#admitting.get(session) ?? 0) + 1);\n let accepted: boolean;\n try {\n // 1. The wake first, so a job is scheduled before pi has the work.\n // If the object dies after pi admits the input, that job restarts\n // it. While this admission is in flight the step will not park.\n await this.#wake(session);\n // 2. The one admission. pi deduplicates by request id.\n accepted =\n (await storage.submissionByRequest(\n conversation.id,\n operationId,\n BG\n )) === undefined;\n await conversation.submit(\n {\n type: \"input\",\n content: input,\n whenBusy: options.whenBusy ?? \"followUp\",\n requestId: operationId\n },\n BG\n );\n } finally {\n const left = (this.#admitting.get(session) ?? 1) - 1;\n if (left === 0) this.#admitting.delete(session);\n else this.#admitting.set(session, left);\n }\n // 3. Step now, so the wake sees the work even if it just parked.\n await this.#wake(session);\n return { operationId, session, accepted };\n }\n\n /** @internal Withdraw a queued input, or abort the run it joined. */\n async withdraw(session: PiSessionId, operationId: string): Promise<boolean> {\n const { pi, storage } = await this.#open();\n const id = conversationId(session);\n const record = await storage.submissionByRequest(id, operationId, BG);\n if (!record || record.status === \"done\" || record.status === \"unanswered\") {\n return false;\n }\n const withdrawn = await pi.abortSubmission(record.id, BG, id);\n if (withdrawn === \"already_placed\") {\n await (await pi.conversation(id, BG))?.abort(BG);\n }\n return withdrawn !== \"settled\" && withdrawn !== \"not_found\";\n }\n\n /** @internal Wait for pi to settle an operation, by its request id. */\n async settled(\n session: PiSessionId,\n operationId: string,\n signal?: AbortSignal\n ): Promise<PiOperationResult> {\n const conversation = await this.conversation(session);\n const context = signalContext(signal);\n const submission = await this.#findSubmission(\n conversation.id,\n operationId,\n context\n );\n if (!submission) {\n return {\n operationId,\n session,\n status: \"unanswered\",\n reason: \"not_found\"\n };\n }\n return this.#result(\n session,\n operationId,\n await submission.wait(context),\n context\n );\n }\n\n // ── The wake ─────────────────────────────────────────────────────────────\n\n /** Schedule the session's wake job now, or pull it forward. */\n #wake(session: PiSessionId, time = Date.now()): Promise<unknown> {\n // A push made while the job is dispatching supersedes that dispatch's\n // outcome, so a submit is never lost to a wake that is completing.\n return this.lifecycle.jobs.push({\n id: wakeJobId(session),\n fn: WAKE_FN,\n time,\n payload: { session },\n singleflight: true,\n recoveryLoop: true\n });\n }\n\n /**\n * One run of a session's wake job. It never admits or replays anything:\n * it waits while pi has live tasks in the session and completes when it\n * has none. pi does all the work in between.\n */\n async #wakeStep(session: PiSessionId): Promise<LifecycleJobOutcome> {\n const heartbeat = { rescheduleAt: Date.now() + this.#heartbeatMs };\n if (this.#waits.has(session)) return heartbeat;\n const { pi } = await this.#open();\n const conversation = await pi.conversation(conversationId(session), BG);\n if (!conversation) return undefined;\n\n const tasks = (await pi.inspect(BG)).tasks.filter(\n (task) => task.record.conversationId === conversation.id\n );\n if (tasks.length === 0) {\n // A submit between its wake and pi's admission: check again later.\n return this.#admitting.has(session) ? heartbeat : undefined;\n }\n const wakeAt = await this.#longWait(pi, conversation.id, BG);\n if (wakeAt !== undefined) return { rescheduleAt: wakeAt };\n // Background tasks are outside the conversation's idle wait.\n if (tasks.every((task) => task.record.background)) return heartbeat;\n\n const wait = this.#waitForIdle(conversation).finally(() => {\n this.#waits.delete(session);\n // Re-check now: pi may have started more work, such as a follow-up.\n void this.#wake(session);\n });\n this.#waits.set(session, wait);\n // The wait runs past this dispatch, inside the alarm's work, so the\n // object stays alive for it. The heartbeat covers an eviction.\n this.lifecycle.trackAlarmWork(wait);\n return heartbeat;\n }\n\n async #waitForIdle(conversation: Conversation): Promise<void> {\n const budget = new AbortController();\n const timer = setTimeout(() => budget.abort(), this.#waitBudgetMs);\n try {\n // Cancelling the wait never cancels pi's work.\n await conversation.waitForIdle(withAbortSignal(budget.signal, BG));\n } catch (error) {\n if (!budget.signal.aborted) {\n this.lifecycle.events.emit(\"pi:wake_error\", {\n session: String(conversation.id),\n error: error instanceof Error ? error.message : String(error)\n });\n }\n } finally {\n clearTimeout(timer);\n }\n }\n\n // ── pi ───────────────────────────────────────────────────────────────────\n\n #open(): Promise<Opened> {\n this.#opening ??= this.#doOpen().catch((error: unknown) => {\n this.#opening = undefined;\n throw error;\n });\n return this.#opening;\n }\n\n async #doOpen(): Promise<Opened> {\n const storage = await openPiSessionStore(\n this.lifecycle.storage,\n this.#options.store\n );\n const pi = await this.#options.harness({ storage, context: BG });\n await pi.root(BG, { init: (tx, id) => this.#init(tx, id) });\n // Continue whatever the last isolate left: pi reconciles tasks that were\n // running to pending and schedules them again.\n pi.resume();\n return { pi, storage };\n }\n\n async #init(tx: Tx, id: ConversationId): Promise<void> {\n const config = await tx.doc(ConversationConfig, id);\n const defaults = this.#options.defaults;\n if (defaults?.model) config.model = { ...defaults.model };\n if (defaults?.thinkingLevel) config.thinkingLevel = defaults.thinkingLevel;\n if (defaults?.retry) config.retry = { ...defaults.retry };\n }\n\n async #findSubmission(\n id: ConversationId,\n operationId: string,\n context: Context\n ) {\n const { pi, storage } = await this.#open();\n // Read from pi's storage: the Harness only reacquires submissions by id.\n const record = await storage.submissionByRequest(id, operationId, context);\n return record ? pi.submission(record.id, context) : undefined;\n }\n\n /** When pi's current wait is far enough away to hand to the alarm. */\n async #longWait(\n pi: Harness,\n id: ConversationId,\n context: Context\n ): Promise<number | undefined> {\n const live = await pi.snapshot(LiveDoc, id, context);\n const at =\n live?.generation?.deferred?.pollAt ?? live?.generation?.retry?.at;\n return at !== undefined && at - Date.now() > this.#sleepThresholdMs\n ? at\n : undefined;\n }\n\n async #result(\n session: PiSessionId,\n operationId: string,\n settled: SettledSubmissionRecord,\n context: Context\n ): Promise<PiOperationResult> {\n if (settled.status === \"unanswered\") {\n return {\n operationId,\n session,\n status: \"unanswered\",\n reason: settled.reason\n };\n }\n if (settled.type !== \"input\")\n return { operationId, session, status: \"done\" };\n const conversation = await this.conversation(session);\n const page = await conversation.entries(\n { minEntryId: settled.answer, maxEntryId: settled.answer },\n 1,\n undefined,\n context\n );\n return {\n operationId,\n session,\n status: \"done\",\n text: assistantText(page.items[0])\n };\n }\n}\n\n/** One pi conversation, addressed through the harness. */\nexport class PiSession {\n readonly #harness: PiHarness;\n readonly id: PiSessionId;\n\n constructor(harness: PiHarness, id: PiSessionId) {\n this.#harness = harness;\n this.id = id;\n }\n\n /** Durably submit a prompt. Resolves before the model runs. */\n submit(input: UserInput, options: PiSubmitOptions = {}): Promise<PiReceipt> {\n return this.#harness.enqueue(this.id, input, options);\n }\n\n /** Submit and wait for the answer and the updated transcript. */\n async prompt(\n input: UserInput,\n options: PiSubmitOptions = {}\n ): Promise<PiPromptResponse> {\n const receipt = await this.submit(input, options);\n const result = await this.wait(receipt.operationId);\n return { ...result, messages: await this.messages() };\n }\n\n /** Join the running work after its current tool round. */\n steer(input: UserInput, options: Omit<PiSubmitOptions, \"whenBusy\"> = {}) {\n return this.submit(input, { ...options, whenBusy: \"steer\" });\n }\n\n /** Wait for an operation to settle. Aborting `signal` stops only the wait. */\n wait(operationId: string, signal?: AbortSignal): Promise<PiOperationResult> {\n return this.#harness.settled(this.id, operationId, signal);\n }\n\n /**\n * Withdraw one queued operation (or abort the run it joined), or, with no\n * id, abort the session: pi withdraws queued inputs and aborts the\n * running work.\n */\n async abort(operationId?: string): Promise<boolean> {\n if (operationId !== undefined) {\n return this.#harness.withdraw(this.id, operationId);\n }\n const conversation = await this.#harness.conversation(this.id);\n await conversation.abort(BG);\n return true;\n }\n\n /** Start a new context, optionally from a handoff note. */\n async reset(handoff?: string): Promise<void> {\n await (await this.#harness.conversation(this.id)).reset(handoff, BG);\n }\n\n async setModel(model: ModelRef): Promise<void> {\n await (await this.#harness.conversation(this.id)).setModel(model, BG);\n }\n\n /** The active transcript, as pi's entries since the newest reset. */\n async messages(): Promise<EntryRecord[]> {\n const view = await (await this.#harness.conversation(this.id)).context(BG);\n return [...view.entries];\n }\n\n /** pi's agent events for this session: a snapshot, then one batch per commit. */\n async events(context: Context = BG): Promise<AgentEventStream> {\n const pi = await this.#harness.pi();\n return watchEvents(pi, conversationId(this.id), context);\n }\n\n async busy(): Promise<boolean> {\n const pi = await this.#harness.pi();\n const live = await pi.snapshot(LiveDoc, conversationId(this.id), BG);\n return live?.run !== undefined;\n }\n}\n\n/** Every pi conversation in this object. */\nexport class PiSessions {\n readonly #harness: PiHarness;\n\n constructor(harness: PiHarness) {\n this.#harness = harness;\n }\n\n get(id: PiSessionId): PiSession {\n return this.#harness.session(id);\n }\n\n /** A new top-level session, configured like the root. */\n async create(): Promise<PiSession> {\n const pi = await this.#harness.pi();\n const conversation = await pi.createConversation(\n {\n ownership: { kind: \"ownerless\" },\n init: (tx, id) => this.#harness.initSession(tx, id)\n },\n BG\n );\n return this.#harness.session(String(conversation.id));\n }\n\n /** A new session that sees `from`'s history up to its newest entry. */\n async fork(from: PiSessionId): Promise<PiSession> {\n const conversation = await this.#harness.conversation(from);\n const newest = await conversation.entries({}, 1, undefined, BG);\n const at = newest.items[0];\n if (!at) throw new Error(`Session ${from} has no entries to fork from`);\n const fork = await conversation.fork(\n at.id,\n { ownership: { kind: \"ownerless\" } },\n BG\n );\n return this.#harness.session(String(fork.id));\n }\n\n /**\n * Every conversation, including ones subagent tools own. Read from pi's\n * storage directly: the Harness has no conversation listing.\n */\n async list(): Promise<PiSessionInfo[]> {\n const storage = await this.#harness.storage();\n const pi = await this.#harness.pi();\n const sessions: PiSessionInfo[] = [];\n let cursor: Parameters<SqliteStorage[\"scanConversations\"]>[2];\n for (;;) {\n const page = await storage.scanConversations({}, 100, cursor, BG);\n for (const record of page.items) {\n const live = await pi.snapshot(LiveDoc, record.id, BG);\n sessions.push({\n id: String(record.id),\n ...(record.parent\n ? { parent: String(record.parent.conversationId) }\n : {}),\n busy: live?.run !== undefined\n });\n }\n if (page.next === undefined) return sessions;\n cursor = page.next;\n }\n }\n}\n","import type { JsonValue } from \"@earendil-works/pi-ai\";\nimport { Type } from \"@earendil-works/pi-ai\";\nimport type {\n Registry,\n ToolExecutionResult,\n ToolRegistration\n} from \"@earendil-works/pi-durable\";\nimport type {\n SkillContent,\n SkillDescriptor,\n SkillResourceDescriptor,\n SkillSource\n} from \"../../skills\";\n\n/** Skills resolved from `agents/skills` sources for one process lifetime. */\nexport type ResolvedSkills = {\n /** Changes when any source's fingerprint changes. */\n readonly fingerprint: string;\n /** Model-facing activation tools; empty when there are no skills. */\n readonly tools: readonly ToolRegistration[];\n /** System-prompt catalog, or null when there are no skills. */\n readonly catalog: string | null;\n readonly warnings: readonly string[];\n};\n\ntype ResolvedSkill = {\n readonly descriptor: SkillDescriptor;\n readonly content: SkillContent;\n readonly source: SkillSource;\n};\n\nexport function skillsFingerprint(sources: readonly SkillSource[]): string {\n return sources\n .map((source) => `${source.id}:${source.fingerprint}`)\n .join(\"|\");\n}\n\nfunction textResult(text: string): ToolExecutionResult {\n return { content: [{ type: \"text\", text }] };\n}\n\n/** pi validates arguments against the schema before `execute` runs. */\nfunction argsOf<T>(args: JsonValue): T {\n return args as T;\n}\n\nfunction attributes(\n pairs: ReadonlyArray<readonly [string, string | undefined]>\n) {\n return pairs\n .filter((pair): pair is readonly [string, string] => pair[1] !== undefined)\n .map(([key, value]) => ` ${key}=\"${value.replace(/\"/g, \""\")}\"`)\n .join(\"\");\n}\n\nfunction describeResource(resource: SkillResourceDescriptor): string {\n const details = [\n resource.kind,\n resource.encoding ?? \"text\",\n resource.mimeType,\n resource.size === undefined ? undefined : `${resource.size} bytes`\n ].filter((value): value is string => value !== undefined);\n return `- ${resource.path} (${details.join(\", \")})`;\n}\n\nfunction renderSkillContent(skill: ResolvedSkill): string {\n const resources = skill.content.resources ?? [];\n const lines = [\n `<skill_content${attributes([\n [\"name\", skill.descriptor.name],\n [\"version\", skill.descriptor.version]\n ])}>`,\n skill.content.body.trim()\n ];\n if (resources.length > 0) {\n lines.push(\"<skill_resources>\");\n for (const resource of resources) {\n lines.push(\n ` <file${attributes([\n [\"kind\", resource.kind],\n [\"encoding\", resource.encoding ?? \"text\"],\n [\n \"size\",\n resource.size === undefined ? undefined : String(resource.size)\n ]\n ])}>${resource.path}</file>`\n );\n }\n lines.push(\"</skill_resources>\");\n }\n lines.push(\"</skill_content>\", \"\");\n lines.push(\n resources.length === 0\n ? \"No bundled resources.\"\n : [\"Bundled resources:\", ...resources.map(describeResource)].join(\"\\n\")\n );\n return lines.join(\"\\n\");\n}\n\n/**\n * Resolve `agents/skills` sources into a system-prompt catalog and two\n * tools.\n *\n * The first source to list a name wins, as in `SkillRegistry`. pi-durable\n * has no skill concept of its own, so the model activates skills through\n * `activate_skill` and reads bundled files through `read_skill_resource` —\n * the same tools `@cloudflare/think` offers, so skills authored for one\n * framework work in the other.\n */\nexport async function resolveSkillSources(\n sources: readonly SkillSource[]\n): Promise<ResolvedSkills> {\n const fingerprint = skillsFingerprint(sources);\n const warnings: string[] = [];\n const resolved = new Map<string, ResolvedSkill>();\n for (const source of sources) {\n let descriptors: SkillDescriptor[];\n try {\n descriptors = await source.list();\n } catch (error) {\n warnings.push(\n `Skill source \"${source.id}\" failed to list skills: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n continue;\n }\n for (const descriptor of descriptors) {\n if (resolved.has(descriptor.name)) {\n warnings.push(\n `Skill \"${descriptor.name}\" from source \"${source.id}\" is shadowed by an earlier source`\n );\n continue;\n }\n let content: SkillContent | null;\n try {\n content = await source.load(descriptor.name);\n } catch (error) {\n warnings.push(\n `Skill \"${descriptor.name}\" from source \"${source.id}\" failed to load: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n continue;\n }\n if (!content) continue;\n resolved.set(descriptor.name, { descriptor, content, source });\n }\n }\n\n const visible = [...resolved.values()].filter(\n (skill) => skill.descriptor.metadata?.[\"disable-model-invocation\"] !== true\n );\n if (visible.length === 0) {\n return { fingerprint, tools: [], catalog: null, warnings };\n }\n\n const names = visible.map((skill) => skill.descriptor.name);\n const nameSchema = Type.Union(names.map((name) => Type.Literal(name)));\n const byName = new Map(\n visible.map((skill) => [skill.descriptor.name, skill])\n );\n\n const activateParameters = Type.Object({ name: nameSchema });\n const activateSkill: ToolRegistration = {\n name: \"activate_skill\",\n description:\n \"Activate a skill by name. Use this when the user's task matches one of the available skills; the response contains the skill's full instructions.\",\n parameters: activateParameters,\n replay: \"safe\",\n async execute(args) {\n const input = argsOf<{ name: string }>(args);\n const skill = byName.get(input.name);\n return textResult(\n skill ? renderSkillContent(skill) : `Skill not found: ${input.name}`\n );\n }\n };\n\n const resourceParameters = Type.Object({\n name: Type.Optional(nameSchema),\n path: Type.String({ minLength: 1 })\n });\n const readResource: ToolRegistration = {\n name: \"read_skill_resource\",\n description:\n \"Read a file bundled with a skill, such as a reference document or template. Provide the skill name and the file's path from the skill's resource list.\",\n parameters: resourceParameters,\n replay: \"safe\",\n async execute(args) {\n const input = argsOf<{ name?: string; path: string }>(args);\n const target = resolveResourceTarget(byName, input.name, input.path);\n if (!target) {\n return textResult(\n `Skill resource not found: ${input.name ? `${input.name}/` : \"\"}${input.path}`\n );\n }\n const resource = await target.skill.source\n .readResource?.(target.skill.descriptor.name, target.path)\n .catch(() => null);\n if (!resource) {\n return textResult(\n `Skill resource not found: ${target.skill.descriptor.name}/${target.path}`\n );\n }\n return textResult(\n [\n `<skill_resource${attributes([\n [\"name\", target.skill.descriptor.name],\n [\"path\", resource.path],\n [\"kind\", resource.kind],\n [\"encoding\", resource.encoding ?? \"text\"],\n [\"mimeType\", resource.mimeType]\n ])}>`,\n resource.content,\n \"</skill_resource>\"\n ].join(\"\\n\")\n );\n }\n };\n\n const catalog = [\n \"Available skills. When a task matches a skill, use activate_skill with its name before proceeding.\",\n \"\",\n ...visible.map(\n (skill) => `- ${skill.descriptor.name}: ${skill.descriptor.description}`\n )\n ].join(\"\\n\");\n\n return {\n fingerprint,\n tools: [activateSkill, readResource],\n catalog,\n warnings\n };\n}\n\nfunction resolveResourceTarget(\n byName: ReadonlyMap<string, ResolvedSkill>,\n name: string | undefined,\n path: string\n): { readonly skill: ResolvedSkill; readonly path: string } | undefined {\n if (path.split(\"/\").some((segment) => segment === \"..\")) return undefined;\n if (name !== undefined) {\n const skill = byName.get(name);\n return skill && hasResource(skill, path) ? { skill, path } : undefined;\n }\n // A qualified path names the skill in its first segment.\n const [head, ...rest] = path.split(\"/\");\n const skill = head === undefined ? undefined : byName.get(head);\n const relative = rest.join(\"/\");\n return skill && relative && hasResource(skill, relative)\n ? { skill, path: relative }\n : undefined;\n}\n\nfunction hasResource(skill: ResolvedSkill, path: string): boolean {\n return (skill.content.resources ?? []).some(\n (resource) => resource.path === path\n );\n}\n\n/**\n * Register `agents/skills` sources on a pi registry: the activation tools\n * and a \"skills\" system prompt section. Resolution reads the sources, so a\n * host awaits this in its `harness` factory, before `Harness.open`.\n */\nexport async function addSkills(\n registry: Registry,\n sources: readonly SkillSource[]\n): Promise<ResolvedSkills> {\n const resolved = await resolveSkillSources(sources);\n for (const warning of resolved.warnings) {\n console.warn(`pi skills: ${warning}`);\n }\n const catalog = resolved.catalog;\n registry.batch(() => {\n for (const tool of resolved.tools) registry.tools.add(tool);\n if (catalog) registry.systemPrompt.section(\"skills\", () => catalog);\n });\n return resolved;\n}\n"],"mappings":"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"}
|