@ny4n/durable 0.0.0-stage → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (303) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +711 -2
  3. package/dist/documents.d.ts +66 -0
  4. package/dist/documents.d.ts.map +1 -0
  5. package/dist/documents.js +98 -0
  6. package/dist/documents.js.map +1 -0
  7. package/dist/entries.d.ts +31 -0
  8. package/dist/entries.d.ts.map +1 -0
  9. package/dist/entries.js +31 -0
  10. package/dist/entries.js.map +1 -0
  11. package/dist/env/decode.d.ts +16 -0
  12. package/dist/env/decode.d.ts.map +1 -0
  13. package/dist/env/decode.js +28 -0
  14. package/dist/env/decode.js.map +1 -0
  15. package/dist/env/index.d.ts +263 -0
  16. package/dist/env/index.d.ts.map +1 -0
  17. package/dist/env/index.js +49 -0
  18. package/dist/env/index.js.map +1 -0
  19. package/dist/env/line-scan.d.ts +13 -0
  20. package/dist/env/line-scan.d.ts.map +1 -0
  21. package/dist/env/line-scan.js +147 -0
  22. package/dist/env/line-scan.js.map +1 -0
  23. package/dist/env/node-watch.d.ts +29 -0
  24. package/dist/env/node-watch.d.ts.map +1 -0
  25. package/dist/env/node-watch.js +485 -0
  26. package/dist/env/node-watch.js.map +1 -0
  27. package/dist/env/node.d.ts +56 -0
  28. package/dist/env/node.d.ts.map +1 -0
  29. package/dist/env/node.js +1166 -0
  30. package/dist/env/node.js.map +1 -0
  31. package/dist/errors.d.ts +32 -0
  32. package/dist/errors.d.ts.map +1 -0
  33. package/dist/errors.js +53 -0
  34. package/dist/errors.js.map +1 -0
  35. package/dist/harness/agent.d.ts +33 -0
  36. package/dist/harness/agent.d.ts.map +1 -0
  37. package/dist/harness/agent.js +235 -0
  38. package/dist/harness/agent.js.map +1 -0
  39. package/dist/harness/assistant.d.ts +15 -0
  40. package/dist/harness/assistant.d.ts.map +1 -0
  41. package/dist/harness/assistant.js +23 -0
  42. package/dist/harness/assistant.js.map +1 -0
  43. package/dist/harness/compaction.d.ts +56 -0
  44. package/dist/harness/compaction.d.ts.map +1 -0
  45. package/dist/harness/compaction.js +384 -0
  46. package/dist/harness/compaction.js.map +1 -0
  47. package/dist/harness/context.d.ts +63 -0
  48. package/dist/harness/context.d.ts.map +1 -0
  49. package/dist/harness/context.js +221 -0
  50. package/dist/harness/context.js.map +1 -0
  51. package/dist/harness/define.d.ts +18 -0
  52. package/dist/harness/define.d.ts.map +1 -0
  53. package/dist/harness/define.js +25 -0
  54. package/dist/harness/define.js.map +1 -0
  55. package/dist/harness/events.d.ts +180 -0
  56. package/dist/harness/events.d.ts.map +1 -0
  57. package/dist/harness/events.js +370 -0
  58. package/dist/harness/events.js.map +1 -0
  59. package/dist/harness/generation.d.ts +54 -0
  60. package/dist/harness/generation.d.ts.map +1 -0
  61. package/dist/harness/generation.js +514 -0
  62. package/dist/harness/generation.js.map +1 -0
  63. package/dist/harness/harness.d.ts +17 -0
  64. package/dist/harness/harness.d.ts.map +1 -0
  65. package/dist/harness/harness.js +332 -0
  66. package/dist/harness/harness.js.map +1 -0
  67. package/dist/harness/inbox.d.ts +59 -0
  68. package/dist/harness/inbox.d.ts.map +1 -0
  69. package/dist/harness/inbox.js +97 -0
  70. package/dist/harness/inbox.js.map +1 -0
  71. package/dist/harness/json.d.ts +10 -0
  72. package/dist/harness/json.d.ts.map +1 -0
  73. package/dist/harness/json.js +33 -0
  74. package/dist/harness/json.js.map +1 -0
  75. package/dist/harness/live.d.ts +142 -0
  76. package/dist/harness/live.d.ts.map +1 -0
  77. package/dist/harness/live.js +149 -0
  78. package/dist/harness/live.js.map +1 -0
  79. package/dist/harness/output.d.ts +69 -0
  80. package/dist/harness/output.d.ts.map +1 -0
  81. package/dist/harness/output.js +318 -0
  82. package/dist/harness/output.js.map +1 -0
  83. package/dist/harness/prompt.d.ts +27 -0
  84. package/dist/harness/prompt.d.ts.map +1 -0
  85. package/dist/harness/prompt.js +131 -0
  86. package/dist/harness/prompt.js.map +1 -0
  87. package/dist/harness/provider.d.ts +14 -0
  88. package/dist/harness/provider.d.ts.map +1 -0
  89. package/dist/harness/provider.js +30 -0
  90. package/dist/harness/provider.js.map +1 -0
  91. package/dist/harness/registry.d.ts +6 -0
  92. package/dist/harness/registry.d.ts.map +1 -0
  93. package/dist/harness/registry.js +101 -0
  94. package/dist/harness/registry.js.map +1 -0
  95. package/dist/harness/run.d.ts +17 -0
  96. package/dist/harness/run.d.ts.map +1 -0
  97. package/dist/harness/run.js +26 -0
  98. package/dist/harness/run.js.map +1 -0
  99. package/dist/harness/scheduler.d.ts +106 -0
  100. package/dist/harness/scheduler.d.ts.map +1 -0
  101. package/dist/harness/scheduler.js +1743 -0
  102. package/dist/harness/scheduler.js.map +1 -0
  103. package/dist/harness/submissions.d.ts +29 -0
  104. package/dist/harness/submissions.d.ts.map +1 -0
  105. package/dist/harness/submissions.js +175 -0
  106. package/dist/harness/submissions.js.map +1 -0
  107. package/dist/harness/task-graph.d.ts +49 -0
  108. package/dist/harness/task-graph.d.ts.map +1 -0
  109. package/dist/harness/task-graph.js +168 -0
  110. package/dist/harness/task-graph.js.map +1 -0
  111. package/dist/harness/tool.d.ts +76 -0
  112. package/dist/harness/tool.d.ts.map +1 -0
  113. package/dist/harness/tool.js +736 -0
  114. package/dist/harness/tool.js.map +1 -0
  115. package/dist/harness/types.d.ts +713 -0
  116. package/dist/harness/types.d.ts.map +1 -0
  117. package/dist/harness/types.js +2 -0
  118. package/dist/harness/types.js.map +1 -0
  119. package/dist/harness/usage.d.ts +18 -0
  120. package/dist/harness/usage.d.ts.map +1 -0
  121. package/dist/harness/usage.js +57 -0
  122. package/dist/harness/usage.js.map +1 -0
  123. package/dist/harness/util.d.ts +19 -0
  124. package/dist/harness/util.d.ts.map +1 -0
  125. package/dist/harness/util.js +58 -0
  126. package/dist/harness/util.js.map +1 -0
  127. package/dist/harness/view.d.ts +47 -0
  128. package/dist/harness/view.d.ts.map +1 -0
  129. package/dist/harness/view.js +206 -0
  130. package/dist/harness/view.js.map +1 -0
  131. package/dist/ids.d.ts +6 -0
  132. package/dist/ids.d.ts.map +1 -0
  133. package/dist/ids.js +9 -0
  134. package/dist/ids.js.map +1 -0
  135. package/dist/images/cloudflare.d.ts +4 -0
  136. package/dist/images/cloudflare.d.ts.map +1 -0
  137. package/dist/images/cloudflare.js +9 -0
  138. package/dist/images/cloudflare.js.map +1 -0
  139. package/dist/images/exif.d.ts +3 -0
  140. package/dist/images/exif.d.ts.map +1 -0
  141. package/dist/images/exif.js +71 -0
  142. package/dist/images/exif.js.map +1 -0
  143. package/dist/images/index.d.ts +18 -0
  144. package/dist/images/index.d.ts.map +1 -0
  145. package/dist/images/index.js +125 -0
  146. package/dist/images/index.js.map +1 -0
  147. package/dist/images/node-worker.d.ts +17 -0
  148. package/dist/images/node-worker.d.ts.map +1 -0
  149. package/dist/images/node-worker.js +16 -0
  150. package/dist/images/node-worker.js.map +1 -0
  151. package/dist/images/node.d.ts +21 -0
  152. package/dist/images/node.d.ts.map +1 -0
  153. package/dist/images/node.js +121 -0
  154. package/dist/images/node.js.map +1 -0
  155. package/dist/index.d.ts +24 -0
  156. package/dist/index.d.ts.map +1 -0
  157. package/dist/index.js +20 -0
  158. package/dist/index.js.map +1 -0
  159. package/dist/session/forks.d.ts +10 -0
  160. package/dist/session/forks.d.ts.map +1 -0
  161. package/dist/session/forks.js +42 -0
  162. package/dist/session/forks.js.map +1 -0
  163. package/dist/session/observation.d.ts +42 -0
  164. package/dist/session/observation.d.ts.map +1 -0
  165. package/dist/session/observation.js +281 -0
  166. package/dist/session/observation.js.map +1 -0
  167. package/dist/session/session.d.ts +133 -0
  168. package/dist/session/session.d.ts.map +1 -0
  169. package/dist/session/session.js +811 -0
  170. package/dist/session/session.js.map +1 -0
  171. package/dist/session/transaction.d.ts +119 -0
  172. package/dist/session/transaction.d.ts.map +1 -0
  173. package/dist/session/transaction.js +795 -0
  174. package/dist/session/transaction.js.map +1 -0
  175. package/dist/storage/jsonl/index.d.ts +2 -0
  176. package/dist/storage/jsonl/index.d.ts.map +1 -0
  177. package/dist/storage/jsonl/index.js +2 -0
  178. package/dist/storage/jsonl/index.js.map +1 -0
  179. package/dist/storage/jsonl/node.d.ts +6 -0
  180. package/dist/storage/jsonl/node.d.ts.map +1 -0
  181. package/dist/storage/jsonl/node.js +8 -0
  182. package/dist/storage/jsonl/node.js.map +1 -0
  183. package/dist/storage/jsonl/storage.d.ts +143 -0
  184. package/dist/storage/jsonl/storage.d.ts.map +1 -0
  185. package/dist/storage/jsonl/storage.js +682 -0
  186. package/dist/storage/jsonl/storage.js.map +1 -0
  187. package/dist/storage/memory.d.ts +62 -0
  188. package/dist/storage/memory.d.ts.map +1 -0
  189. package/dist/storage/memory.js +733 -0
  190. package/dist/storage/memory.js.map +1 -0
  191. package/dist/storage/scan.d.ts +18 -0
  192. package/dist/storage/scan.d.ts.map +1 -0
  193. package/dist/storage/scan.js +29 -0
  194. package/dist/storage/scan.js.map +1 -0
  195. package/dist/storage/sqlite/cloudflare.d.ts +46 -0
  196. package/dist/storage/sqlite/cloudflare.d.ts.map +1 -0
  197. package/dist/storage/sqlite/cloudflare.js +106 -0
  198. package/dist/storage/sqlite/cloudflare.js.map +1 -0
  199. package/dist/storage/sqlite/database.d.ts +37 -0
  200. package/dist/storage/sqlite/database.d.ts.map +1 -0
  201. package/dist/storage/sqlite/database.js +2 -0
  202. package/dist/storage/sqlite/database.js.map +1 -0
  203. package/dist/storage/sqlite/index.d.ts +4 -0
  204. package/dist/storage/sqlite/index.d.ts.map +1 -0
  205. package/dist/storage/sqlite/index.js +3 -0
  206. package/dist/storage/sqlite/index.js.map +1 -0
  207. package/dist/storage/sqlite/migrations.d.ts +11 -0
  208. package/dist/storage/sqlite/migrations.d.ts.map +1 -0
  209. package/dist/storage/sqlite/migrations.js +111 -0
  210. package/dist/storage/sqlite/migrations.js.map +1 -0
  211. package/dist/storage/sqlite/node.d.ts +41 -0
  212. package/dist/storage/sqlite/node.d.ts.map +1 -0
  213. package/dist/storage/sqlite/node.js +179 -0
  214. package/dist/storage/sqlite/node.js.map +1 -0
  215. package/dist/storage/sqlite/storage.d.ts +65 -0
  216. package/dist/storage/sqlite/storage.d.ts.map +1 -0
  217. package/dist/storage/sqlite/storage.js +670 -0
  218. package/dist/storage/sqlite/storage.js.map +1 -0
  219. package/dist/tasks.d.ts +6 -0
  220. package/dist/tasks.d.ts.map +1 -0
  221. package/dist/tasks.js +5 -0
  222. package/dist/tasks.js.map +1 -0
  223. package/dist/testing/assertions.d.ts +5 -0
  224. package/dist/testing/assertions.d.ts.map +1 -0
  225. package/dist/testing/assertions.js +25 -0
  226. package/dist/testing/assertions.js.map +1 -0
  227. package/dist/testing/env-conformance.d.ts +7 -0
  228. package/dist/testing/env-conformance.d.ts.map +1 -0
  229. package/dist/testing/env-conformance.js +431 -0
  230. package/dist/testing/env-conformance.js.map +1 -0
  231. package/dist/testing/index.d.ts +7 -0
  232. package/dist/testing/index.d.ts.map +1 -0
  233. package/dist/testing/index.js +6 -0
  234. package/dist/testing/index.js.map +1 -0
  235. package/dist/testing/runner.d.ts +12 -0
  236. package/dist/testing/runner.d.ts.map +1 -0
  237. package/dist/testing/runner.js +23 -0
  238. package/dist/testing/runner.js.map +1 -0
  239. package/dist/testing/storage-benchmark.d.ts +41 -0
  240. package/dist/testing/storage-benchmark.d.ts.map +1 -0
  241. package/dist/testing/storage-benchmark.js +350 -0
  242. package/dist/testing/storage-benchmark.js.map +1 -0
  243. package/dist/testing/storage-conformance.d.ts +4 -0
  244. package/dist/testing/storage-conformance.d.ts.map +1 -0
  245. package/dist/testing/storage-conformance.js +1213 -0
  246. package/dist/testing/storage-conformance.js.map +1 -0
  247. package/dist/testing/types.d.ts +37 -0
  248. package/dist/testing/types.d.ts.map +1 -0
  249. package/dist/testing/types.js +2 -0
  250. package/dist/testing/types.js.map +1 -0
  251. package/dist/tools/bash.d.ts +55 -0
  252. package/dist/tools/bash.d.ts.map +1 -0
  253. package/dist/tools/bash.js +138 -0
  254. package/dist/tools/bash.js.map +1 -0
  255. package/dist/tools/edit-diff.d.ts +89 -0
  256. package/dist/tools/edit-diff.d.ts.map +1 -0
  257. package/dist/tools/edit-diff.js +386 -0
  258. package/dist/tools/edit-diff.js.map +1 -0
  259. package/dist/tools/edit.d.ts +18 -0
  260. package/dist/tools/edit.d.ts.map +1 -0
  261. package/dist/tools/edit.js +117 -0
  262. package/dist/tools/edit.js.map +1 -0
  263. package/dist/tools/env.d.ts +5 -0
  264. package/dist/tools/env.d.ts.map +1 -0
  265. package/dist/tools/env.js +7 -0
  266. package/dist/tools/env.js.map +1 -0
  267. package/dist/tools/file-mutation-queue.d.ts +9 -0
  268. package/dist/tools/file-mutation-queue.d.ts.map +1 -0
  269. package/dist/tools/file-mutation-queue.js +52 -0
  270. package/dist/tools/file-mutation-queue.js.map +1 -0
  271. package/dist/tools/image-processor.d.ts +47 -0
  272. package/dist/tools/image-processor.d.ts.map +1 -0
  273. package/dist/tools/image-processor.js +30 -0
  274. package/dist/tools/image-processor.js.map +1 -0
  275. package/dist/tools/image.d.ts +20 -0
  276. package/dist/tools/image.d.ts.map +1 -0
  277. package/dist/tools/image.js +178 -0
  278. package/dist/tools/image.js.map +1 -0
  279. package/dist/tools/index.d.ts +46 -0
  280. package/dist/tools/index.d.ts.map +1 -0
  281. package/dist/tools/index.js +23 -0
  282. package/dist/tools/index.js.map +1 -0
  283. package/dist/tools/path-utils.d.ts +5 -0
  284. package/dist/tools/path-utils.d.ts.map +1 -0
  285. package/dist/tools/path-utils.js +26 -0
  286. package/dist/tools/path-utils.js.map +1 -0
  287. package/dist/tools/read.d.ts +25 -0
  288. package/dist/tools/read.d.ts.map +1 -0
  289. package/dist/tools/read.js +235 -0
  290. package/dist/tools/read.js.map +1 -0
  291. package/dist/tools/write.d.ts +10 -0
  292. package/dist/tools/write.d.ts.map +1 -0
  293. package/dist/tools/write.js +31 -0
  294. package/dist/tools/write.js.map +1 -0
  295. package/dist/truncate.d.ts +64 -0
  296. package/dist/truncate.d.ts.map +1 -0
  297. package/dist/truncate.js +154 -0
  298. package/dist/truncate.js.map +1 -0
  299. package/dist/types.d.ts +932 -0
  300. package/dist/types.d.ts.map +1 -0
  301. package/dist/types.js +3 -0
  302. package/dist/types.js.map +1 -0
  303. package/package.json +140 -5
