@earendil-works/pi-durable 1.3.0 → 1.5.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/CHANGELOG.md +227 -0
- package/README.md +287 -82
- package/dist/codemode/codemode.d.ts +4 -4
- package/dist/codemode/codemode.d.ts.map +1 -1
- package/dist/codemode/codemode.js +21 -16
- package/dist/codemode/codemode.js.map +1 -1
- package/dist/codemode/models.d.ts.map +1 -1
- package/dist/codemode/models.js +6 -4
- package/dist/codemode/models.js.map +1 -1
- package/dist/documents.d.ts +1 -1
- package/dist/documents.d.ts.map +1 -1
- package/dist/documents.js.map +1 -1
- package/dist/env/index.d.ts +12 -10
- package/dist/env/index.d.ts.map +1 -1
- package/dist/env/index.js.map +1 -1
- package/dist/env/node-watch.d.ts +3 -3
- package/dist/env/node-watch.d.ts.map +1 -1
- package/dist/env/node-watch.js +18 -16
- package/dist/env/node-watch.js.map +1 -1
- package/dist/env/node.d.ts +2 -2
- package/dist/env/node.d.ts.map +1 -1
- package/dist/env/node.js +12 -4
- package/dist/env/node.js.map +1 -1
- package/dist/errors.d.ts +18 -2
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +26 -3
- package/dist/errors.js.map +1 -1
- package/dist/harness/agent.d.ts +13 -2
- package/dist/harness/agent.d.ts.map +1 -1
- package/dist/harness/agent.js +48 -6
- package/dist/harness/agent.js.map +1 -1
- package/dist/harness/compaction.d.ts +3 -1
- package/dist/harness/compaction.d.ts.map +1 -1
- package/dist/harness/compaction.js +38 -6
- package/dist/harness/compaction.js.map +1 -1
- package/dist/harness/context.d.ts +23 -7
- package/dist/harness/context.d.ts.map +1 -1
- package/dist/harness/context.js +71 -25
- package/dist/harness/context.js.map +1 -1
- package/dist/harness/define.d.ts +7 -3
- package/dist/harness/define.d.ts.map +1 -1
- package/dist/harness/define.js +4 -0
- package/dist/harness/define.js.map +1 -1
- package/dist/harness/generation.d.ts +38 -5
- package/dist/harness/generation.d.ts.map +1 -1
- package/dist/harness/generation.js +497 -108
- package/dist/harness/generation.js.map +1 -1
- package/dist/harness/harness.d.ts +7 -2
- package/dist/harness/harness.d.ts.map +1 -1
- package/dist/harness/harness.js +147 -57
- package/dist/harness/harness.js.map +1 -1
- package/dist/harness/inbox.d.ts +7 -3
- package/dist/harness/inbox.d.ts.map +1 -1
- package/dist/harness/inbox.js +7 -4
- package/dist/harness/inbox.js.map +1 -1
- package/dist/harness/json.d.ts +20 -4
- package/dist/harness/json.d.ts.map +1 -1
- package/dist/harness/json.js +23 -5
- package/dist/harness/json.js.map +1 -1
- package/dist/harness/live.d.ts +122 -16
- package/dist/harness/live.d.ts.map +1 -1
- package/dist/harness/live.js +93 -12
- package/dist/harness/live.js.map +1 -1
- package/dist/harness/partial-changes.d.ts +54 -0
- package/dist/harness/partial-changes.d.ts.map +1 -0
- package/dist/harness/partial-changes.js +162 -0
- package/dist/harness/partial-changes.js.map +1 -0
- package/dist/harness/prompt.d.ts +1 -1
- package/dist/harness/prompt.d.ts.map +1 -1
- package/dist/harness/prompt.js +1 -1
- package/dist/harness/prompt.js.map +1 -1
- package/dist/harness/registry-reader.d.ts +11 -0
- package/dist/harness/registry-reader.d.ts.map +1 -0
- package/dist/harness/registry-reader.js +25 -0
- package/dist/harness/registry-reader.js.map +1 -0
- package/dist/harness/scheduler.d.ts +86 -14
- package/dist/harness/scheduler.d.ts.map +1 -1
- package/dist/harness/scheduler.js +1459 -369
- package/dist/harness/scheduler.js.map +1 -1
- package/dist/harness/submissions.d.ts +23 -11
- package/dist/harness/submissions.d.ts.map +1 -1
- package/dist/harness/submissions.js +104 -36
- package/dist/harness/submissions.js.map +1 -1
- package/dist/harness/task-graph.d.ts +28 -8
- package/dist/harness/task-graph.d.ts.map +1 -1
- package/dist/harness/task-graph.js +85 -36
- package/dist/harness/task-graph.js.map +1 -1
- package/dist/harness/telemetry.d.ts +307 -0
- package/dist/harness/telemetry.d.ts.map +1 -0
- package/dist/harness/telemetry.js +136 -0
- package/dist/harness/telemetry.js.map +1 -0
- package/dist/harness/tool.d.ts +2 -0
- package/dist/harness/tool.d.ts.map +1 -1
- package/dist/harness/tool.js +223 -61
- package/dist/harness/tool.js.map +1 -1
- package/dist/harness/transcript.d.ts +72 -0
- package/dist/harness/transcript.d.ts.map +1 -0
- package/dist/harness/transcript.js +264 -0
- package/dist/harness/transcript.js.map +1 -0
- package/dist/harness/types.d.ts +302 -48
- package/dist/harness/types.d.ts.map +1 -1
- package/dist/harness/types.js.map +1 -1
- package/dist/harness/util.d.ts +7 -1
- package/dist/harness/util.d.ts.map +1 -1
- package/dist/harness/util.js +13 -0
- package/dist/harness/util.js.map +1 -1
- package/dist/harness/view.d.ts +43 -22
- package/dist/harness/view.d.ts.map +1 -1
- package/dist/harness/view.js +130 -71
- package/dist/harness/view.js.map +1 -1
- package/dist/index.d.ts +13 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -5
- package/dist/index.js.map +1 -1
- package/dist/search.d.ts +19 -3
- package/dist/search.d.ts.map +1 -1
- package/dist/search.js +107 -44
- package/dist/search.js.map +1 -1
- package/dist/session/cached-storage.d.ts +71 -0
- package/dist/session/cached-storage.d.ts.map +1 -0
- package/dist/session/cached-storage.js +269 -0
- package/dist/session/cached-storage.js.map +1 -0
- package/dist/session/conversation-tails.d.ts +33 -0
- package/dist/session/conversation-tails.d.ts.map +1 -0
- package/dist/session/conversation-tails.js +101 -0
- package/dist/session/conversation-tails.js.map +1 -0
- package/dist/session/keys.d.ts +68 -0
- package/dist/session/keys.d.ts.map +1 -0
- package/dist/session/keys.js +161 -0
- package/dist/session/keys.js.map +1 -0
- package/dist/session/session.d.ts +181 -29
- package/dist/session/session.d.ts.map +1 -1
- package/dist/session/session.js +1073 -183
- package/dist/session/session.js.map +1 -1
- package/dist/session/transaction.d.ts +86 -4
- package/dist/session/transaction.d.ts.map +1 -1
- package/dist/session/transaction.js +250 -38
- package/dist/session/transaction.js.map +1 -1
- package/dist/session/writer.d.ts +74 -0
- package/dist/session/writer.d.ts.map +1 -0
- package/dist/session/writer.js +294 -0
- package/dist/session/writer.js.map +1 -0
- package/dist/storage/indexeddb.d.ts +68 -0
- package/dist/storage/indexeddb.d.ts.map +1 -0
- package/dist/storage/indexeddb.js +881 -0
- package/dist/storage/indexeddb.js.map +1 -0
- package/dist/storage/jsonl/storage.d.ts +30 -2
- package/dist/storage/jsonl/storage.d.ts.map +1 -1
- package/dist/storage/jsonl/storage.js +88 -24
- package/dist/storage/jsonl/storage.js.map +1 -1
- package/dist/storage/memory.d.ts +7 -2
- package/dist/storage/memory.d.ts.map +1 -1
- package/dist/storage/memory.js +29 -3
- package/dist/storage/memory.js.map +1 -1
- package/dist/storage/sqlite/cloudflare.d.ts +2 -51
- package/dist/storage/sqlite/cloudflare.d.ts.map +1 -1
- package/dist/storage/sqlite/cloudflare.js +2 -133
- package/dist/storage/sqlite/cloudflare.js.map +1 -1
- package/dist/storage/sqlite/database.d.ts +1 -36
- package/dist/storage/sqlite/database.d.ts.map +1 -1
- package/dist/storage/sqlite/database.js.map +1 -1
- package/dist/storage/sqlite/index.d.ts +1 -1
- package/dist/storage/sqlite/index.d.ts.map +1 -1
- package/dist/storage/sqlite/index.js.map +1 -1
- package/dist/storage/sqlite/migrations.d.ts +2 -5
- package/dist/storage/sqlite/migrations.d.ts.map +1 -1
- package/dist/storage/sqlite/migrations.js +28 -28
- package/dist/storage/sqlite/migrations.js.map +1 -1
- package/dist/storage/sqlite/node.d.ts +2 -37
- package/dist/storage/sqlite/node.d.ts.map +1 -1
- package/dist/storage/sqlite/node.js +3 -174
- package/dist/storage/sqlite/node.js.map +1 -1
- package/dist/storage/sqlite/schema.d.ts +1 -3
- package/dist/storage/sqlite/schema.d.ts.map +1 -1
- package/dist/storage/sqlite/schema.js +2 -9
- package/dist/storage/sqlite/schema.js.map +1 -1
- package/dist/storage/sqlite/storage.d.ts +15 -3
- package/dist/storage/sqlite/storage.d.ts.map +1 -1
- package/dist/storage/sqlite/storage.js +110 -36
- package/dist/storage/sqlite/storage.js.map +1 -1
- package/dist/storage/store/commit.d.ts +33 -0
- package/dist/storage/store/commit.d.ts.map +1 -0
- package/dist/storage/store/commit.js +286 -0
- package/dist/storage/store/commit.js.map +1 -0
- package/dist/storage/store/documents.d.ts +43 -0
- package/dist/storage/store/documents.d.ts.map +1 -0
- package/dist/storage/store/documents.js +102 -0
- package/dist/storage/store/documents.js.map +1 -0
- package/dist/storage/store/index.d.ts +2 -0
- package/dist/storage/store/index.d.ts.map +1 -0
- package/dist/storage/store/index.js +2 -0
- package/dist/storage/store/index.js.map +1 -0
- package/dist/storage/store/queries.d.ts +49 -0
- package/dist/storage/store/queries.d.ts.map +1 -0
- package/dist/storage/store/queries.js +93 -0
- package/dist/storage/store/queries.js.map +1 -0
- package/dist/storage/store/storage.d.ts +59 -0
- package/dist/storage/store/storage.d.ts.map +1 -0
- package/dist/storage/store/storage.js +438 -0
- package/dist/storage/store/storage.js.map +1 -0
- package/dist/storage/store/tables.d.ts +54 -0
- package/dist/storage/store/tables.d.ts.map +1 -0
- package/dist/storage/store/tables.js +108 -0
- package/dist/storage/store/tables.js.map +1 -0
- package/dist/testing/commit-writes.d.ts +5 -0
- package/dist/testing/commit-writes.d.ts.map +1 -0
- package/dist/testing/commit-writes.js +12 -0
- package/dist/testing/commit-writes.js.map +1 -0
- package/dist/testing/env-conformance.js +7 -7
- package/dist/testing/env-conformance.js.map +1 -1
- package/dist/testing/index.d.ts +1 -0
- package/dist/testing/index.d.ts.map +1 -1
- package/dist/testing/index.js +1 -0
- package/dist/testing/index.js.map +1 -1
- package/dist/testing/storage-benchmark.d.ts.map +1 -1
- package/dist/testing/storage-benchmark.js +18 -17
- package/dist/testing/storage-benchmark.js.map +1 -1
- package/dist/testing/storage-conformance.d.ts.map +1 -1
- package/dist/testing/storage-conformance.js +369 -67
- package/dist/testing/storage-conformance.js.map +1 -1
- package/dist/timers.d.ts +21 -0
- package/dist/timers.d.ts.map +1 -0
- package/dist/timers.js +72 -0
- package/dist/timers.js.map +1 -0
- package/dist/tool-search/tool-search.d.ts +6 -12
- package/dist/tool-search/tool-search.d.ts.map +1 -1
- package/dist/tool-search/tool-search.js +7 -7
- package/dist/tool-search/tool-search.js.map +1 -1
- package/dist/tools/bash.d.ts +12 -12
- package/dist/tools/bash.d.ts.map +1 -1
- package/dist/tools/bash.js +16 -15
- package/dist/tools/bash.js.map +1 -1
- package/dist/tools/edit.d.ts +7 -7
- package/dist/tools/edit.d.ts.map +1 -1
- package/dist/tools/edit.js +9 -9
- package/dist/tools/edit.js.map +1 -1
- package/dist/tools/index.d.ts +32 -32
- package/dist/tools/read.d.ts +6 -6
- package/dist/tools/read.d.ts.map +1 -1
- package/dist/tools/read.js +19 -8
- package/dist/tools/read.js.map +1 -1
- package/dist/tools/write.d.ts +4 -4
- package/dist/tools/write.d.ts.map +1 -1
- package/dist/tools/write.js +5 -5
- package/dist/tools/write.js.map +1 -1
- package/dist/types.d.ts +331 -64
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +27 -10
- package/dist/harness/events.d.ts +0 -186
- package/dist/harness/events.d.ts.map +0 -1
- package/dist/harness/events.js +0 -373
- package/dist/harness/events.js.map +0 -1
- package/dist/session/observation.d.ts +0 -42
- package/dist/session/observation.d.ts.map +0 -1
- package/dist/session/observation.js +0 -281
- package/dist/session/observation.js.map +0 -1
package/dist/harness/types.d.ts
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type { AssistantMessage, CacheRetention, Message, Models, ModelThinkingLevel,
|
|
1
|
+
import type { Context, JsonValue, WatchHandle } from "@earendil-works/chord";
|
|
2
|
+
import type { Api, AssistantMessage, CacheRetention, ClientIdentity, Message, Model, Models, ModelThinkingLevel, Tool, ToolCall, ToolResultMessage, Transport, Usage, UserMessage } from "@earendil-works/pi-ai";
|
|
3
|
+
import type { Static } from "@earendil-works/pi-schema";
|
|
4
|
+
import type { TelemetryContext } from "@earendil-works/pi-telemetry";
|
|
3
5
|
import type { ExecutionEnv, ShellOutputSkip, ShellOutputWindow } from "../env/index.ts";
|
|
4
|
-
import type { ConversationId, ConversationOwnership, ConversationRecord, Cursor, DocumentObserver, DocumentReader, EntryDraft, EntryId, EntryQuery, EntryRecord, JsonObject, Page, Session, SubmissionId, SubmissionRecord, Task, TaskId, TaskOptions, TaskRecord, TaskState, Tx,
|
|
6
|
+
import type { CommitOptions, ConversationId, ConversationOwnership, ConversationRecord, Cursor, DocumentObserver, DocumentReader, Entry, EntryDraft, EntryId, EntryQuery, EntryRecord, JsonObject, Observation, Observer, Page, Report, Session, SetTimer, SubmissionId, SubmissionRecord, Task, TaskId, TaskOptions, TaskRecord, TaskState, Tx, TypedEntry } from "../types.ts";
|
|
5
7
|
import type { TaskGraph, TaskGraphWatch } from "./task-graph.ts";
|
|
6
8
|
import type { UsageState } from "./usage.ts";
|
|
7
|
-
import type { ConversationView } from "./view.ts";
|
|
9
|
+
import type { ConversationView, ConversationWindow } from "./view.ts";
|
|
8
10
|
/** Provider and model ID resolved through pi-ai `Models`. */
|
|
9
11
|
export type ModelRef = {
|
|
10
12
|
readonly provider: string;
|
|
@@ -19,13 +21,23 @@ export type InputEntry = {
|
|
|
19
21
|
readonly kind: string;
|
|
20
22
|
readonly data?: JsonValue;
|
|
21
23
|
};
|
|
22
|
-
/**
|
|
24
|
+
/**
|
|
25
|
+
* Host submission: user input that may start a run, a passive entry write, or a continue: a run without a new user
|
|
26
|
+
* message, for an idle conversation whose context the model still owes an answer (it ends in a user message or tool
|
|
27
|
+
* results, for example after a run that ended without an answer).
|
|
28
|
+
*/
|
|
23
29
|
export type SubmissionDraft = {
|
|
24
30
|
readonly requestId?: string;
|
|
25
31
|
} & ({
|
|
26
32
|
readonly type: "input";
|
|
27
33
|
readonly content: UserInput;
|
|
28
34
|
readonly whenBusy?: "steer" | "followUp" | "reject";
|
|
35
|
+
/**
|
|
36
|
+
* `reject`: an idle conversation (no run) rejects the input with `ConversationIdle` and writes nothing, so the input
|
|
37
|
+
* never starts a run of its own. With `whenBusy: "steer"` it steers the current run or is refused; a run that
|
|
38
|
+
* answered and waits for its `afterRun` tasks is still busy, and such an input queues and starts the next run.
|
|
39
|
+
*/
|
|
40
|
+
readonly whenIdle?: "reject";
|
|
29
41
|
/** Place the input as this entry; default `pi.user` without data. The kind must not start with `pi.`. */
|
|
30
42
|
readonly entry?: InputEntry;
|
|
31
43
|
} | {
|
|
@@ -33,6 +45,20 @@ export type SubmissionDraft = {
|
|
|
33
45
|
readonly entry: EntryDraft;
|
|
34
46
|
readonly content?: never;
|
|
35
47
|
readonly whenBusy?: never;
|
|
48
|
+
readonly whenIdle?: never;
|
|
49
|
+
} | {
|
|
50
|
+
/**
|
|
51
|
+
* Start a run on the context as it is, without a user message. Only when idle: a busy conversation rejects it with
|
|
52
|
+
* `ConversationBusy`, and it never queues. Items kept in `pi.inbox` are placed first and join the run. A context
|
|
53
|
+
* with nothing to answer (empty, or ending in an answer, also a text answer cut off at its output limit) ends the
|
|
54
|
+
* run without a request, `unanswered` with `nothing_to_answer`. A cut-off answer with tool calls is continued:
|
|
55
|
+
* its calls never ran, and the context ends in their error results (`missing_result`).
|
|
56
|
+
*/
|
|
57
|
+
readonly type: "continue";
|
|
58
|
+
readonly content?: never;
|
|
59
|
+
readonly entry?: never;
|
|
60
|
+
readonly whenBusy?: never;
|
|
61
|
+
readonly whenIdle?: never;
|
|
36
62
|
});
|
|
37
63
|
export type InputSubmissionDraft = Extract<SubmissionDraft, {
|
|
38
64
|
readonly type: "input";
|
|
@@ -76,12 +102,16 @@ export type ConversationAbortOptions = {
|
|
|
76
102
|
/** Hook handler map declared by a task definition. */
|
|
77
103
|
export type HooksOf<K> = K extends Task<infer _I, infer _S, infer _R, infer H> ? H : never;
|
|
78
104
|
/**
|
|
79
|
-
* Invocation-bound conversation operations for tasks and tools. Rejects after the invocation ends
|
|
80
|
-
*
|
|
105
|
+
* Invocation-bound conversation operations for tasks and tools. Rejects after the invocation ends. `submit` takes any
|
|
106
|
+
* submission, in both forms of `Conversation.submit()`: a subagent's conversation is an ordinary one, so a tool may also
|
|
107
|
+
* continue it, and a task may admit a submission in the same commit as its own writes (`runtime.commit()`); entries
|
|
108
|
+
* the admission appends there carry the task's `byTaskId`. The transaction form also rejects once the invocation is
|
|
109
|
+
* aborted.
|
|
81
110
|
*/
|
|
82
111
|
export interface ConversationHandle {
|
|
83
112
|
readonly id: ConversationId;
|
|
84
|
-
submit(submission:
|
|
113
|
+
submit(submission: SubmissionDraft, context: Context): Promise<Submission>;
|
|
114
|
+
submit(tx: Tx, submission: SubmissionDraft): Promise<SubmissionId>;
|
|
85
115
|
/** `Conversation.abort()`: withdraw queued inputs, abort the ordinary ownership scope, and wait until it is idle. */
|
|
86
116
|
abort(context: Context, options?: ConversationAbortOptions): Promise<void>;
|
|
87
117
|
/** Resolve when the conversation's ordinary ownership scope has no live non-background task. */
|
|
@@ -90,7 +120,12 @@ export interface ConversationHandle {
|
|
|
90
120
|
/** Post-tools controls requested by a tool result. */
|
|
91
121
|
export type ToolControl = {
|
|
92
122
|
readonly addTools?: readonly string[];
|
|
93
|
-
|
|
123
|
+
/** End the run without another model request when every result of the round sets it to `true`; `false` is a no-op. */
|
|
124
|
+
readonly terminate?: boolean;
|
|
125
|
+
/**
|
|
126
|
+
* Start a new context with this text as its user message, as `reset(handoff)` writes, and continue the run there.
|
|
127
|
+
* The last handoff in call order wins.
|
|
128
|
+
*/
|
|
94
129
|
readonly handoff?: string;
|
|
95
130
|
};
|
|
96
131
|
/** Remark about a call for the model and the UI, such as truncation or a spill path; never part of the tool's data. */
|
|
@@ -158,10 +193,12 @@ export interface ToolExecutionApi<TDetails extends JsonValue = JsonValue> extend
|
|
|
158
193
|
readonly registry: RegistrySnapshot;
|
|
159
194
|
/** The calling conversation's agent, as the tool task's phase resolved it. */
|
|
160
195
|
agent(context: Context): Promise<Agent>;
|
|
161
|
-
/** `HarnessOptions.models
|
|
196
|
+
/** The current `HarnessOptions.models`, read at each access: the catalog, credentials, and request transforms. */
|
|
162
197
|
readonly models: Models;
|
|
163
198
|
/** Built by `HarnessOptions.env` for this call; `undefined` without an environment. */
|
|
164
199
|
readonly env: ExecutionEnv | undefined;
|
|
200
|
+
/** The Harness clock (`HarnessOptions.now`), for times a rerun after a restart compares against. */
|
|
201
|
+
now(): number;
|
|
165
202
|
/**
|
|
166
203
|
* Append running output; it becomes the result's `output` when the result omits it. `skipped` counts output
|
|
167
204
|
* omitted before the chunk, as reported by an environment given `outputWindow` (`ShellOutputInfo.skipped`).
|
|
@@ -185,7 +222,8 @@ export interface ToolExecutionApi<TDetails extends JsonValue = JsonValue> extend
|
|
|
185
222
|
diagnostic(diagnostic: ToolDiagnostic): void;
|
|
186
223
|
/** Replace running details; the last value becomes the result details when the result omits `details`. */
|
|
187
224
|
details(value: TDetails, context: Context): Promise<void>;
|
|
188
|
-
commit
|
|
225
|
+
/** A commit of this call's task; `options` may defer storing it (`CommitPersistence`). */
|
|
226
|
+
commit<T>(change: (tx: Tx) => T | Promise<T>, context: Context, options?: CommitOptions): Promise<T>;
|
|
189
227
|
memo<T extends JsonValue>(name: string, context: Context): Promise<T | undefined>;
|
|
190
228
|
memo<T extends JsonValue>(name: string, candidate: T, context: Context): Promise<T>;
|
|
191
229
|
/**
|
|
@@ -231,11 +269,18 @@ export interface ToolExecutionApi<TDetails extends JsonValue = JsonValue> extend
|
|
|
231
269
|
readonly progress?: boolean;
|
|
232
270
|
}): Promise<NestedToolExecutionResult>;
|
|
233
271
|
}
|
|
272
|
+
/**
|
|
273
|
+
* The arguments type of a tool with parameter schema `TParameters`: pi-schema's `Static<TParameters>` (the builders'
|
|
274
|
+
* type, TypeBox's for the common TypeBox kinds, else `unknown`), and `any` for `ToolRegistration<any>`.
|
|
275
|
+
*/
|
|
276
|
+
export type ToolArgs<TParameters> = IsAny<TParameters> extends true ? any : Static<TParameters>;
|
|
277
|
+
type IsAny<T> = boolean extends (T extends never ? true : false) ? true : false;
|
|
234
278
|
/**
|
|
235
279
|
* Executable tool registered in a registry. Only pi-ai `Tool` fields enter the transcript. `args` are typed by
|
|
236
|
-
* `parameters
|
|
280
|
+
* `parameters` (any JSON Schema object; see {@link ToolArgs}), which the Harness validates them against before
|
|
281
|
+
* `execute()`; `defineTool()` infers both generics.
|
|
237
282
|
*/
|
|
238
|
-
export type ToolRegistration<TParameters extends
|
|
283
|
+
export type ToolRegistration<TParameters extends object = object, TDetails extends JsonValue = JsonValue> = Tool<TParameters> & {
|
|
239
284
|
/** Whether an interrupted execution may rerun on recovery. Default `unsafe`. */
|
|
240
285
|
readonly replay?: "safe" | "unsafe";
|
|
241
286
|
/** Default: the settings' `toolExecution`. One sequential call makes its whole round sequential. */
|
|
@@ -245,12 +290,12 @@ export type ToolRegistration<TParameters extends TSchema = TSchema, TDetails ext
|
|
|
245
290
|
* pure and must not mutate `args`: it runs again when a call is retried before its intent is recorded. Its result is
|
|
246
291
|
* still validated against `parameters`.
|
|
247
292
|
*/
|
|
248
|
-
prepareArguments?(args: unknown):
|
|
293
|
+
prepareArguments?(args: unknown): ToolArgs<TParameters>;
|
|
249
294
|
/**
|
|
250
295
|
* Schema of `structuredOutput`, which programs that call the tool receive. Omitted: they receive the result's bounded
|
|
251
296
|
* output, success or error, as `NestedToolExecutionResult.structuredOutput` describes.
|
|
252
297
|
*/
|
|
253
|
-
readonly structuredOutputSchema?:
|
|
298
|
+
readonly structuredOutputSchema?: object;
|
|
254
299
|
/**
|
|
255
300
|
* Who may call the tool: the model, other tools through `executeTool()`, or both (default). A code mode tool is
|
|
256
301
|
* `["model"]`, so scripts cannot start scripts; tools behind code mode, such as MCP tools, can be `["tools"]`, so the
|
|
@@ -267,7 +312,7 @@ export type ToolRegistration<TParameters extends TSchema = TSchema, TDetails ext
|
|
|
267
312
|
readonly maxLines?: number;
|
|
268
313
|
readonly retain?: "head" | "tail";
|
|
269
314
|
};
|
|
270
|
-
execute(args:
|
|
315
|
+
execute(args: ToolArgs<TParameters>, api: ToolExecutionApi<TDetails>, context: Context): Promise<ToolExecutionResult<TDetails>>;
|
|
271
316
|
};
|
|
272
317
|
/** Input to system prompt section rendering for one request preparation. */
|
|
273
318
|
export type PromptInput<Tool extends ToolRegistration = ToolRegistration> = {
|
|
@@ -373,6 +418,11 @@ export type AgentState = {
|
|
|
373
418
|
instructions?: string;
|
|
374
419
|
/** Directory within the environment's file system, passed to `HarnessOptions.env`. */
|
|
375
420
|
cwd?: string;
|
|
421
|
+
/**
|
|
422
|
+
* Tool rounds one run takes at most (`pi.live.run.turns`): the round that reaches it runs its tools, then the run ends
|
|
423
|
+
* `unanswered` with `turn_limit`. An integer, `1` or more; unset, no limit. Task-owned children and forks inherit it.
|
|
424
|
+
*/
|
|
425
|
+
maxTurns?: number;
|
|
376
426
|
};
|
|
377
427
|
/** A change to `pi.agent`: a given field replaces the stored one, `null` clears it, `undefined` changes nothing. */
|
|
378
428
|
export type AgentChange = {
|
|
@@ -392,6 +442,8 @@ export type AgentChange = {
|
|
|
392
442
|
} | null;
|
|
393
443
|
readonly instructions?: string | null;
|
|
394
444
|
readonly cwd?: string | null;
|
|
445
|
+
/** `configure()` throws a `RangeError` unless it is an integer `1` or more (or `null`). */
|
|
446
|
+
readonly maxTurns?: number | null;
|
|
395
447
|
};
|
|
396
448
|
/** A conversation's agent resolved against a registry snapshot and the settings. */
|
|
397
449
|
export type Agent<Tool extends ToolRegistration = ToolRegistration> = {
|
|
@@ -408,6 +460,11 @@ export type Agent<Tool extends ToolRegistration = ToolRegistration> = {
|
|
|
408
460
|
readonly sections: readonly PromptSection<Tool>[];
|
|
409
461
|
readonly instructions?: string;
|
|
410
462
|
readonly cwd?: string;
|
|
463
|
+
/**
|
|
464
|
+
* Tool rounds one run takes at most (`pi.live.run.turns`): the round that reaches it runs its tools, then the run ends
|
|
465
|
+
* `unanswered` with `turn_limit`. An integer, `1` or more; unset, no limit. Task-owned children and forks inherit it.
|
|
466
|
+
*/
|
|
467
|
+
readonly maxTurns?: number;
|
|
411
468
|
};
|
|
412
469
|
/**
|
|
413
470
|
* Runs inside the creating commit, after the creation hook and the `agent` change. The conversation creation is already
|
|
@@ -453,14 +510,28 @@ export type CompactionPolicy = {
|
|
|
453
510
|
backgroundTokens: number;
|
|
454
511
|
};
|
|
455
512
|
/**
|
|
456
|
-
*
|
|
457
|
-
*
|
|
513
|
+
* Harness-wide compaction settings. `modelOverrides` is keyed by exact `"provider/modelId"`; each field it sets
|
|
514
|
+
* replaces the harness-wide one for that model, so small- and large-window models can share a harness.
|
|
515
|
+
*/
|
|
516
|
+
export type CompactionSettings = Partial<CompactionPolicy> & {
|
|
517
|
+
readonly modelOverrides?: Readonly<Record<string, Partial<CompactionPolicy>>>;
|
|
518
|
+
};
|
|
519
|
+
/**
|
|
520
|
+
* How often running progress is committed, and how long it may wait in memory before it is stored. Progress commits are
|
|
521
|
+
* deferred (`CommitPersistence`): watches see each at once, and Storage gets them together, at the run's next phase
|
|
522
|
+
* boundary or after `persistWithinMs`. A host can commit less often, so live answers and tool output appear in larger steps.
|
|
458
523
|
*/
|
|
459
524
|
export type ProgressPolicy = {
|
|
460
525
|
/** Minimum pause between commits of the answer being generated. */
|
|
461
526
|
partialIntervalMs: number;
|
|
462
527
|
/** Minimum pause between commits of running tool output; large commits also pause in proportion to their size. */
|
|
463
528
|
outputIntervalMs: number;
|
|
529
|
+
/**
|
|
530
|
+
* How long these commits, and other deferred commits without their own `withinMs`, may stay in memory before they are
|
|
531
|
+
* stored (`CommitPersistence`); a crash loses at most about this much of an answer or of tool output. Default 1,000;
|
|
532
|
+
* `Infinity` stores them only at the next commit that reads or writes their document and at close.
|
|
533
|
+
*/
|
|
534
|
+
persistWithinMs: number;
|
|
464
535
|
};
|
|
465
536
|
/** Why a compaction runs: `compact()`, a threshold in generation preparation, or a context overflow. */
|
|
466
537
|
export type CompactionReason = "manual" | "threshold" | "overflow";
|
|
@@ -478,7 +549,7 @@ export type HarnessSettings = {
|
|
|
478
549
|
readonly extensions?: readonly Extension[];
|
|
479
550
|
readonly stream?: ConversationStreamOptions;
|
|
480
551
|
readonly retry?: Partial<ConversationRetryPolicy>;
|
|
481
|
-
readonly compaction?:
|
|
552
|
+
readonly compaction?: CompactionSettings;
|
|
482
553
|
readonly progress?: Partial<ProgressPolicy>;
|
|
483
554
|
readonly toolExecution?: ToolExecutionMode;
|
|
484
555
|
readonly steeringMode?: QueueMode;
|
|
@@ -489,25 +560,49 @@ export type HarnessSettings = {
|
|
|
489
560
|
*/
|
|
490
561
|
readonly contextRetentionMs?: number;
|
|
491
562
|
/**
|
|
492
|
-
* How long a loaded document that no watch
|
|
563
|
+
* How long a loaded document that no watch observes stays in memory after its last read or write;
|
|
493
564
|
* the next access loads it from Storage. Observed documents always stay. Default ten minutes; `0` drops one right
|
|
494
565
|
* after use; `Infinity` keeps them. Anything else that is not a number of milliseconds means the default.
|
|
495
566
|
*/
|
|
496
567
|
readonly documentRetentionMs?: number;
|
|
568
|
+
/**
|
|
569
|
+
* What a run that fails (`model_error`, `no_model`, `interrupted`, `restart_limit`, `nothing_to_answer`,
|
|
570
|
+
* `turn_limit`) does with the inputs queued behind it: `keep` leaves them queued until the next input or queued write, `continue` starts the
|
|
571
|
+
* next run with them, as an answer would, and `withdraw` settles them `unanswered` with reason `run_failed`. Default
|
|
572
|
+
* `keep`.
|
|
573
|
+
*/
|
|
574
|
+
readonly afterFailedRun?: AfterFailedRun;
|
|
575
|
+
/**
|
|
576
|
+
* How many times in a row a task may be cut off by a crash, eviction, or reset (a close does not count) without
|
|
577
|
+
* changing its state before it ends instead of running again: a tool call with an error result, a compaction failed
|
|
578
|
+
* into `pi.live.compactionFailure`, a run with `pi.live.runFailure` reason `restart_limit`, any other task `faulted`
|
|
579
|
+
* with detail `{ reason: "restart_limit" }`. A generation's request or poll the host died during is a failed attempt
|
|
580
|
+
* under `retry` first; the limit bounds it only when charging that attempt keeps being cut off. Default 5;
|
|
581
|
+
* `Infinity` never ends a task for it.
|
|
582
|
+
*/
|
|
583
|
+
readonly restartLimit?: number;
|
|
497
584
|
};
|
|
585
|
+
/**
|
|
586
|
+
* What a failed run does with the inputs queued behind it (`HarnessSettings.afterFailedRun`): a run that ends with
|
|
587
|
+
* `model_error`, `no_model`, `interrupted`, `restart_limit`, `nothing_to_answer`, or `turn_limit`.
|
|
588
|
+
*/
|
|
589
|
+
export type AfterFailedRun = "keep" | "continue" | "withdraw";
|
|
498
590
|
/** Resolved settings: every field over its built-in default, object fields merged. */
|
|
499
591
|
export type Settings = {
|
|
500
592
|
/** Absent: every installed extension, in install order. */
|
|
501
593
|
readonly extensions?: readonly Extension[];
|
|
502
594
|
readonly stream: ConversationStreamOptions;
|
|
503
595
|
readonly retry: ConversationRetryPolicy;
|
|
504
|
-
|
|
596
|
+
/** Harness-wide policy over the defaults; per-model overrides apply where the model is known. */
|
|
597
|
+
readonly compaction: CompactionPolicy & Pick<CompactionSettings, "modelOverrides">;
|
|
505
598
|
readonly progress: ProgressPolicy;
|
|
506
599
|
readonly toolExecution: ToolExecutionMode;
|
|
507
600
|
readonly steeringMode: QueueMode;
|
|
508
601
|
readonly followUpMode: QueueMode;
|
|
509
602
|
readonly contextRetentionMs: number;
|
|
510
603
|
readonly documentRetentionMs: number;
|
|
604
|
+
readonly afterFailedRun: AfterFailedRun;
|
|
605
|
+
readonly restartLimit: number;
|
|
511
606
|
};
|
|
512
607
|
/** What `HarnessOptions.env` builds an environment for. */
|
|
513
608
|
export type EnvTarget = {
|
|
@@ -517,10 +612,23 @@ export type EnvTarget = {
|
|
|
517
612
|
readonly read: DocumentReader;
|
|
518
613
|
};
|
|
519
614
|
export type HarnessOptions<Tool extends ToolRegistration = ToolRegistration> = {
|
|
520
|
-
/**
|
|
521
|
-
readonly
|
|
615
|
+
/** Host-owned adapter for content-free admission/phase telemetry; propagation and metrics are optional. */
|
|
616
|
+
readonly telemetry?: TelemetryContext;
|
|
617
|
+
/**
|
|
618
|
+
* pi-ai model access used by generation, compaction, hooks and tools: a `Models`, or a function returning the current
|
|
619
|
+
* one, called at each use, so a host can replace its model configuration without reopening the Harness.
|
|
620
|
+
*/
|
|
621
|
+
readonly models: Models | (() => Models);
|
|
622
|
+
/**
|
|
623
|
+
* How model requests identify the app to providers, merged field by field over `DEFAULT_HARNESS_IDENTITY`
|
|
624
|
+
* (`{ attribution: PI_ATTRIBUTION }`, provider attribution to pi). It applies to every request through the Harness's
|
|
625
|
+
* models, including hooks and tools, and overrides the identity the `Models` was created with; a request's own
|
|
626
|
+
* `identity` overrides it. Pass `{ attribution: null }` to send no attribution headers.
|
|
627
|
+
*/
|
|
628
|
+
readonly identity?: ClientIdentity;
|
|
522
629
|
readonly registry: RegistryReader<Tool>;
|
|
523
|
-
|
|
630
|
+
/** Run settings, or a function returning the current ones; read at each use either way. */
|
|
631
|
+
readonly settings?: HarnessSettings | (() => HarnessSettings | undefined);
|
|
524
632
|
/** Builds a conversation's environment at each use. Never called on the Session line; may be async. */
|
|
525
633
|
readonly env?: (target: EnvTarget, context: Context) => ExecutionEnv | undefined | Promise<ExecutionEnv | undefined>;
|
|
526
634
|
/**
|
|
@@ -529,12 +637,55 @@ export type HarnessOptions<Tool extends ToolRegistration = ToolRegistration> = {
|
|
|
529
637
|
* Table reads throw `ReadAfterWrite`, as in `init`; a throw fails the creating commit.
|
|
530
638
|
*/
|
|
531
639
|
readonly conversationCreated?: (tx: Tx, conversation: ConversationRecord) => void | Promise<void>;
|
|
640
|
+
/**
|
|
641
|
+
* The Harness clock, epoch milliseconds; default `Date.now`. Sleeping tasks store deadlines on it, so every process
|
|
642
|
+
* that opens the same storage must use the same clock.
|
|
643
|
+
*/
|
|
532
644
|
readonly now?: () => number;
|
|
533
645
|
/**
|
|
534
|
-
*
|
|
535
|
-
*
|
|
646
|
+
* Arms the timers of the Session, the scheduler, and its tasks: pacing progress commits, freeing idle memory
|
|
647
|
+
* (`background`), and, without `onWake`, resuming sleeping tasks; and the timers of `TaskRuntime.setTimer()`. The
|
|
648
|
+
* Node.js environment, file watcher, and image worker keep their own timers. Default `setTimeout`, with background
|
|
649
|
+
* timers unreferenced, or declined in Cloudflare Workers and where they cannot be unreferenced. Tests can pass fake
|
|
650
|
+
* timers; a host can keep timers off a process that should hibernate.
|
|
651
|
+
*/
|
|
652
|
+
readonly setTimer?: SetTimer;
|
|
653
|
+
/**
|
|
654
|
+
* Wakes the process for sleeping tasks instead of a `setTimer` timer. Without it, while scheduling runs, a timer that
|
|
655
|
+
* keeps the process alive resumes sleeping tasks when they are due. With it, the Harness arms no timer for them: it
|
|
656
|
+
* calls `onWake` after open and whenever `Harness.wake()` changes, and the host arms its own wakeup, such as a
|
|
657
|
+
* Durable Object alarm, and calls `resume()` when it fires. Called in a microtask the Session line never waits for,
|
|
658
|
+
* after the commit that changed the value was adopted, so a host arms a recovery wakeup before calls that can start
|
|
659
|
+
* work. It may call `wake()` and `resume()`, and must not block. A throw is reported, and the value is offered again
|
|
660
|
+
* at the next change.
|
|
536
661
|
*/
|
|
537
|
-
readonly
|
|
662
|
+
readonly onWake?: (wake: Wake) => void;
|
|
663
|
+
/**
|
|
664
|
+
* Receives failures that do not fail the calling operation, such as a throwing hook or listener, a task that faulted,
|
|
665
|
+
* and the error that fails the Session, once: one `Report`, the `error` and what happened (`kind` and the fields of
|
|
666
|
+
* its `ReportInfo`). A host can tell a failed Session (`storage_failed`, often a platform reset) from a faulted task
|
|
667
|
+
* (`task_faulted`). Its own throw or rejection is dropped.
|
|
668
|
+
*/
|
|
669
|
+
readonly onReport?: (report: Report) => void;
|
|
670
|
+
/**
|
|
671
|
+
* Open for reading only, as a viewer of a session that another process drives, for example a synced copy on a device
|
|
672
|
+
* that only shows it. Open recovers nothing: a `running` task stays as committed. Every commit with writes rejects
|
|
673
|
+
* with `ReadOnlySession` before it reaches Storage, and so does `resume()` and every call that enables scheduling;
|
|
674
|
+
* the Harness stays usable for reads and watches. `wake()` is always inactive, and `onWake` is never called. Reopen
|
|
675
|
+
* without it to write.
|
|
676
|
+
*/
|
|
677
|
+
readonly readOnly?: boolean;
|
|
678
|
+
};
|
|
679
|
+
/**
|
|
680
|
+
* When a Session next needs a running process (`Harness.wake()`). `active`: some task can run now or is running, or a
|
|
681
|
+
* reconcile pass such as open's recovery has not landed yet, so a process that dies must be woken again soon, for
|
|
682
|
+
* example by a recovery alarm. `at`: the earliest sleep not yet due,
|
|
683
|
+
* when there is one. Neither: nothing needs a process until new work is submitted. Tasks blocked on a missing or
|
|
684
|
+
* unmigratable definition, `completing` tasks, and waits on live tasks do not count; the work they wait for does.
|
|
685
|
+
*/
|
|
686
|
+
export type Wake = {
|
|
687
|
+
readonly active: boolean;
|
|
688
|
+
readonly at?: number;
|
|
538
689
|
};
|
|
539
690
|
/** Live task and what the scheduler would do with it under the current registry. */
|
|
540
691
|
export type TaskInspection = {
|
|
@@ -544,7 +695,7 @@ export type TaskInspection = {
|
|
|
544
695
|
}
|
|
545
696
|
/** The next scheduling pass reserves it; `migrates` when its definition is newer and has `migrate`. */
|
|
546
697
|
| {
|
|
547
|
-
readonly kind: "
|
|
698
|
+
readonly kind: "pending";
|
|
548
699
|
readonly migrates: boolean;
|
|
549
700
|
}
|
|
550
701
|
/**
|
|
@@ -555,11 +706,16 @@ export type TaskInspection = {
|
|
|
555
706
|
readonly kind: "waiting";
|
|
556
707
|
readonly on: readonly TaskId[];
|
|
557
708
|
}
|
|
709
|
+
/** Sleeps until the Harness clock reaches `until`. */
|
|
710
|
+
| {
|
|
711
|
+
readonly kind: "sleeping";
|
|
712
|
+
readonly until: number;
|
|
713
|
+
}
|
|
558
714
|
/** Outcome held until its ordinary owned work drains. */
|
|
559
715
|
| {
|
|
560
716
|
readonly kind: "completing";
|
|
561
717
|
}
|
|
562
|
-
/**
|
|
718
|
+
/** Cannot run here: no registered definition can take it (aborting it settles it as `orphaned`). */
|
|
563
719
|
| {
|
|
564
720
|
readonly kind: "blocked";
|
|
565
721
|
readonly reason: "missing_task" | "task_too_old" | "migration_failed";
|
|
@@ -592,12 +748,25 @@ export interface Conversation {
|
|
|
592
748
|
/** `configure()` in its own commit. */
|
|
593
749
|
configure(change: AgentChange, context: Context): Promise<void>;
|
|
594
750
|
/**
|
|
595
|
-
* Durably admit user input
|
|
596
|
-
* writes that affect model context in `pi.inbox`; `whenBusy: "reject"` rejects input with
|
|
597
|
-
* and writes nothing.
|
|
598
|
-
*
|
|
751
|
+
* Durably admit user input, a passive entry write, or a continue. A busy conversation, or one with queued items,
|
|
752
|
+
* queues input and writes that affect model context in `pi.inbox`; `whenBusy: "reject"` rejects input with
|
|
753
|
+
* `ConversationBusy` instead and writes nothing. An idle conversation rejects `whenIdle: "reject"` input with
|
|
754
|
+
* `ConversationIdle` and writes nothing. A write of only `kind` and `data` (no `model`, `head`, or `edits`)
|
|
755
|
+
* is appended at once, even mid-run, as it changes nothing the model sees. A continue starts a run on the context as
|
|
756
|
+
* it is, after placing queued items; a busy conversation rejects it with `ConversationBusy`, as it never queues.
|
|
599
757
|
*/
|
|
600
758
|
submit(submission: SubmissionDraft, context: Context): Promise<Submission>;
|
|
759
|
+
/**
|
|
760
|
+
* Admit a submission inside the caller's commit `tx` (`Harness.commit()`, `Conversation.commit()`, a task's
|
|
761
|
+
* `runtime.commit()`), with the same rules, and return its ID: the admission is stored with that commit, or not at all
|
|
762
|
+
* when the callback throws later or the commit fails. Call it before the commit's first table write (`appendEntry()`,
|
|
763
|
+
* `createTask()`, `createSubmission()`, another admission): otherwise it throws `ReadAfterWrite`, on every path.
|
|
764
|
+
* Documents may be read and written before and after it. A rejection (`ConversationBusy`, `ConversationIdle`) throws
|
|
765
|
+
* before any write, so the callback may catch it. Do not call `Submission` or other Harness reads inside the callback:
|
|
766
|
+
* they wait for the commit holding the line. Its `pi.durable.submit` span covers the admission only, so its `result`
|
|
767
|
+
* is provisional. Throws for a transaction of another Session.
|
|
768
|
+
*/
|
|
769
|
+
submit(tx: Tx, submission: SubmissionDraft): Promise<SubmissionId>;
|
|
601
770
|
/**
|
|
602
771
|
* Admit a write of a `pi.reset` entry that starts a new context, carrying `handoff` as a user message when given.
|
|
603
772
|
* Resolves after admission; while busy, it is placed at the next boundary.
|
|
@@ -608,8 +777,8 @@ export interface Conversation {
|
|
|
608
777
|
* summary through a write submission: at once when idle, otherwise at the next boundary (spec §8.7).
|
|
609
778
|
*/
|
|
610
779
|
compact(instructions: string | undefined, context: Context): Promise<TaskId<CompactionResult>>;
|
|
611
|
-
/** Session commit whose `tx.createTask()` defaults to this conversation. */
|
|
612
|
-
commit<T>(change: (tx: Tx) => T | Promise<T>, context: Context): Promise<T>;
|
|
780
|
+
/** Session commit whose `tx.createTask()` defaults to this conversation; `options` as for `Session.commit()`. */
|
|
781
|
+
commit<T>(change: (tx: Tx) => T | Promise<T>, context: Context, options?: CommitOptions): Promise<T>;
|
|
613
782
|
/**
|
|
614
783
|
* Committed raw active transcript and model context. With `at`, the context as of that visible entry: the same view
|
|
615
784
|
* `fork(at)` would start with, without creating a conversation.
|
|
@@ -630,20 +799,30 @@ export interface Conversation {
|
|
|
630
799
|
* owned, transitively, by its non-background tasks.
|
|
631
800
|
*/
|
|
632
801
|
waitForIdle(context: Context): Promise<void>;
|
|
633
|
-
/**
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
802
|
+
/**
|
|
803
|
+
* The structural view (spec §9.3) as a serialized watch; commits made while its listener runs arrive folded. Its
|
|
804
|
+
* `entries` are a window over the transcript, as `window` says: the newest 50 by default, then appends, dropping the
|
|
805
|
+
* oldest past 100. Built on the same mount as `Harness.observeConversation()`.
|
|
806
|
+
*/
|
|
807
|
+
watch(context: Context, window?: ConversationWindow): Promise<ConversationWatch>;
|
|
637
808
|
}
|
|
638
809
|
export type ConversationWatch = WatchHandle<ConversationView>;
|
|
639
810
|
/** Durable agent harness over one Session. */
|
|
640
811
|
export interface Harness extends Session {
|
|
641
812
|
/**
|
|
642
|
-
* Enable task scheduling. Idempotent; throws after close
|
|
643
|
-
* `Conversation.submit()`, `Conversation.compact()`, `Conversation.abort()`,
|
|
644
|
-
* `Harness.waitForIdle()`, and `Conversation.waitForIdle()`. Read-only viewers
|
|
813
|
+
* Enable task scheduling. Idempotent; throws after close, and `ReadOnlySession` on a read-only Harness. Calls that
|
|
814
|
+
* ask for progress enable it too: `Conversation.submit()`, `Conversation.compact()`, `Conversation.abort()`,
|
|
815
|
+
* `Submission.wait()`, `waitForTask()`, `Harness.waitForIdle()`, and `Conversation.waitForIdle()`. Read-only viewers
|
|
816
|
+
* never do.
|
|
645
817
|
*/
|
|
646
818
|
resume(): void;
|
|
819
|
+
/**
|
|
820
|
+
* When this Session next needs a running process, from the scheduler's memory: `active` while some task can run now
|
|
821
|
+
* or is running, `at` for the earliest sleep. Answers also while scheduling is paused. A host that wakes the
|
|
822
|
+
* process itself, such as a Durable Object alarm, arms from it and calls `resume()` when woken; see
|
|
823
|
+
* `HarnessOptions.onWake`.
|
|
824
|
+
*/
|
|
825
|
+
wake(): Wake;
|
|
647
826
|
/** Return the reserved root conversation, creating it with `agent` and `init` in one commit when absent. */
|
|
648
827
|
root(context: Context, options?: {
|
|
649
828
|
readonly agent?: AgentChange;
|
|
@@ -669,19 +848,42 @@ export interface Harness extends Session {
|
|
|
669
848
|
waitForIdle(context: Context): Promise<void>;
|
|
670
849
|
/** Session total: every conversation's `pi.usage` summed. */
|
|
671
850
|
usage(context: Context): Promise<UsageState>;
|
|
672
|
-
/**
|
|
673
|
-
|
|
674
|
-
|
|
851
|
+
/**
|
|
852
|
+
* Every live task with its owner edge, status, and owned conversations (spec §9.4), as a serialized watch; commits
|
|
853
|
+
* made while its listener runs arrive folded.
|
|
854
|
+
*/
|
|
675
855
|
watchTaskGraph(context: Context): Promise<TaskGraphWatch>;
|
|
856
|
+
/**
|
|
857
|
+
* Attach a synchronous `Observer` to a conversation's structural view (spec §9.3), atomically on the Session line,
|
|
858
|
+
* for adapters: `advance` gets each next revision with its operations as memory adopts the commit, inside Storage's
|
|
859
|
+
* `adopt` for a stored one and before it is stored for a deferred one, so it only records it. `window` as for
|
|
860
|
+
* `Conversation.watch()`; each observer has its own. `context` governs only the attachment.
|
|
861
|
+
*/
|
|
862
|
+
observeConversation(id: ConversationId, observer: Observer<ConversationView>, context: Context, window?: ConversationWindow): Promise<Observation<ConversationView>>;
|
|
863
|
+
/**
|
|
864
|
+
* Attach a synchronous `Observer` to the task graph (spec §9.4), as `observeConversation()` does to a view. A
|
|
865
|
+
* `blocked` reason that changes without a commit (a registry change, a failed migration) advances it on the Session
|
|
866
|
+
* line outside any commit and `adopt`, with the background context.
|
|
867
|
+
*/
|
|
868
|
+
observeTaskGraph(observer: Observer<TaskGraph>, context: Context): Promise<Observation<TaskGraph>>;
|
|
676
869
|
}
|
|
677
|
-
/**
|
|
870
|
+
/**
|
|
871
|
+
* What a hook may use: committed reads and the asking task's memos, which hooks and the task share. Hooks run off the
|
|
872
|
+
* Session line, so reads see what is committed when they run; a hook rerun after a crash may see more.
|
|
873
|
+
*/
|
|
678
874
|
export interface HookApi extends DocumentReader {
|
|
679
875
|
readonly taskId: TaskId;
|
|
680
876
|
readonly conversationId: ConversationId;
|
|
681
|
-
/** `HarnessOptions.models
|
|
877
|
+
/** The current `HarnessOptions.models`, read at each access. */
|
|
682
878
|
readonly models: Models;
|
|
683
879
|
memo<T extends JsonValue>(name: string, context: Context): Promise<T | undefined>;
|
|
684
880
|
memo<T extends JsonValue>(name: string, candidate: T, context: Context): Promise<T>;
|
|
881
|
+
/** Committed entry visible from the task's conversation, as `TaskRuntime.entry()`. */
|
|
882
|
+
entry(id: EntryId, context: Context): Promise<EntryRecord | undefined>;
|
|
883
|
+
/** Undefined when the entry is absent, not visible, or has another kind. */
|
|
884
|
+
entry<D extends JsonValue>(token: Entry<D>, id: EntryId, context: Context): Promise<TypedEntry<D> | undefined>;
|
|
885
|
+
/** Committed raw history of the task's conversation, as `TaskRuntime.entries()`. */
|
|
886
|
+
entries(query: Omit<EntryQuery, "conversationId">, limit: number, cursor: Cursor | undefined, context: Context): Promise<Page<EntryRecord, Cursor>>;
|
|
685
887
|
}
|
|
686
888
|
export type HookResult<T> = T | undefined | Promise<T | undefined>;
|
|
687
889
|
/** Hooks of the built-in generation task. */
|
|
@@ -692,6 +894,17 @@ export interface GenerationHooks {
|
|
|
692
894
|
}, api: HookApi, context: Context): HookResult<{
|
|
693
895
|
readonly messages: readonly Message[];
|
|
694
896
|
}>;
|
|
897
|
+
/**
|
|
898
|
+
* After pi-ai builds the provider request body, before it is sent; the result replaces the body for that request only.
|
|
899
|
+
* Runs again whenever pi-ai rebuilds the body, such as a retry within one attempt. The body is in the provider API's
|
|
900
|
+
* own format (`request.model.api`), so a hook checks the API before changing it.
|
|
901
|
+
*/
|
|
902
|
+
beforeProviderRequest(request: {
|
|
903
|
+
readonly model: Model<Api>;
|
|
904
|
+
readonly payload: unknown;
|
|
905
|
+
}, api: HookApi, context: Context): HookResult<{
|
|
906
|
+
readonly payload: unknown;
|
|
907
|
+
}>;
|
|
695
908
|
/** Every terminal provider message, before classification. */
|
|
696
909
|
afterResponse(message: AssistantMessage, api: HookApi, context: Context): void | Promise<void>;
|
|
697
910
|
/** A final answer; the first `continue` appends a user message and continues the run. */
|
|
@@ -700,7 +913,36 @@ export interface GenerationHooks {
|
|
|
700
913
|
}>;
|
|
701
914
|
/** After every tool of the round is terminal; `results` are the round's result entries in call order. */
|
|
702
915
|
afterTools(assistant: EntryId, results: readonly EntryId[], api: HookApi, context: Context): void | Promise<void>;
|
|
916
|
+
/**
|
|
917
|
+
* After a run answered, its answer committed and its inputs settled `done`: a final answer, or a `terminate` round;
|
|
918
|
+
* not when an `onYield` continuation is taken, and never after a failure or an abort. The requested tasks of every
|
|
919
|
+
* hook are created together as children of the generation, which keeps the run, and the conversation busy, until
|
|
920
|
+
* they are terminal; then queued items are placed and the run ends (spec §8.3). A crash before they are created asks
|
|
921
|
+
* again; once created, never again for this run.
|
|
922
|
+
*/
|
|
923
|
+
afterRun(run: RunSummary, api: HookApi, context: Context): HookResult<{
|
|
924
|
+
readonly tasks: readonly RunEndTask[];
|
|
925
|
+
}>;
|
|
703
926
|
}
|
|
927
|
+
/** How a run ended, for `afterRun` hooks. Read the run's history with `api.entries({ minEntryId: first, maxEntryId: last })`. */
|
|
928
|
+
export type RunSummary = {
|
|
929
|
+
/** A final answer, or a tool round whose every call asked to `terminate`. */
|
|
930
|
+
readonly reason: "answer" | "terminate";
|
|
931
|
+
/**
|
|
932
|
+
* The run's first entry (`LiveRun.first`): the first one the boundary that started it placed, for a continue the failed
|
|
933
|
+
* run's it continues, otherwise its first tool-calling answer; the answer itself for a run that has none of these.
|
|
934
|
+
*/
|
|
935
|
+
readonly first: EntryId;
|
|
936
|
+
/** The answer, or the terminating round's tool-calling answer, whose results follow it. */
|
|
937
|
+
readonly answer: EntryId;
|
|
938
|
+
/** The run's last entry: the answer; for a `terminate` round its newest result, or the reset of its handoff. */
|
|
939
|
+
readonly last: EntryId;
|
|
940
|
+
};
|
|
941
|
+
/** A task an `afterRun` hook asks for, built by `runEndTask()`. */
|
|
942
|
+
export type RunEndTask = {
|
|
943
|
+
readonly task: AnyTask;
|
|
944
|
+
readonly input: JsonValue;
|
|
945
|
+
};
|
|
704
946
|
/** A call as tool hooks see it; `parent` is set for a nested call, one a running tool made through `executeTool()`. */
|
|
705
947
|
export type ToolHookCall = ToolCall & {
|
|
706
948
|
readonly parent?: {
|
|
@@ -715,7 +957,18 @@ export interface ToolHooks {
|
|
|
715
957
|
readonly arguments?: JsonObject;
|
|
716
958
|
readonly block?: string;
|
|
717
959
|
}>;
|
|
718
|
-
/**
|
|
960
|
+
/**
|
|
961
|
+
* Before the result is committed; replaces the result. Runs on every result the tool task writes: an executed
|
|
962
|
+
* call's, and the error results the Harness writes itself, told apart by their diagnostic code: a tool that does not
|
|
963
|
+
* resolve (`tool_unavailable`), invalid arguments (`invalid_arguments`, with `call.arguments` as the model sent
|
|
964
|
+
* them), a block (`blocked`), and, rebuilt from the call's partial output, an interruption (`interrupted`), the
|
|
965
|
+
* restart limit (`restart_limit`), and an abort (`aborted`, `abandoned`). Once the task was cut off more than
|
|
966
|
+
* `settings.restartLimit` times the hooks no longer run, since they may be what cuts it off, nor in the last attempt
|
|
967
|
+
* the scheduler gives an abort handler (restarts at the limit minus one). A result's `structuredOutput` is dropped
|
|
968
|
+
* when the Harness wrote it (a nested call a hook turns into a success gets the bounded output as a schema-less tool's
|
|
969
|
+
* does), and its `control` applies only to a call that completes (not to an interrupted, cut-off, or aborted one).
|
|
970
|
+
* An abort's hooks run inside the abort handler, which cannot be aborted: a slow hook delays `Conversation.abort()`.
|
|
971
|
+
*/
|
|
719
972
|
afterTool(call: ToolHookCall, result: ToolExecutionResult, api: HookApi, context: Context): HookResult<ToolExecutionResult>;
|
|
720
973
|
}
|
|
721
974
|
/** Hooks of the built-in compaction task. */
|
|
@@ -737,4 +990,5 @@ export interface CompactionHooks {
|
|
|
737
990
|
readonly summary: string;
|
|
738
991
|
}>;
|
|
739
992
|
}
|
|
993
|
+
export {};
|
|
740
994
|
//# sourceMappingURL=types.d.ts.map
|