@@ -0,0 +1,713 @@
1
+ import type { AssistantMessage, CacheRetention, Message, ModelRuntime, ModelThinkingLevel, Static, Tool, ToolCall, ToolResultMessage, Transport, TSchema, Usage, UserMessage } from "@ny4n/ai/contracts";
2
+ import type { AttachedReplicatedState, Context, JsonValue } from "@ny4n/chord";
3
+ 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, WatchHandle } from "../types.ts";
5
+ import type { TaskGraph, TaskGraphWatch } from "./task-graph.ts";
6
+ import type { UsageState } from "./usage.ts";
7
+ import type { ConversationView } from "./view.ts";
8
+ /** Provider and model ID resolved through the provider-neutral model runtime contract. */
9
+ export type ModelRef = {
10
+ readonly provider: string;
11
+ readonly modelId: string;
12
+ };
13
+ export type UserInput = UserMessage["content"];
14
+ /** Host submission: user input that may start a run, or a passive entry write. */
15
+ export type SubmissionDraft = {
16
+ readonly requestId?: string;
17
+ } & ({
18
+ readonly type: "input";
19
+ readonly content: UserInput;
20
+ readonly whenBusy?: "steer" | "followUp" | "reject";
21
+ readonly entry?: never;
22
+ } | {
23
+ readonly type: "write";
24
+ readonly entry: EntryDraft;
25
+ readonly content?: never;
26
+ readonly whenBusy?: never;
27
+ });
28
+ export type InputSubmissionDraft = Extract<SubmissionDraft, {
29
+ readonly type: "input";
30
+ }>;
31
+ export type SettledSubmissionRecord = SubmissionRecord & {
32
+ readonly status: "done" | "unanswered";
33
+ };
34
+ /** Awaitable host object for one durably admitted submission. */
35
+ export interface Submission {
36
+ readonly id: SubmissionId;
37
+ status(context: Context): Promise<SubmissionRecord>;
38
+ wait(context: Context): Promise<SettledSubmissionRecord>;
39
+ abort(context: Context): Promise<"aborted" | "already_placed" | "settled">;
40
+ }
41
+ export type SettledTask<R> = TaskRecord<JsonValue, JsonValue, R> & {
42
+ readonly state: Extract<TaskState<JsonValue, R>, {
43
+ readonly status: "terminal";
44
+ }>;
45
+ };
46
+ /** Erased executable task definition stored in the registry. */
47
+ export type AnyTask = {
48
+ readonly definition: {
49
+ readonly name: string;
50
+ readonly version: number;
51
+ readonly initial: unknown;
52
+ readonly phases: Readonly<Record<string, unknown>>;
53
+ readonly abort: unknown;
54
+ readonly migrate?: unknown;
55
+ readonly hooks?: object;
56
+ };
57
+ };
58
+ /** Options of `Conversation.abort()`. */
59
+ export type ConversationAbortOptions = {
60
+ /**
61
+ * Cross background boundaries: mark every live task reached ignoring the background flag when the abort is admitted,
62
+ * withdraw the queued inputs of every conversation reached, and wait until those tasks are terminal and the
63
+ * conversation is ordinarily idle. Background work created afterwards is neither marked nor awaited.
64
+ */
65
+ readonly background?: boolean;
66
+ };
67
+ /** Hook handler map declared by a task definition. */
68
+ export type HooksOf<K> = K extends Task<infer _I, infer _S, infer _R, infer H> ? H : never;
69
+ /**
70
+ * Invocation-bound conversation operations for tasks and tools. Rejects after the invocation ends; passive entries are
71
+ * written with ordinary transaction writes instead.
72
+ */
73
+ export interface ConversationHandle {
74
+ readonly id: ConversationId;
75
+ submit(submission: InputSubmissionDraft, context: Context): Promise<Submission>;
76
+ /** `Conversation.abort()`: withdraw queued inputs, abort the ordinary ownership scope, and wait until it is idle. */
77
+ abort(context: Context, options?: ConversationAbortOptions): Promise<void>;
78
+ /** Resolve when the conversation's ordinary ownership scope has no live non-background task. */
79
+ waitForIdle(context: Context): Promise<void>;
80
+ }
81
+ /** Post-tools controls requested by a tool result. */
82
+ export type ToolControl = {
83
+ readonly addTools?: readonly string[];
84
+ readonly terminate?: true;
85
+ readonly handoff?: string;
86
+ };
87
+ /** Remark about a call for the model and the UI, such as truncation or a spill path; never part of the tool's data. */
88
+ export type ToolDiagnostic = {
89
+ readonly severity: "info" | "warn" | "error";
90
+ readonly message: string;
91
+ readonly code?: string;
92
+ };
93
+ /**
94
+ * What a tool returns, on three channels: `output` for the model, `structuredOutput` for programs that call the tool
95
+ * (`executeTool()` callers, code mode scripts), and `details` for UIs.
96
+ */
97
+ export type ToolExecutionResult<TDetails extends JsonValue = JsonValue> = {
98
+ /** For the model. Omitted: the retained `output()` text. */
99
+ readonly output?: ToolResultMessage["content"];
100
+ /**
101
+ * For programs. Required unless `isError` when the tool declares `structuredOutputSchema`, and validated against it;
102
+ * not allowed without one, where programs get the output itself (`NestedToolExecutionResult.structuredOutput`).
103
+ */
104
+ readonly structuredOutput?: JsonValue;
105
+ readonly isError?: boolean;
106
+ /** Omitted: the last `details()` value becomes the details. */
107
+ readonly details?: TDetails;
108
+ /** Added after those recorded through `api.diagnostic()`. */
109
+ readonly diagnostics?: readonly ToolDiagnostic[];
110
+ /** Spend of the execution itself, such as a model call; stored on the result and in `nyan.usage.tools`. */
111
+ readonly usage?: Usage;
112
+ readonly control?: ToolControl;
113
+ };
114
+ /**
115
+ * Result of a nested call, as `executeTool()` returns it. Programs read `structuredOutput`; the output for the model
116
+ * is not kept, and `control` does not apply.
117
+ */
118
+ export type NestedToolExecutionResult = {
119
+ /** The nested call's tool task. */
120
+ readonly taskId: TaskId;
121
+ /**
122
+ * The value for programs. A tool with `structuredOutputSchema`: its validated `structuredOutput`, absent on an error
123
+ * result that has none. A tool without: its bounded output, success or error, as a string for one text item, an
124
+ * `ImageContent` for one image, `""` for none, and the content list otherwise. Absent on an error result the Harness
125
+ * wrote itself (unavailable, invalid, blocked, interrupted, aborted); `diagnostics` say what went wrong.
126
+ */
127
+ readonly structuredOutput?: JsonValue;
128
+ readonly isError: boolean;
129
+ readonly details?: JsonValue;
130
+ readonly diagnostics: readonly ToolDiagnostic[];
131
+ readonly usage?: Usage;
132
+ /** Execution time of the attempt that produced the result; absent when it never executed. */
133
+ readonly durationMs?: number;
134
+ };
135
+ /** Whether the tools of one round run at once or one after another in call order. */
136
+ export type ToolExecutionMode = "parallel" | "sequential";
137
+ /** How many queued items of one mode a boundary places: the first, or all of them. */
138
+ export type QueueMode = "all" | "one-at-a-time";
139
+ /**
140
+ * Operations available to one tool invocation. A plain object, so a wrapper can spread it. Every operation rejects after
141
+ * the invocation ends.
142
+ */
143
+ export interface ToolExecutionApi<TDetails extends JsonValue = JsonValue> extends DocumentObserver, DocumentReader {
144
+ readonly taskId: TaskId;
145
+ readonly conversationId: ConversationId;
146
+ readonly callId: string;
147
+ /** The tool task's phase snapshot. */
148
+ readonly registry: RegistrySnapshot;
149
+ /** The calling conversation's agent, as the tool task's phase resolved it. */
150
+ agent(context: Context): Promise<Agent>;
151
+ /** `HarnessOptions.models`: the catalog, credentials, and request transforms generation uses. */
152
+ readonly models: ModelRuntime;
153
+ /** Built by `HarnessOptions.env` for this call; `undefined` without an environment. */
154
+ readonly env: ExecutionEnv | undefined;
155
+ /**
156
+ * Append running output; it becomes the result's `output` when the result omits it. `skipped` counts output
157
+ * omitted before the chunk, as reported by an environment given `outputWindow` (`ShellOutputInfo.skipped`).
158
+ */
159
+ output(chunk: string | Uint8Array, skipped?: ShellOutputSkip): void;
160
+ /**
161
+ * The tail this call's output keeps and the pace of its progress commits, for `ShellExecOptions.window`; `undefined`
162
+ * when the tool keeps the head of its output, which cannot accept skips. A wrapper that replaces `output` and
163
+ * transforms text must also replace this with `undefined`, so skipped text cannot bypass its transform.
164
+ */
165
+ readonly outputWindow: ShellOutputWindow | undefined;
166
+ /**
167
+ * The output retained so far, as the model will see it when the result omits `output`, and whether earlier output was
168
+ * dropped; for a tool that also returns that text in its `structuredOutput`.
169
+ */
170
+ retainedOutput(): {
171
+ readonly text: string;
172
+ readonly truncated: boolean;
173
+ };
174
+ /** Record a model-visible remark about this call. */
175
+ diagnostic(diagnostic: ToolDiagnostic): void;
176
+ /** Replace running details; the last value becomes the result details when the result omits `details`. */
177
+ details(value: TDetails, context: Context): Promise<void>;
178
+ commit<T>(change: (tx: Tx) => T | Promise<T>, context: Context): Promise<T>;
179
+ memo<T extends JsonValue>(name: string, context: Context): Promise<T | undefined>;
180
+ memo<T extends JsonValue>(name: string, candidate: T, context: Context): Promise<T>;
181
+ /**
182
+ * Create a task in one commit. A child task of a tool that is not replay-safe defaults to `abandonOnRestart`: the
183
+ * tool never resumes after a restart, so nothing awaits the child then.
184
+ */
185
+ createTask<I, S extends {
186
+ phase: string;
187
+ }, R, H extends object>(task: Task<I, S, R, H>, input: I, options: Omit<TaskOptions, "conversationId">, context: Context): Promise<TaskId<R>>;
188
+ getTask<R>(id: TaskId<R>, context: Context): Promise<TaskRecord<JsonValue, JsonValue, R> | undefined>;
189
+ waitForTask<R>(id: TaskId<R>, context: Context): Promise<SettledTask<R>>;
190
+ /** Invocation-bound handle of an existing conversation, such as one this tool created in `commit()`. */
191
+ conversation(id: ConversationId, context: Context): Promise<ConversationHandle | undefined>;
192
+ /**
193
+ * Run tool `name` as a nested call of this one and wait for its result. The nested call is its own `nyan.tool` task,
194
+ * owned by this call: it resolves the tool among the conversation's tools, validates, runs the `ToolTask` hooks (which
195
+ * see `call.parent`), applies output limits and the tool's replay policy, and reports progress in `nyan.live.nestedTools`.
196
+ * Its result returns here instead of entering the transcript. A call that is blocked, invalid, throws, is interrupted,
197
+ * or is aborted returns an `isError` result.
198
+ *
199
+ * The nested call's key names it within this call; its call ID is `<callId>/<key>`. By default the key is the call's
200
+ * position among this invocation's nested calls, `1`, `2`, ... An explicit `key` must be non-empty, without `/`, not
201
+ * `__proto__`, and not a positive integer, so it never collides with a default one. A rerun of a replay-safe tool
202
+ * that makes a call with a used key, by calling in the same order or by passing the same `key`, gets that nested call
203
+ * back, finished or still running, instead of starting another. A nested call a crash interrupted before its result
204
+ * committed follows its own replay policy, so this is not exactly-once execution. Reusing a key with another tool or
205
+ * other arguments throws. A tool that is not replay-safe never reruns: after a restart, its unfinished nested calls
206
+ * are abandoned (`TaskOptions.abandonOnRestart`) before they run again.
207
+ *
208
+ * `progress: false` commits no running output, details, or diagnostics to the nested call's slot, only its status;
209
+ * the result still carries its details and diagnostics, and a schema-less tool's output as `structuredOutput`. An
210
+ * interrupted or aborted call's result is built from its slot, so it then has none of them. Either way, programs never
211
+ * get the partial output of an interrupted or aborted call.
212
+ *
213
+ * Nested calls run as soon as they are made, whatever their `executionMode`; the caller decides what runs at once by
214
+ * what it awaits. Cancelling `context` stops only the wait; the nested call runs on. When this call settles, nested
215
+ * calls it left running are aborted first. A nested result's `usage` is already counted under its tool; a result
216
+ * that passes it on counts it again. Rejects, instead of returning a result, once `execute()` has returned, when this
217
+ * call is aborted, or when the Harness closes.
218
+ */
219
+ executeTool(name: string, args: JsonObject, context: Context, options?: {
220
+ readonly key?: string;
221
+ readonly progress?: boolean;
222
+ }): Promise<NestedToolExecutionResult>;
223
+ }
224
+ /**
225
+ * Executable tool registered in a registry. Only nyan-ai `Tool` fields enter the transcript. `args` are typed by
226
+ * `parameters`, which the Harness validates them against before `execute()`; `defineTool()` infers both generics.
227
+ */
228
+ export type ToolRegistration<TParameters extends TSchema = TSchema, TDetails extends JsonValue = JsonValue> = Tool<TParameters> & {
229
+ /** Whether an interrupted execution may rerun on recovery. Default `unsafe`. */
230
+ readonly replay?: "safe" | "unsafe";
231
+ /** Default: the settings' `toolExecution`. One sequential call makes its whole round sequential. */
232
+ readonly executionMode?: ToolExecutionMode;
233
+ /**
234
+ * Repair arguments models commonly get wrong before validation, such as a JSON string where an array belongs. Must be
235
+ * pure and must not mutate `args`: it runs again when a call is retried before its intent is recorded. Its result is
236
+ * still validated against `parameters`.
237
+ */
238
+ prepareArguments?(args: unknown): Static<TParameters>;
239
+ /**
240
+ * Schema of `structuredOutput`, which programs that call the tool receive. Omitted: they receive the result's bounded
241
+ * output, success or error, as `NestedToolExecutionResult.structuredOutput` describes.
242
+ */
243
+ readonly structuredOutputSchema?: TSchema;
244
+ /**
245
+ * Who may call the tool: the model, other tools through `executeTool()`, or both (default). A code mode tool is
246
+ * `["model"]`, so scripts cannot start scripts; tools behind code mode, such as MCP tools, can be `["tools"]`, so the
247
+ * model is never offered them.
248
+ */
249
+ readonly callers?: readonly ("model" | "tools")[];
250
+ readonly outputLimits?: {
251
+ readonly maxBytes?: number;
252
+ readonly maxLines?: number;
253
+ readonly retain?: "head" | "tail";
254
+ };
255
+ execute(args: Static<TParameters>, api: ToolExecutionApi<TDetails>, context: Context): Promise<ToolExecutionResult<TDetails>>;
256
+ };
257
+ /** Input to system prompt section rendering for one request preparation. */
258
+ export type PromptInput<Tool extends ToolRegistration = ToolRegistration> = {
259
+ readonly conversationId: ConversationId;
260
+ /** The request's resolution; `agent.tools` are the tools offered in this request. */
261
+ readonly agent: Agent<Tool>;
262
+ /** Built by `HarnessOptions.env` for this preparation; `undefined` without an environment. */
263
+ readonly env: ExecutionEnv | undefined;
264
+ /** Sections already in effect after replaying the active transcript. */
265
+ readonly shown: Readonly<Record<string, string>>;
266
+ /** Committed document reads. */
267
+ readonly read: DocumentReader;
268
+ };
269
+ /** One system prompt section; the agent's sections render in order before each request. */
270
+ export type PromptSection<Tool extends ToolRegistration = ToolRegistration> = {
271
+ readonly key: string;
272
+ render(input: PromptInput<Tool>, context: Context): string | undefined | Promise<string | undefined>;
273
+ /** Default true: wrap the text as `<key>\n...\n</key>`. */
274
+ readonly tag?: boolean;
275
+ };
276
+ /** Built by `hook()`; matches tasks by name. */
277
+ export type HookRegistration = {
278
+ readonly task: string;
279
+ readonly handlers: object;
280
+ };
281
+ /** Built by `wrapTool()` and `wrapSection()`; targets a tool name or a section key. Wrappers are pure. */
282
+ export type Wrap<Tool extends ToolRegistration = ToolRegistration> = {
283
+ readonly tool: string;
284
+ wrap(tool: Tool): Tool;
285
+ } | {
286
+ readonly section: string;
287
+ wrap(section: PromptSection<Tool>): PromptSection<Tool>;
288
+ };
289
+ /** Named bundle of code; installed in a registry and selected by conversations by name. */
290
+ export interface Extension<Tool extends ToolRegistration = ToolRegistration> {
291
+ readonly name: string;
292
+ readonly tools?: readonly Tool[];
293
+ readonly sections?: readonly PromptSection<Tool>[];
294
+ readonly hooks?: readonly HookRegistration[];
295
+ /** Apply where this extension is selected, in order. */
296
+ readonly wraps?: readonly Wrap<Tool>[];
297
+ /** Resolved by name for every task, whichever conversations select this extension. */
298
+ readonly tasks?: readonly AnyTask[];
299
+ }
300
+ /** Immutable view of one published registry state. */
301
+ export interface RegistrySnapshot<Tool extends ToolRegistration = ToolRegistration> {
302
+ installed(): readonly Extension<Tool>[];
303
+ extension(name: string): Extension<Tool> | undefined;
304
+ /** Every installed tool with its extension, in install order. Names may repeat across extensions. */
305
+ tools(): readonly {
306
+ readonly extension: Extension<Tool>;
307
+ readonly tool: Tool;
308
+ }[];
309
+ sections(): readonly {
310
+ readonly extension: Extension<Tool>;
311
+ readonly section: PromptSection<Tool>;
312
+ }[];
313
+ /** Built-in and installed task definitions. */
314
+ tasks(): readonly AnyTask[];
315
+ task(name: string): AnyTask | undefined;
316
+ }
317
+ /** Read side of a registry consumed by a Harness. */
318
+ export interface RegistryReader<Tool extends ToolRegistration = ToolRegistration> {
319
+ /** Immutable view of the whole current registry. */
320
+ snapshot(): RegistrySnapshot<Tool>;
321
+ /** Called synchronously after every publication; wakes the scheduler to reconsider blocked tasks. */
322
+ subscribe(listener: () => void): () => void;
323
+ }
324
+ /** Application-owned registry of extensions. */
325
+ export interface Registry<Tool extends ToolRegistration = ToolRegistration> extends RegistryReader<Tool> {
326
+ /** Install `extension`, or replace the installed extension with its name in place. Publishes at once. */
327
+ install(extension: Extension<Tool>): void;
328
+ /** Remove the installed extension with `extension.name`, whichever object it is. A later install appends. */
329
+ uninstall(extension: Extension): void;
330
+ }
331
+ /** Stored choices of one conversation; names, not objects. Unset fields follow the host. */
332
+ export type AgentState = {
333
+ model?: ModelRef;
334
+ thinkingLevel?: ModelThinkingLevel;
335
+ /** An array selects exactly these extensions, in order. An object edits the host default selection. */
336
+ extensions?: string[] | {
337
+ add?: string[];
338
+ remove?: string[];
339
+ };
340
+ /** Filters the selected extensions' tools: the enabled tools. An array enables exactly these, in order. */
341
+ tools?: string[] | {
342
+ remove: string[];
343
+ };
344
+ /**
345
+ * Filters the enabled tools the model may call (`callers` includes `model`): the tools offered to it. An array offers
346
+ * exactly these, in order. Never widens: other tools can still call the ones it leaves out.
347
+ */
348
+ modelTools?: string[] | {
349
+ remove: string[];
350
+ };
351
+ /** Rendered after every extension section, as the section `instructions`. */
352
+ instructions?: string;
353
+ /** Directory within the environment's file system, passed to `HarnessOptions.env`. */
354
+ cwd?: string;
355
+ };
356
+ /** A change to `nyan.agent`: a given field replaces the stored one, `null` clears it, `undefined` changes nothing. */
357
+ export type AgentChange = {
358
+ readonly model?: ModelRef | null;
359
+ readonly thinkingLevel?: ModelThinkingLevel | null;
360
+ readonly extensions?: readonly Extension[] | {
361
+ readonly add?: readonly Extension[];
362
+ readonly remove?: readonly Extension[];
363
+ } | null;
364
+ readonly tools?: readonly ToolRegistration[] | {
365
+ readonly remove: readonly ToolRegistration[];
366
+ } | null;
367
+ readonly modelTools?: readonly ToolRegistration[] | {
368
+ readonly remove: readonly ToolRegistration[];
369
+ } | null;
370
+ readonly instructions?: string | null;
371
+ readonly cwd?: string | null;
372
+ };
373
+ /** A conversation's agent resolved against a registry snapshot and the settings. */
374
+ export type Agent<Tool extends ToolRegistration = ToolRegistration> = {
375
+ readonly model?: ModelRef;
376
+ readonly thinkingLevel: ModelThinkingLevel;
377
+ readonly extensions: readonly Extension<Tool>[];
378
+ /** The tools a request offers, in order: enabled, callable by the model, and selected by `modelTools`. */
379
+ readonly tools: readonly Tool[];
380
+ /** The tools nested calls (`executeTool()`) resolve among, in order: enabled and callable by tools. */
381
+ readonly callable: readonly Tool[];
382
+ /** Extension sections, then `instructions` when set. */
383
+ readonly sections: readonly PromptSection<Tool>[];
384
+ readonly instructions?: string;
385
+ readonly cwd?: string;
386
+ };
387
+ /**
388
+ * Runs inside the creating commit, after the creation hook and the `agent` change. The conversation creation is already
389
+ * a table write, so table reads here throw `ReadAfterWrite`; document access remains available.
390
+ */
391
+ export type ConversationInit = (tx: Tx, conversationId: ConversationId) => void | Promise<void>;
392
+ export type ConversationCreateOptions = {
393
+ readonly ownership: ConversationOwnership;
394
+ /** Applied in the creating commit after the creation hook's copy, before `init`. */
395
+ readonly agent?: AgentChange;
396
+ readonly init?: ConversationInit;
397
+ };
398
+ /** Curated nyan-ai request options; absent fields use nyan-ai defaults. */
399
+ export type ConversationStreamOptions = {
400
+ transport?: Transport;
401
+ timeoutMs?: number;
402
+ /** Provider/SDK retries inside one request attempt. */
403
+ maxRetries?: number;
404
+ maxRetryDelayMs?: number;
405
+ headers?: Record<string, string>;
406
+ metadata?: JsonObject;
407
+ cacheRetention?: CacheRetention;
408
+ deferred?: boolean | {
409
+ window?: "15m" | "1h" | "24h";
410
+ };
411
+ };
412
+ /** Durable generation attempt retries; the JSON shape of nyan-ai `RetryPolicy`. */
413
+ export type ConversationRetryPolicy = {
414
+ enabled: boolean;
415
+ maxRetries: number;
416
+ baseDelayMs: number;
417
+ maxAgentDelayMs?: number;
418
+ };
419
+ /** Automatic compaction thresholds (spec §8.7); manual compaction ignores `enabled`. */
420
+ export type CompactionPolicy = {
421
+ /** Threshold and overflow compaction. */
422
+ enabled: boolean;
423
+ /** Room kept free for the answer: generation blocks to compact above `contextWindow - reserveTokens`. */
424
+ reserveTokens: number;
425
+ /** Approximate size of the recent context a summary keeps verbatim. */
426
+ keepRecentTokens: number;
427
+ /** Background compaction starts `backgroundTokens` below the blocking threshold; `0` disables it. */
428
+ backgroundTokens: number;
429
+ };
430
+ /**
431
+ * How often running progress is committed. Each progress commit is a storage write; a host whose storage is remote can
432
+ * commit less often, so live answers and tool output appear in larger steps.
433
+ */
434
+ export type ProgressPolicy = {
435
+ /** Minimum pause between commits of the answer being generated. */
436
+ partialIntervalMs: number;
437
+ /** Minimum pause between commits of running tool output; large commits also pause in proportion to their size. */
438
+ outputIntervalMs: number;
439
+ };
440
+ /** Why a compaction runs: `compact()`, a threshold in generation preparation, or a context overflow. */
441
+ export type CompactionReason = "manual" | "threshold" | "overflow";
442
+ /**
443
+ * `entryId` of a blocking compaction's summary, or the `submissionId` of a conversation-owned compaction's summary
444
+ * write; both absent when nothing was compacted.
445
+ */
446
+ export type CompactionResult = {
447
+ entryId?: EntryId;
448
+ submissionId?: SubmissionId;
449
+ };
450
+ /** Harness-wide run policy. Read at every resolution and never copied; getters are fine. Synchronous: some readers run on the Session line. */
451
+ export type HarnessSettings = {
452
+ /** Default extension selection; absent: every installed extension, in install order. */
453
+ readonly extensions?: readonly Extension[];
454
+ readonly stream?: ConversationStreamOptions;
455
+ readonly retry?: Partial<ConversationRetryPolicy>;
456
+ readonly compaction?: Partial<CompactionPolicy>;
457
+ readonly progress?: Partial<ProgressPolicy>;
458
+ readonly toolExecution?: ToolExecutionMode;
459
+ readonly steeringMode?: QueueMode;
460
+ readonly followUpMode?: QueueMode;
461
+ /**
462
+ * How long an idle conversation keeps its last context read in memory, so its next run reads only newer entries.
463
+ * Busy conversations always keep it; `0` drops it once the conversation is idle.
464
+ */
465
+ readonly contextRetentionMs?: number;
466
+ /**
467
+ * How long a loaded document that no watch or document state observes stays in memory after its last read or write;
468
+ * the next access loads it from Storage. Observed documents always stay. Default ten minutes; `0` drops one right
469
+ * after use; `Infinity` keeps them. Anything else that is not a number of milliseconds means the default.
470
+ */
471
+ readonly documentRetentionMs?: number;
472
+ };
473
+ /** Resolved settings: every field over its built-in default, object fields merged. */
474
+ export type Settings = {
475
+ /** Absent: every installed extension, in install order. */
476
+ readonly extensions?: readonly Extension[];
477
+ readonly stream: ConversationStreamOptions;
478
+ readonly retry: ConversationRetryPolicy;
479
+ readonly compaction: CompactionPolicy;
480
+ readonly progress: ProgressPolicy;
481
+ readonly toolExecution: ToolExecutionMode;
482
+ readonly steeringMode: QueueMode;
483
+ readonly followUpMode: QueueMode;
484
+ readonly contextRetentionMs: number;
485
+ readonly documentRetentionMs: number;
486
+ };
487
+ /** What `HarnessOptions.env` builds an environment for. */
488
+ export type EnvTarget = {
489
+ readonly conversationId: ConversationId;
490
+ /** The conversation's agent `cwd`. */
491
+ readonly cwd?: string;
492
+ readonly read: DocumentReader;
493
+ };
494
+ export type HarnessOptions<Tool extends ToolRegistration = ToolRegistration> = {
495
+ /** Provider-neutral model operations used by generation. */
496
+ readonly models: ModelRuntime;
497
+ readonly registry: RegistryReader<Tool>;
498
+ readonly settings?: HarnessSettings;
499
+ /** Builds a conversation's environment at each use. Never called on the Session line; may be async. */
500
+ readonly env?: (target: EnvTarget, context: Context) => ExecutionEnv | undefined | Promise<ExecutionEnv | undefined>;
501
+ /**
502
+ * Runs in every commit that creates or forks a conversation, raw `tx.createConversation()` included, after the
503
+ * built-in `nyan.*` documents and before the conveniences apply `agent` and run `init`. A fork already has its copies.
504
+ * Table reads throw `ReadAfterWrite`, as in `init`; a throw fails the creating commit.
505
+ */
506
+ readonly conversationCreated?: (tx: Tx, conversation: ConversationRecord) => void | Promise<void>;
507
+ readonly now?: () => number;
508
+ /**
509
+ * Receives failures that do not fail the calling operation, such as a throwing hook or listener, and the error that
510
+ * fails the Session, once. Its own throw or rejection is dropped.
511
+ */
512
+ readonly onReport?: (error: unknown) => void;
513
+ };
514
+ /** Live task and what the scheduler would do with it under the current registry. */
515
+ export type TaskInspection = {
516
+ readonly record: TaskRecord<JsonValue, JsonValue, JsonValue>;
517
+ readonly state: {
518
+ readonly kind: "running";
519
+ }
520
+ /** The next scheduling pass reserves it; `migrates` when its definition is newer and has `migrate`. */
521
+ | {
522
+ readonly kind: "ready";
523
+ readonly migrates: boolean;
524
+ }
525
+ /**
526
+ * Waits for these live tasks: the live part of its `on`, or, when abort-marked, its live ordinary owned work, which
527
+ * must end before its abort handler starts.
528
+ */
529
+ | {
530
+ readonly kind: "waiting";
531
+ readonly on: readonly TaskId[];
532
+ }
533
+ /** Outcome held until its ordinary owned work drains. */
534
+ | {
535
+ readonly kind: "completing";
536
+ }
537
+ /** No registered definition can take it; aborting it settles it as `orphaned`. */
538
+ | {
539
+ readonly kind: "blocked";
540
+ readonly reason: "missing_task" | "task_too_old" | "migration_failed";
541
+ readonly error?: unknown;
542
+ };
543
+ };
544
+ /** Point-in-time view of live work: unfinished tasks and submissions, read on the Session line. */
545
+ export type HarnessInspection = {
546
+ readonly scheduling: "paused" | "running" | "closing";
547
+ readonly tasks: readonly TaskInspection[];
548
+ /** Queued and placed submissions, in ID order. */
549
+ readonly submissions: readonly SubmissionRecord[];
550
+ };
551
+ /** Raw active transcript and derived model context. */
552
+ export type ContextView = {
553
+ /** Newest applicable head marker, if any. */
554
+ readonly head: EntryRecord | undefined;
555
+ /** Raw active entries: the head marker followed by non-head entries from its head through the tail. */
556
+ readonly entries: readonly EntryRecord[];
557
+ /** Per entry of `entries`, its model messages after edits and excluded stop reasons, before tool result ordering. */
558
+ readonly contributions: readonly (readonly Message[])[];
559
+ /** Model context for the next provider request. */
560
+ readonly messages: readonly Message[];
561
+ };
562
+ /** Stateless handle for one conversation, bound to the Harness that returned it. Compare handles by `id`. */
563
+ export interface Conversation {
564
+ readonly id: ConversationId;
565
+ /** Resolved with the current registry snapshot and settings. */
566
+ agent(context: Context): Promise<Agent>;
567
+ /** `configure()` in its own commit. */
568
+ configure(change: AgentChange, context: Context): Promise<void>;
569
+ /**
570
+ * Durably admit user input or a passive entry write. A busy conversation, or one with queued items, queues it in
571
+ * `nyan.inbox`; `whenBusy: "reject"` rejects with `ConversationBusy` instead and writes nothing.
572
+ */
573
+ submit(submission: SubmissionDraft, context: Context): Promise<Submission>;
574
+ /**
575
+ * Admit a write of a `nyan.reset` entry that starts a new context, carrying `handoff` as a user message when given.
576
+ * Resolves after admission; while busy, it is placed at the next boundary.
577
+ */
578
+ reset(handoff: string | undefined, context: Context): Promise<void>;
579
+ /**
580
+ * Admit a manual compaction task and return its ID. It summarizes while the conversation keeps working and places its
581
+ * summary through a write submission: at once when idle, otherwise at the next boundary (spec §8.7).
582
+ */
583
+ compact(instructions: string | undefined, context: Context): Promise<TaskId<CompactionResult>>;
584
+ /** Session commit whose `tx.createTask()` defaults to this conversation. */
585
+ commit<T>(change: (tx: Tx) => T | Promise<T>, context: Context): Promise<T>;
586
+ /**
587
+ * Committed raw active transcript and model context. With `at`, the context as of that visible entry: the same view
588
+ * `fork(at)` would start with, without creating a conversation.
589
+ */
590
+ context(context: Context, options?: {
591
+ readonly at?: EntryId;
592
+ }): Promise<ContextView>;
593
+ /** Fork-aware history of this conversation, newest first unless `query.order` is `ascending`. */
594
+ entries(query: Omit<EntryQuery, "conversationId">, limit: number, cursor: Cursor | undefined, context: Context): Promise<Page<EntryRecord, Cursor>>;
595
+ fork(at: EntryId, options: ConversationCreateOptions, context: Context): Promise<Conversation>;
596
+ /**
597
+ * Withdraw queued inputs (queued writes stay), mark every live non-background task of the ordinary ownership scope,
598
+ * signal them, and resolve once the scope is idle. Background subtrees survive unless `background` is set.
599
+ */
600
+ abort(context: Context, options?: ConversationAbortOptions): Promise<void>;
601
+ /**
602
+ * Resolve when the ordinary ownership scope has no live non-background task: this conversation and the conversations
603
+ * owned, transitively, by its non-background tasks.
604
+ */
605
+ waitForIdle(context: Context): Promise<void>;
606
+ /** The structural view (spec §9.3) as a disposable read-only Chord state. */
607
+ viewState(context: Context): Promise<AttachedReplicatedState<ConversationView>>;
608
+ /** The structural view as a serialized exact-frame watch with bounded pending frames. */
609
+ watch(context: Context): Promise<ConversationWatch>;
610
+ }
611
+ export type ConversationWatch = WatchHandle<ConversationView>;
612
+ /** Durable agent harness over one Session. */
613
+ export interface Harness extends Session {
614
+ /**
615
+ * Enable task scheduling. Idempotent; throws after close. Calls that ask for progress enable it too:
616
+ * `Conversation.submit()`, `Conversation.compact()`, `Conversation.abort()`, `Submission.wait()`, `waitForTask()`,
617
+ * `Harness.waitForIdle()`, and `Conversation.waitForIdle()`. Read-only viewers never do.
618
+ */
619
+ resume(): void;
620
+ /** Return the reserved root conversation, creating it with `agent` and `init` in one commit when absent. */
621
+ root(context: Context, options?: {
622
+ readonly agent?: AgentChange;
623
+ readonly init?: ConversationInit;
624
+ }): Promise<Conversation>;
625
+ conversation(id: ConversationId, context: Context): Promise<Conversation | undefined>;
626
+ createConversation(options: ConversationCreateOptions, context: Context): Promise<Conversation>;
627
+ getTask<R>(id: TaskId<R>, context: Context): Promise<TaskRecord<JsonValue, JsonValue, R> | undefined>;
628
+ /** Live tasks and unsettled submissions. Writes nothing and runs no task code. */
629
+ inspect(context: Context): Promise<HarnessInspection>;
630
+ /** Reacquire a submission, for example after reopen. */
631
+ submission(id: SubmissionId, context: Context): Promise<Submission | undefined>;
632
+ /** `not_found` for an unknown submission or one of another conversation than `conversationId`. */
633
+ abortSubmission(id: SubmissionId, context: Context, conversationId?: ConversationId): Promise<"aborted" | "already_placed" | "settled" | "not_found">;
634
+ /**
635
+ * Commit the abort mark, signal and join an active run invocation, and schedule the abort invocation. A task whose
636
+ * definition cannot take it settles as `orphaned` instead.
637
+ */
638
+ abortTask(id: TaskId, context: Context): Promise<"marked" | "terminal">;
639
+ /** Resolve with the terminal receipt; cancelling `context` cancels only this wait. */
640
+ waitForTask<R>(id: TaskId<R>, context: Context): Promise<SettledTask<R>>;
641
+ /** Resolve when the ordinary ownership scope of every ownerless conversation has no live non-background task. */
642
+ waitForIdle(context: Context): Promise<void>;
643
+ /** Session total: every conversation's `nyan.usage` summed. */
644
+ usage(context: Context): Promise<UsageState>;
645
+ /** Every live task with its owner edge, status, and owned conversations (spec §9.5), as a disposable Chord state. */
646
+ taskGraph(context: Context): Promise<AttachedReplicatedState<TaskGraph>>;
647
+ /** The task graph as a serialized exact-frame watch with bounded pending frames. */
648
+ watchTaskGraph(context: Context): Promise<TaskGraphWatch>;
649
+ }
650
+ /** What a hook may use: committed reads and the asking task's memos, which hooks and the task share. */
651
+ export interface HookApi extends DocumentReader {
652
+ readonly taskId: TaskId;
653
+ readonly conversationId: ConversationId;
654
+ /** `HarnessOptions.models`. */
655
+ readonly models: ModelRuntime;
656
+ memo<T extends JsonValue>(name: string, context: Context): Promise<T | undefined>;
657
+ memo<T extends JsonValue>(name: string, candidate: T, context: Context): Promise<T>;
658
+ }
659
+ export type HookResult<T> = T | undefined | Promise<T | undefined>;
660
+ /** Hooks of the built-in generation task. */
661
+ export interface GenerationHooks {
662
+ /** Before every request attempt, including recovery; the result is used for that request only. */
663
+ beforeRequest(request: {
664
+ readonly messages: readonly Message[];
665
+ }, api: HookApi, context: Context): HookResult<{
666
+ readonly messages: readonly Message[];
667
+ }>;
668
+ /** Every terminal provider message, before classification. */
669
+ afterResponse(message: AssistantMessage, api: HookApi, context: Context): void | Promise<void>;
670
+ /** A final answer; the first `continue` appends a user message and continues the run. */
671
+ onYield(answer: AssistantMessage, api: HookApi, context: Context): HookResult<{
672
+ readonly continue: UserInput;
673
+ }>;
674
+ /** After every tool of the round is terminal; `results` are the round's result entries in call order. */
675
+ afterTools(assistant: EntryId, results: readonly EntryId[], api: HookApi, context: Context): void | Promise<void>;
676
+ }
677
+ /** A call as tool hooks see it; `parent` is set for a nested call, one a running tool made through `executeTool()`. */
678
+ export type ToolHookCall = ToolCall & {
679
+ readonly parent?: {
680
+ readonly taskId: TaskId;
681
+ readonly callId: string;
682
+ };
683
+ };
684
+ /** Hooks of the built-in tool task, for model-issued and nested calls. */
685
+ export interface ToolHooks {
686
+ /** Before intent; the first `block` wins, otherwise `arguments` replace the call's arguments. A throw blocks. */
687
+ beforeTool(call: ToolHookCall, api: HookApi, context: Context): HookResult<{
688
+ readonly arguments?: JsonObject;
689
+ readonly block?: string;
690
+ }>;
691
+ /** After execution, before the result is committed; replaces the result. */
692
+ afterTool(call: ToolHookCall, result: ToolExecutionResult, api: HookApi, context: Context): HookResult<ToolExecutionResult>;
693
+ }
694
+ /** Hooks of the built-in compaction task. */
695
+ export interface CompactionHooks {
696
+ /**
697
+ * After range selection, before summarizing; the first decision wins. `entries` are the active entries the summary
698
+ * replaces, the head marker first, and `messages` their model context, the summarizer's source; `firstKept` is the
699
+ * first entry kept verbatim.
700
+ */
701
+ beforeCompact(compaction: {
702
+ readonly reason: CompactionReason;
703
+ readonly entries: readonly EntryRecord[];
704
+ readonly messages: readonly Message[];
705
+ readonly firstKept: EntryId;
706
+ readonly instructions?: string;
707
+ }, api: HookApi, context: Context): HookResult<{
708
+ readonly decline: true;
709
+ } | {
710
+ readonly summary: string;
711
+ }>;
712
+ }
713
+ //# sourceMappingURL=types.d.ts.map