@code-yeongyu/senpi-agent-core 2026.8.12 → 2026.8.13

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 (153) hide show
  1. package/README.md +13 -7
  2. package/dist/agent-loop.js +5 -1
  3. package/dist/agent-loop.js.map +1 -1
  4. package/dist/agent.d.ts +3 -1
  5. package/dist/agent.d.ts.map +1 -1
  6. package/dist/agent.js +8 -0
  7. package/dist/agent.js.map +1 -1
  8. package/dist/harness/agent-harness.d.ts +452 -96
  9. package/dist/harness/agent-harness.d.ts.map +1 -1
  10. package/dist/harness/agent-harness.js +162 -1005
  11. package/dist/harness/agent-harness.js.map +1 -1
  12. package/dist/harness/compaction/branch-summarization.d.ts +13 -6
  13. package/dist/harness/compaction/branch-summarization.d.ts.map +1 -1
  14. package/dist/harness/compaction/branch-summarization.js +10 -14
  15. package/dist/harness/compaction/branch-summarization.js.map +1 -1
  16. package/dist/harness/compaction/compaction.d.ts +14 -17
  17. package/dist/harness/compaction/compaction.d.ts.map +1 -1
  18. package/dist/harness/compaction/compaction.js +23 -36
  19. package/dist/harness/compaction/compaction.js.map +1 -1
  20. package/dist/harness/env/nodejs.d.ts +1 -0
  21. package/dist/harness/env/nodejs.d.ts.map +1 -1
  22. package/dist/harness/env/nodejs.js +23 -7
  23. package/dist/harness/env/nodejs.js.map +1 -1
  24. package/dist/harness/messages.d.ts +3 -3
  25. package/dist/harness/messages.d.ts.map +1 -1
  26. package/dist/harness/messages.js +3 -3
  27. package/dist/harness/messages.js.map +1 -1
  28. package/dist/harness/prompt-templates.d.ts.map +1 -1
  29. package/dist/harness/prompt-templates.js +4 -9
  30. package/dist/harness/prompt-templates.js.map +1 -1
  31. package/dist/harness/reducer.d.ts +100 -0
  32. package/dist/harness/reducer.d.ts.map +1 -0
  33. package/dist/harness/reducer.js +414 -0
  34. package/dist/harness/reducer.js.map +1 -0
  35. package/dist/harness/result.d.ts +40 -0
  36. package/dist/harness/result.d.ts.map +1 -0
  37. package/dist/harness/result.js +41 -0
  38. package/dist/harness/result.js.map +1 -0
  39. package/dist/harness/session/context.d.ts +22 -0
  40. package/dist/harness/session/context.d.ts.map +1 -0
  41. package/dist/harness/session/context.js +67 -0
  42. package/dist/harness/session/context.js.map +1 -0
  43. package/dist/harness/session/index.d.ts +7 -0
  44. package/dist/harness/session/index.d.ts.map +1 -0
  45. package/dist/harness/session/index.js +6 -0
  46. package/dist/harness/session/index.js.map +1 -0
  47. package/dist/harness/session/jsonl/codec.d.ts +8 -0
  48. package/dist/harness/session/jsonl/codec.d.ts.map +1 -0
  49. package/dist/harness/session/jsonl/codec.js +190 -0
  50. package/dist/harness/session/jsonl/codec.js.map +1 -0
  51. package/dist/harness/session/jsonl/errors.d.ts +5 -0
  52. package/dist/harness/session/jsonl/errors.d.ts.map +1 -0
  53. package/dist/harness/session/jsonl/errors.js +11 -0
  54. package/dist/harness/session/jsonl/errors.js.map +1 -0
  55. package/dist/harness/session/jsonl/repo.d.ts +23 -0
  56. package/dist/harness/session/jsonl/repo.d.ts.map +1 -0
  57. package/dist/harness/session/jsonl/repo.js +129 -0
  58. package/dist/harness/session/jsonl/repo.js.map +1 -0
  59. package/dist/harness/session/jsonl/storage.d.ts +43 -0
  60. package/dist/harness/session/jsonl/storage.d.ts.map +1 -0
  61. package/dist/harness/session/jsonl/storage.js +206 -0
  62. package/dist/harness/session/jsonl/storage.js.map +1 -0
  63. package/dist/harness/session/jsonl/types.d.ts +38 -0
  64. package/dist/harness/session/jsonl/types.d.ts.map +1 -0
  65. package/dist/harness/session/jsonl/types.js +2 -0
  66. package/dist/harness/session/jsonl/types.js.map +1 -0
  67. package/dist/harness/session/jsonl.d.ts +3 -0
  68. package/dist/harness/session/jsonl.d.ts.map +1 -0
  69. package/dist/harness/session/jsonl.js +2 -0
  70. package/dist/harness/session/jsonl.js.map +1 -0
  71. package/dist/harness/session/memory.d.ts +44 -0
  72. package/dist/harness/session/memory.d.ts.map +1 -0
  73. package/dist/harness/session/memory.js +142 -0
  74. package/dist/harness/session/memory.js.map +1 -0
  75. package/dist/harness/session/search.d.ts +19 -0
  76. package/dist/harness/session/search.d.ts.map +1 -0
  77. package/dist/harness/session/search.js +41 -0
  78. package/dist/harness/session/search.js.map +1 -0
  79. package/dist/harness/session/session.d.ts +43 -38
  80. package/dist/harness/session/session.d.ts.map +1 -1
  81. package/dist/harness/session/session.js +186 -304
  82. package/dist/harness/session/session.js.map +1 -1
  83. package/dist/harness/session/state.d.ts +65 -0
  84. package/dist/harness/session/state.d.ts.map +1 -0
  85. package/dist/harness/session/state.js +320 -0
  86. package/dist/harness/session/state.js.map +1 -0
  87. package/dist/harness/session/testing/conformance.d.ts +4 -0
  88. package/dist/harness/session/testing/conformance.d.ts.map +1 -0
  89. package/dist/harness/session/testing/conformance.js +743 -0
  90. package/dist/harness/session/testing/conformance.js.map +1 -0
  91. package/dist/harness/session/testing/index.d.ts +3 -0
  92. package/dist/harness/session/testing/index.d.ts.map +1 -0
  93. package/dist/harness/session/testing/index.js +2 -0
  94. package/dist/harness/session/testing/index.js.map +1 -0
  95. package/dist/harness/session/testing/types.d.ts +14 -0
  96. package/dist/harness/session/testing/types.d.ts.map +1 -0
  97. package/dist/harness/session/testing/types.js +2 -0
  98. package/dist/harness/session/testing/types.js.map +1 -0
  99. package/dist/harness/session/types.d.ts +333 -0
  100. package/dist/harness/session/types.d.ts.map +1 -0
  101. package/dist/harness/session/types.js +9 -0
  102. package/dist/harness/session/types.js.map +1 -0
  103. package/dist/harness/skills.js +21 -19
  104. package/dist/harness/skills.js.map +1 -1
  105. package/dist/harness/telemetry.d.ts +1221 -0
  106. package/dist/harness/telemetry.d.ts.map +1 -0
  107. package/dist/harness/telemetry.js +508 -0
  108. package/dist/harness/telemetry.js.map +1 -0
  109. package/dist/harness/types.d.ts +8 -485
  110. package/dist/harness/types.d.ts.map +1 -1
  111. package/dist/harness/types.js +4 -16
  112. package/dist/harness/types.js.map +1 -1
  113. package/dist/harness/utils/truncate.js.map +1 -1
  114. package/dist/index.d.ts +10 -9
  115. package/dist/index.d.ts.map +1 -1
  116. package/dist/index.js +7 -8
  117. package/dist/index.js.map +1 -1
  118. package/dist/proxy.d.ts +1 -1
  119. package/dist/proxy.d.ts.map +1 -1
  120. package/dist/proxy.js +1 -0
  121. package/dist/proxy.js.map +1 -1
  122. package/dist/types.d.ts +6 -0
  123. package/dist/types.d.ts.map +1 -1
  124. package/dist/types.js.map +1 -1
  125. package/package.json +9 -2
  126. package/dist/harness/session/array-session-reader.d.ts +0 -3
  127. package/dist/harness/session/array-session-reader.d.ts.map +0 -1
  128. package/dist/harness/session/array-session-reader.js +0 -70
  129. package/dist/harness/session/array-session-reader.js.map +0 -1
  130. package/dist/harness/session/fork.d.ts +0 -4
  131. package/dist/harness/session/fork.d.ts.map +0 -1
  132. package/dist/harness/session/fork.js +0 -22
  133. package/dist/harness/session/fork.js.map +0 -1
  134. package/dist/harness/session/jsonl-store.d.ts +0 -13
  135. package/dist/harness/session/jsonl-store.d.ts.map +0 -1
  136. package/dist/harness/session/jsonl-store.js +0 -304
  137. package/dist/harness/session/jsonl-store.js.map +0 -1
  138. package/dist/harness/session/keyed-operation-queue.d.ts +0 -17
  139. package/dist/harness/session/keyed-operation-queue.d.ts.map +0 -1
  140. package/dist/harness/session/keyed-operation-queue.js +0 -60
  141. package/dist/harness/session/keyed-operation-queue.js.map +0 -1
  142. package/dist/harness/session/memory-store.d.ts +0 -6
  143. package/dist/harness/session/memory-store.d.ts.map +0 -1
  144. package/dist/harness/session/memory-store.js +0 -107
  145. package/dist/harness/session/memory-store.js.map +0 -1
  146. package/dist/harness/session/repository.d.ts +0 -28
  147. package/dist/harness/session/repository.d.ts.map +0 -1
  148. package/dist/harness/session/repository.js +0 -61
  149. package/dist/harness/session/repository.js.map +0 -1
  150. package/dist/harness/session/search-backend.d.ts +0 -8
  151. package/dist/harness/session/search-backend.d.ts.map +0 -1
  152. package/dist/harness/session/search-backend.js +0 -22
  153. package/dist/harness/session/search-backend.js.map +0 -1
@@ -1,1077 +1,234 @@
1
- import { contentText, } from "@earendil-works/pi-ai";
2
- import { runAgentLoop } from "../agent-loop.js";
3
- import { collectEntriesForBranchSummary, generateBranchSummary } from "./compaction/branch-summarization.js";
4
- import { compact, DEFAULT_COMPACTION_SETTINGS, prepareCompaction } from "./compaction/compaction.js";
5
- import { convertToLlm } from "./messages.js";
6
- import { formatPromptTemplateInvocation } from "./prompt-templates.js";
7
- import { formatSkillInvocation } from "./skills.js";
8
- import { AgentHarnessError, BranchSummaryError, CompactionError, SessionError, toError } from "./types.js";
9
- function createUserMessage(text, images) {
10
- const content = [{ type: "text", text }];
11
- if (images)
12
- content.push(...images);
13
- return { role: "user", content, timestamp: Date.now() };
1
+ import { TaggedError } from "./result.js";
2
+ export class LaneBusy extends TaggedError("LaneBusy") {
14
3
  }
15
- function createFailureMessage(model, error, aborted) {
16
- return {
17
- role: "assistant",
18
- content: [{ type: "text", text: "" }],
19
- api: model.api,
20
- provider: model.provider,
21
- model: model.id,
22
- stopReason: aborted ? "aborted" : "error",
23
- errorMessage: error instanceof Error ? error.message : String(error),
24
- timestamp: Date.now(),
25
- usage: {
26
- input: 0,
27
- output: 0,
28
- cacheRead: 0,
29
- cacheWrite: 0,
30
- totalTokens: 0,
31
- cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
32
- },
33
- };
4
+ export class MissingIdentities extends TaggedError("MissingIdentities") {
34
5
  }
35
- function cloneStreamOptions(streamOptions) {
36
- return {
37
- ...streamOptions,
38
- headers: streamOptions?.headers ? { ...streamOptions.headers } : undefined,
39
- metadata: streamOptions?.metadata ? { ...streamOptions.metadata } : undefined,
40
- };
6
+ export class NoActiveRun extends TaggedError("NoActiveRun") {
41
7
  }
42
- function _mergeHeaders(...headers) {
43
- const merged = {};
44
- let hasHeaders = false;
45
- for (const entry of headers) {
46
- if (!entry)
47
- continue;
48
- Object.assign(merged, entry);
49
- hasHeaders = true;
50
- }
51
- return hasHeaders ? merged : undefined;
8
+ export class NoActiveOperation extends TaggedError("NoActiveOperation") {
52
9
  }
53
- const objectHasOwnProperty = Object.prototype.hasOwnProperty;
54
- function hasOwn(object, key) {
55
- return objectHasOwnProperty.call(object, key);
10
+ export class NothingToResume extends TaggedError("NothingToResume") {
56
11
  }
57
- function findDuplicateNames(names) {
58
- const seen = new Set();
59
- const duplicates = new Set();
60
- for (const name of names) {
61
- if (seen.has(name))
62
- duplicates.add(name);
63
- seen.add(name);
64
- }
65
- return [...duplicates];
12
+ export class InvalidMessage extends TaggedError("InvalidMessage") {
13
+ }
14
+ export class UnknownSkill extends TaggedError("UnknownSkill") {
15
+ }
16
+ export class UnknownTemplate extends TaggedError("UnknownTemplate") {
17
+ }
18
+ export class UnknownTarget extends TaggedError("UnknownTarget") {
19
+ }
20
+ export class UnknownQueueItem extends TaggedError("UnknownQueueItem") {
21
+ }
22
+ export class LaneExists extends TaggedError("LaneExists") {
66
23
  }
67
- function applyStreamOptionsPatch(base, patch) {
68
- const result = cloneStreamOptions(base);
69
- if (!patch)
70
- return result;
71
- if (hasOwn(patch, "transport"))
72
- result.transport = patch.transport;
73
- if (hasOwn(patch, "timeoutMs"))
74
- result.timeoutMs = patch.timeoutMs;
75
- if (hasOwn(patch, "maxRetries"))
76
- result.maxRetries = patch.maxRetries;
77
- if (hasOwn(patch, "maxRetryDelayMs"))
78
- result.maxRetryDelayMs = patch.maxRetryDelayMs;
79
- if (hasOwn(patch, "cacheRetention"))
80
- result.cacheRetention = patch.cacheRetention;
81
- if (hasOwn(patch, "headers")) {
82
- if (patch.headers === undefined) {
83
- result.headers = undefined;
84
- }
85
- else {
86
- const headers = { ...(result.headers ?? {}) };
87
- for (const [key, value] of Object.entries(patch.headers)) {
88
- if (value === undefined)
89
- delete headers[key];
90
- else
91
- headers[key] = value;
92
- }
93
- result.headers = Object.keys(headers).length > 0 ? headers : undefined;
94
- }
24
+ export class InvalidLane extends TaggedError("InvalidLane") {
25
+ }
26
+ export class NothingToCompact extends TaggedError("NothingToCompact") {
27
+ }
28
+ export class Closed extends TaggedError("Closed") {
29
+ }
30
+ export class HarnessFault extends Error {
31
+ constructor(message, cause) {
32
+ super(message);
33
+ this.name = "HarnessFault";
34
+ this.cause = cause;
95
35
  }
96
- if (hasOwn(patch, "metadata")) {
97
- if (patch.metadata === undefined) {
98
- result.metadata = undefined;
99
- }
100
- else {
101
- const metadata = { ...(result.metadata ?? {}) };
102
- for (const [key, value] of Object.entries(patch.metadata)) {
103
- if (value === undefined)
104
- delete metadata[key];
105
- else
106
- metadata[key] = value;
107
- }
108
- result.metadata = Object.keys(metadata).length > 0 ? metadata : undefined;
109
- }
36
+ }
37
+ export class HarnessClosed extends Error {
38
+ constructor() {
39
+ super("AgentHarness was closed while the operation was active");
40
+ this.name = "HarnessClosed";
110
41
  }
111
- return result;
112
42
  }
113
- const SUBSCRIBER_EVENT_TYPE = "*";
114
- function normalizeHarnessError(error, fallbackCode) {
115
- if (error instanceof AgentHarnessError)
116
- return error;
117
- const cause = toError(error);
118
- if (cause instanceof SessionError)
119
- return new AgentHarnessError("session", cause.message, cause);
120
- if (cause instanceof CompactionError)
121
- return new AgentHarnessError("compaction", cause.message, cause);
122
- if (cause instanceof BranchSummaryError)
123
- return new AgentHarnessError("branch_summary", cause.message, cause);
124
- return new AgentHarnessError(fallbackCode, cause.message, cause);
43
+ export class HarnessNotImplemented extends Error {
44
+ constructor(operation) {
45
+ super(`AgentHarness.${operation} is not implemented yet`);
46
+ this.name = "HarnessNotImplemented";
47
+ this.operation = operation;
48
+ }
125
49
  }
126
- function normalizeHookError(error) {
127
- return normalizeHarnessError(error, "hook");
50
+ class UnavailableRegistry {
51
+ constructor(operation, isClosed) {
52
+ this.operation = operation;
53
+ this.isClosed = isClosed;
54
+ }
55
+ on(_name, _handler, _options) {
56
+ throw this.isClosed() ? new HarnessClosed() : new HarnessNotImplemented(this.operation);
57
+ }
128
58
  }
129
59
  export class AgentHarness {
130
60
  constructor(options) {
131
- this.phase = "idle";
132
- this.activeTasks = new Map();
133
- this.isShutdown = false;
134
- this.pendingSessionWrites = [];
135
- this.tools = new Map();
136
- this.steerQueue = [];
137
- this.followUpQueue = [];
138
- this.nextTurnQueue = [];
139
- this.handlers = new Map();
61
+ this.name = "main";
62
+ this.closed = false;
63
+ this.durableSession = options.session;
140
64
  this.session = options.session;
141
- this.models = options.models;
142
- this.resources = options.resources ?? {};
143
- this.streamOptions = cloneStreamOptions(options.streamOptions);
144
- this.retry = options.retry;
145
- this.systemPrompt = options.systemPrompt;
146
- this.toolContext = options.toolContext;
147
- this.validateUniqueNames((options.tools ?? []).map((tool) => tool.name), "Duplicate tool name(s)");
148
- for (const tool of options.tools ?? []) {
149
- this.tools.set(tool.name, tool);
150
- }
65
+ this.hooks = new UnavailableRegistry("hooks.on", () => this.closed);
66
+ this.events = new UnavailableRegistry("events.on", () => this.closed);
151
67
  this.model = options.model;
152
68
  this.thinkingLevel = options.thinkingLevel ?? "off";
153
- this.activeToolNames = options.activeToolNames
154
- ? [...options.activeToolNames]
155
- : (options.tools ?? []).map((tool) => tool.name);
156
- this.validateUniqueNames(this.activeToolNames, "Duplicate active tool name(s)");
157
- this.validateToolNames(this.activeToolNames);
158
- this.steeringQueueMode = options.steeringMode ?? "one-at-a-time";
159
- this.followUpQueueMode = options.followUpMode ?? "one-at-a-time";
160
- }
161
- assertNotShutDown() {
162
- if (this.isShutdown)
163
- throw new AgentHarnessError("invalid_state", "AgentHarness has been shut down");
164
- }
165
- getHandlers(type) {
166
- return this.handlers.get(type);
167
- }
168
- async emitOwn(event, signal) {
169
- for (const listener of this.getHandlers(SUBSCRIBER_EVENT_TYPE) ?? []) {
170
- try {
171
- await listener(event, signal);
172
- }
173
- catch (error) {
174
- throw normalizeHookError(error);
175
- }
176
- }
177
- }
178
- async emitAny(event, signal) {
179
- for (const listener of this.getHandlers(SUBSCRIBER_EVENT_TYPE) ?? []) {
180
- try {
181
- await listener(event, signal);
182
- }
183
- catch (error) {
184
- throw normalizeHookError(error);
185
- }
186
- }
187
- }
188
- async emitHook(event) {
189
- const handlers = this.getHandlers(event.type);
190
- if (!handlers || handlers.size === 0)
191
- return undefined;
192
- let lastResult;
193
- for (const handler of handlers) {
194
- try {
195
- const result = await handler(event);
196
- if (result !== undefined) {
197
- lastResult = result;
198
- }
199
- }
200
- catch (error) {
201
- throw normalizeHookError(error);
202
- }
203
- }
204
- return lastResult;
205
- }
206
- retryCallbacks(operation) {
207
- return {
208
- onRetryScheduled: (attempt, maxAttempts, delayMs, errorMessage) => this.emitOwn({ type: "retry_scheduled", operation, attempt, maxAttempts, delayMs, errorMessage }),
209
- onRetryAttemptStart: () => this.emitOwn({ type: "retry_attempt_start", operation }),
210
- onRetryFinished: () => this.emitOwn({ type: "retry_finished", operation }),
69
+ this.activeToolNames = [...(options.activeToolNames ?? options.tools?.map((tool) => tool.name) ?? [])];
70
+ this.tools = [...(options.tools ?? [])];
71
+ this.resources = {
72
+ skills: options.resources?.skills ? [...options.resources.skills] : undefined,
73
+ promptTemplates: options.resources?.promptTemplates ? [...options.resources.promptTemplates] : undefined,
211
74
  };
212
- }
213
- async emitBeforeProviderRequest(model, sessionId, streamOptions) {
214
- const handlers = this.getHandlers("before_provider_request");
215
- let current = cloneStreamOptions(streamOptions);
216
- if (!handlers || handlers.size === 0)
217
- return current;
218
- for (const handler of handlers) {
219
- try {
220
- const result = await handler({
221
- type: "before_provider_request",
222
- model,
223
- sessionId,
224
- streamOptions: cloneStreamOptions(current),
225
- });
226
- if (result?.streamOptions) {
227
- current = applyStreamOptionsPatch(current, result.streamOptions);
228
- }
229
- }
230
- catch (error) {
231
- throw normalizeHookError(error);
232
- }
233
- }
234
- return current;
235
- }
236
- async emitBeforeProviderPayload(model, payload) {
237
- const handlers = this.getHandlers("before_provider_payload");
238
- let current = payload;
239
- if (!handlers || handlers.size === 0)
240
- return current;
241
- for (const handler of handlers) {
242
- try {
243
- const result = await handler({ type: "before_provider_payload", model, payload: current });
244
- if (result !== undefined) {
245
- current = result.payload;
246
- }
247
- }
248
- catch (error) {
249
- throw normalizeHookError(error);
250
- }
251
- }
252
- return current;
253
- }
254
- async emitQueueUpdate() {
255
- await this.emitOwn({
256
- type: "queue_update",
257
- steer: [...this.steerQueue],
258
- followUp: [...this.followUpQueue],
259
- nextTurn: [...this.nextTurnQueue],
260
- });
261
- }
262
- startOperation() {
263
- const abortController = new AbortController();
264
- let finish = () => { };
265
- this.activeAbortController = abortController;
266
- void this.track("operation", () => new Promise((resolve) => {
267
- finish = resolve;
268
- }));
269
- return {
270
- signal: abortController.signal,
271
- finish: () => {
272
- this.activeAbortController = undefined;
273
- finish();
274
- },
75
+ this.streamOptions = { ...(options.streamOptions ?? {}) };
76
+ this.retryPolicy = options.retry ?? { enabled: false, maxRetries: 0, baseDelayMs: 1000 };
77
+ this.compactionSettings = options.compaction ?? {
78
+ enabled: true,
79
+ reserveTokens: 16384,
80
+ keepRecentTokens: 20000,
275
81
  };
82
+ this.steeringMode = options.steeringMode ?? "one-at-a-time";
83
+ this.followUpMode = options.followUpMode ?? "one-at-a-time";
276
84
  }
277
- async track(kind, operation) {
278
- let settle = () => { };
279
- const settled = new Promise((resolve) => {
280
- settle = resolve;
281
- });
282
- this.activeTasks.set(settled, kind);
283
- try {
284
- return await operation();
285
- }
286
- finally {
287
- this.activeTasks.delete(settled);
288
- settle();
289
- }
85
+ static async create(options) {
86
+ const [record] = await options.session.findRecords({ limit: 1 });
87
+ if (record !== undefined)
88
+ throw new HarnessNotImplemented("create.restore");
89
+ return { harness: new AgentHarness(options), suspended: [] };
290
90
  }
291
- async waitForTasks(kind) {
292
- while (true) {
293
- const tasks = [...this.activeTasks].flatMap(([task, taskKind]) => kind === undefined || kind === taskKind ? [task] : []);
294
- if (tasks.length === 0)
295
- return;
296
- await Promise.all(tasks);
297
- }
91
+ unavailable(operation) {
92
+ return Promise.reject(this.closed ? new HarnessClosed() : new HarnessNotImplemented(operation));
298
93
  }
299
- async resolveToolContext() {
300
- if (typeof this.toolContext === "function") {
301
- return await this.toolContext();
302
- }
303
- return this.toolContext;
94
+ async getLeafId() {
95
+ return this.durableSession.getLeafId();
304
96
  }
305
- bindToolContext(tool, context) {
306
- return {
307
- ...tool,
308
- execute: (toolCallId, params, signal, onUpdate) => tool.execute(toolCallId, params, signal, onUpdate, context),
309
- };
310
- }
311
- async createTurnState() {
312
- this.assertNotShutDown();
313
- const context = await this.session.buildContext();
314
- const resources = this.getResources();
315
- const sessionMetadata = await this.session.getMetadata();
316
- const toolContext = await this.resolveToolContext();
317
- const tools = [...this.tools.values()];
318
- const activeTools = this.activeToolNames
319
- .map((name) => this.tools.get(name))
320
- .filter((tool) => tool !== undefined);
321
- let systemPrompt = "You are a helpful assistant.";
322
- if (typeof this.systemPrompt === "string") {
323
- systemPrompt = this.systemPrompt;
324
- }
325
- else if (this.systemPrompt) {
326
- systemPrompt = await this.systemPrompt({
327
- session: this.session,
328
- model: this.model,
329
- thinkingLevel: this.thinkingLevel,
330
- activeTools,
331
- resources,
332
- });
333
- }
334
- return {
335
- messages: context.messages,
336
- resources,
337
- toolContext,
338
- streamOptions: cloneStreamOptions(this.streamOptions),
339
- sessionId: sessionMetadata.id,
340
- systemPrompt,
341
- model: this.model,
342
- thinkingLevel: this.thinkingLevel,
343
- tools,
344
- activeTools,
345
- };
346
- }
347
- createContext(turnState, systemPrompt) {
348
- return {
349
- systemPrompt: systemPrompt ?? turnState.systemPrompt,
350
- messages: turnState.messages.slice(),
351
- tools: turnState.activeTools.map((tool) => this.bindToolContext(tool, turnState.toolContext)),
352
- };
97
+ async prompt(_input, _images) {
98
+ return this.unavailable("prompt");
353
99
  }
354
- createStreamFn(getTurnState) {
355
- return async (model, context, streamOptions) => {
356
- const turnState = getTurnState();
357
- const snapshotOptions = { ...turnState.streamOptions };
358
- const requestOptions = await this.emitBeforeProviderRequest(model, turnState.sessionId, snapshotOptions);
359
- return this.models.streamSimple(model, context, {
360
- cacheRetention: requestOptions.cacheRetention,
361
- headers: requestOptions.headers,
362
- maxRetries: requestOptions.maxRetries,
363
- maxRetryDelayMs: requestOptions.maxRetryDelayMs,
364
- metadata: requestOptions.metadata,
365
- onPayload: async (payload) => await this.emitBeforeProviderPayload(model, payload),
366
- onResponse: async (response) => {
367
- const headers = { ...response.headers };
368
- await this.emitOwn({ type: "after_provider_response", status: response.status, headers }, streamOptions?.signal);
369
- },
370
- reasoning: streamOptions?.reasoning,
371
- signal: streamOptions?.signal,
372
- sessionId: turnState.sessionId,
373
- timeoutMs: requestOptions.timeoutMs,
374
- transport: requestOptions.transport,
375
- });
376
- };
377
- }
378
- async drainQueuedMessages(queue, mode) {
379
- const messages = mode === "all" ? queue.splice(0) : queue.splice(0, 1);
380
- if (messages.length === 0)
381
- return messages;
382
- try {
383
- await this.emitQueueUpdate();
384
- return messages;
385
- }
386
- catch (error) {
387
- queue.unshift(...messages);
388
- throw normalizeHookError(error);
389
- }
100
+ async skill(_name, _additionalInstructions) {
101
+ return this.unavailable("skill");
390
102
  }
391
- createLoopConfig(getTurnState, setTurnState) {
392
- const turnState = getTurnState();
393
- let steeringQueueAtDrain = this.steerQueue;
394
- let followUpQueueAtDrain = this.followUpQueue;
395
- return {
396
- model: turnState.model,
397
- reasoning: turnState.thinkingLevel === "off" ? undefined : turnState.thinkingLevel,
398
- convertToLlm,
399
- transformContext: async (messages) => {
400
- const result = await this.emitHook({ type: "context", messages: [...messages] });
401
- return result?.messages ?? messages;
402
- },
403
- beforeToolCall: async ({ toolCall, args }) => {
404
- const result = await this.emitHook({
405
- type: "tool_call",
406
- toolCallId: toolCall.id,
407
- toolName: toolCall.name,
408
- input: args,
409
- });
410
- return result ? { block: result.block, reason: result.reason } : undefined;
411
- },
412
- afterToolCall: async ({ toolCall, args, result, isError }) => {
413
- const patch = await this.emitHook({
414
- type: "tool_result",
415
- toolCallId: toolCall.id,
416
- toolName: toolCall.name,
417
- input: args,
418
- content: result.content,
419
- details: result.details,
420
- isError,
421
- usage: result.usage,
422
- });
423
- return patch
424
- ? {
425
- content: patch.content,
426
- details: patch.details,
427
- isError: patch.isError,
428
- usage: patch.usage,
429
- terminate: patch.terminate,
430
- }
431
- : undefined;
432
- },
433
- prepareNextTurn: async () => {
434
- await this.flushPendingSessionWrites();
435
- const nextTurnState = await this.createTurnState();
436
- setTurnState(nextTurnState);
437
- return {
438
- context: this.createContext(nextTurnState),
439
- model: nextTurnState.model,
440
- thinkingLevel: nextTurnState.thinkingLevel,
441
- };
442
- },
443
- getSteeringMessages: async () => {
444
- steeringQueueAtDrain = this.steerQueue;
445
- return this.drainQueuedMessages(steeringQueueAtDrain, this.steeringQueueMode);
446
- },
447
- getFollowUpMessages: async () => {
448
- followUpQueueAtDrain = this.followUpQueue;
449
- return this.drainQueuedMessages(followUpQueueAtDrain, this.followUpQueueMode);
450
- },
451
- restorePendingMessages: async (queue, messages) => {
452
- const target = queue === "steering" ? this.steerQueue : this.followUpQueue;
453
- const drainedQueue = queue === "steering" ? steeringQueueAtDrain : followUpQueueAtDrain;
454
- if (target !== drainedQueue)
455
- return;
456
- for (let index = messages.length - 1; index >= 0; index--) {
457
- const message = messages[index];
458
- if (message?.role !== "user") {
459
- throw new AgentHarnessError("invalid_state", "Only user messages can be restored to input queues");
460
- }
461
- target.unshift(message);
462
- }
463
- await this.emitQueueUpdate();
464
- },
465
- };
103
+ async promptFromTemplate(_name, _args) {
104
+ return this.unavailable("promptFromTemplate");
466
105
  }
467
- validateUniqueNames(names, message) {
468
- const duplicates = findDuplicateNames(names);
469
- if (duplicates.length > 0)
470
- throw new AgentHarnessError("invalid_argument", `${message}: ${duplicates.join(", ")}`);
106
+ async compact(_options) {
107
+ return this.unavailable("compact");
471
108
  }
472
- validateToolNames(toolNames, tools = this.tools) {
473
- this.validateUniqueNames(toolNames, "Duplicate active tool name(s)");
474
- const missing = toolNames.filter((name) => !tools.has(name));
475
- if (missing.length > 0)
476
- throw new AgentHarnessError("invalid_argument", `Unknown tool(s): ${missing.join(", ")}`);
109
+ async navigateTree(_targetId, _options) {
110
+ return this.unavailable("navigateTree");
477
111
  }
478
- async flushPendingSessionWrites() {
479
- while (this.pendingSessionWrites.length > 0) {
480
- const write = this.pendingSessionWrites[0];
481
- if (write.type === "message") {
482
- await this.session.appendMessage(write.message);
483
- }
484
- else if (write.type === "model_change") {
485
- await this.session.appendModelChange(write.provider, write.modelId);
486
- }
487
- else if (write.type === "thinking_level_change") {
488
- await this.session.appendThinkingLevelChange(write.thinkingLevel);
489
- }
490
- else if (write.type === "active_tools_change") {
491
- await this.session.appendActiveToolsChange(write.activeToolNames);
492
- }
493
- else if (write.type === "custom") {
494
- await this.session.appendCustomEntry(write.customType, write.data);
495
- }
496
- else if (write.type === "custom_message") {
497
- await this.session.appendCustomMessageEntry(write.customType, write.content, write.display, write.details);
498
- }
499
- else if (write.type === "label") {
500
- await this.session.appendLabel(write.targetId, write.label);
501
- }
502
- else if (write.type === "session_info") {
503
- await this.session.appendSessionName(write.name ?? "");
504
- }
505
- else if (write.type === "leaf") {
506
- await this.session.moveTo(write.targetId);
507
- }
508
- this.pendingSessionWrites.shift();
509
- }
112
+ async resume() {
113
+ return this.unavailable("resume");
510
114
  }
511
- async handleAgentEvent(event, signal) {
512
- if (event.type === "message_end") {
513
- await this.session.appendMessage(event.message);
514
- await this.emitAny(event, signal);
515
- return;
516
- }
517
- if (event.type === "turn_end") {
518
- let eventError;
519
- try {
520
- await this.emitAny(event, signal);
521
- }
522
- catch (error) {
523
- eventError = error;
524
- }
525
- const hadPendingMutations = this.pendingSessionWrites.length > 0;
526
- await this.flushPendingSessionWrites();
527
- if (eventError)
528
- throw eventError;
529
- await this.emitOwn({ type: "save_point", hadPendingMutations });
530
- return;
531
- }
532
- if (event.type === "agent_end") {
533
- await this.flushPendingSessionWrites();
534
- this.phase = "idle";
535
- await this.emitAny(event, signal);
536
- await this.emitOwn({ type: "settled", nextTurnCount: this.nextTurnQueue.length }, signal);
537
- return;
538
- }
539
- await this.emitAny(event, signal);
540
- }
541
- async emitRunFailure(model, error, aborted, signal) {
542
- const failureMessage = createFailureMessage(model, error, aborted);
543
- await this.handleAgentEvent({ type: "message_start", message: failureMessage }, signal);
544
- await this.handleAgentEvent({ type: "message_end", message: failureMessage }, signal);
545
- await this.handleAgentEvent({ type: "turn_end", message: failureMessage, toolResults: [] }, signal);
546
- await this.handleAgentEvent({ type: "agent_end", messages: [failureMessage] }, signal);
547
- return [failureMessage];
115
+ async abort() {
116
+ return this.unavailable("abort");
548
117
  }
549
- async executeTurn(turnState, text, signal, options) {
550
- this.assertNotShutDown();
551
- let activeTurnState = turnState;
552
- let messages = [createUserMessage(text, options?.images)];
553
- if (this.nextTurnQueue.length > 0) {
554
- const queuedMessages = this.nextTurnQueue.splice(0);
555
- try {
556
- await this.emitQueueUpdate();
557
- }
558
- catch (error) {
559
- this.nextTurnQueue.unshift(...queuedMessages);
560
- throw normalizeHookError(error);
561
- }
562
- messages = [...queuedMessages, messages[0]];
563
- }
564
- const beforeResult = await this.emitHook({
565
- type: "before_agent_start",
566
- prompt: text,
567
- images: options?.images,
568
- systemPrompt: turnState.systemPrompt,
569
- resources: turnState.resources,
570
- });
571
- this.assertNotShutDown();
572
- if (beforeResult?.messages)
573
- messages = [...messages, ...beforeResult.messages];
574
- const getTurnState = () => activeTurnState;
575
- const setTurnState = (nextTurnState) => {
576
- activeTurnState = nextTurnState;
577
- };
578
- const runResultPromise = (async () => {
579
- try {
580
- return await runAgentLoop(messages, this.createContext(turnState, beforeResult?.systemPrompt), this.createLoopConfig(getTurnState, setTurnState), (event) => this.handleAgentEvent(event, signal), signal, this.createStreamFn(getTurnState));
581
- }
582
- catch (error) {
583
- try {
584
- return await this.emitRunFailure(activeTurnState.model, error, signal.aborted, signal);
585
- }
586
- catch (failureError) {
587
- const cause = new AggregateError([toError(error), toError(failureError)], "Agent run failed and failure reporting failed");
588
- throw new AgentHarnessError("unknown", cause.message, cause);
589
- }
590
- }
591
- })();
592
- try {
593
- const newMessages = await runResultPromise;
594
- for (let i = newMessages.length - 1; i >= 0; i--) {
595
- const message = newMessages[i];
596
- if (message.role === "assistant") {
597
- return message;
598
- }
599
- }
600
- throw new AgentHarnessError("invalid_state", "AgentHarness prompt completed without an assistant message");
601
- }
602
- finally {
603
- await this.flushPendingSessionWrites();
604
- }
118
+ async steer(_input, _images) {
119
+ return this.unavailable("steer");
605
120
  }
606
- async prompt(text, options) {
607
- this.assertNotShutDown();
608
- if (this.phase !== "idle")
609
- throw new AgentHarnessError("busy", "AgentHarness is busy");
610
- this.phase = "turn";
611
- const operation = this.startOperation();
612
- try {
613
- const turnState = await this.createTurnState();
614
- return await this.executeTurn(turnState, text, operation.signal, options);
615
- }
616
- catch (error) {
617
- this.phase = "idle";
618
- throw normalizeHarnessError(error, "unknown");
619
- }
620
- finally {
621
- operation.finish();
622
- }
121
+ async followUp(_input, _images) {
122
+ return this.unavailable("followUp");
623
123
  }
624
- async skill(name, additionalInstructions) {
625
- this.assertNotShutDown();
626
- if (this.phase !== "idle")
627
- throw new AgentHarnessError("busy", "AgentHarness is busy");
628
- this.phase = "turn";
629
- const operation = this.startOperation();
630
- try {
631
- const turnState = await this.createTurnState();
632
- const skill = (turnState.resources.skills ?? []).find((candidate) => candidate.name === name);
633
- if (!skill)
634
- throw new AgentHarnessError("invalid_argument", `Unknown skill: ${name}`);
635
- return await this.executeTurn(turnState, formatSkillInvocation(skill, additionalInstructions), operation.signal);
636
- }
637
- catch (error) {
638
- this.phase = "idle";
639
- throw normalizeHarnessError(error, "unknown");
640
- }
641
- finally {
642
- operation.finish();
643
- }
124
+ async nextRun(_input, _images) {
125
+ return this.unavailable("nextRun");
644
126
  }
645
- async promptFromTemplate(name, args = []) {
646
- this.assertNotShutDown();
647
- if (this.phase !== "idle")
648
- throw new AgentHarnessError("busy", "AgentHarness is busy");
649
- this.phase = "turn";
650
- const operation = this.startOperation();
651
- try {
652
- const turnState = await this.createTurnState();
653
- const template = (turnState.resources.promptTemplates ?? []).find((candidate) => candidate.name === name);
654
- if (!template)
655
- throw new AgentHarnessError("invalid_argument", `Unknown prompt template: ${name}`);
656
- return await this.executeTurn(turnState, formatPromptTemplateInvocation(template, args), operation.signal);
657
- }
658
- catch (error) {
659
- this.phase = "idle";
660
- throw normalizeHarnessError(error, "unknown");
661
- }
662
- finally {
663
- operation.finish();
664
- }
127
+ async cancelQueued(_entryId) {
128
+ return this.unavailable("cancelQueued");
665
129
  }
666
- async steer(text, options) {
667
- this.assertNotShutDown();
668
- if (this.phase === "idle")
669
- throw new AgentHarnessError("invalid_state", "Cannot steer while idle");
670
- this.steerQueue.push(createUserMessage(text, options?.images));
671
- await this.emitQueueUpdate();
130
+ async recordUsage(_usage, _options) {
131
+ return this.unavailable("recordUsage");
672
132
  }
673
- async followUp(text, options) {
674
- this.assertNotShutDown();
675
- if (this.phase === "idle")
676
- throw new AgentHarnessError("invalid_state", "Cannot follow up while idle");
677
- this.followUpQueue.push(createUserMessage(text, options?.images));
678
- await this.emitQueueUpdate();
133
+ async waitForIdle() {
134
+ return this.unavailable("waitForIdle");
679
135
  }
680
- async nextTurn(text, options) {
681
- this.assertNotShutDown();
682
- this.nextTurnQueue.push(createUserMessage(text, options?.images));
683
- await this.emitQueueUpdate();
136
+ async runWhenIdle(_callback) {
137
+ return this.unavailable("runWhenIdle");
684
138
  }
685
- async appendMessage(message) {
686
- this.assertNotShutDown();
687
- return this.track("mutation", async () => {
688
- try {
689
- if (this.phase === "idle") {
690
- await this.session.appendMessage(message);
691
- }
692
- else {
693
- this.pendingSessionWrites.push({ type: "message", message });
694
- }
695
- }
696
- catch (error) {
697
- throw normalizeHarnessError(error, "session");
698
- }
699
- });
139
+ async peekAction() {
140
+ return this.unavailable("peekAction");
700
141
  }
701
- async compact(customInstructions) {
702
- this.assertNotShutDown();
703
- if (this.phase !== "idle")
704
- throw new AgentHarnessError("busy", "compact() requires idle harness");
705
- this.phase = "compaction";
706
- const operation = this.startOperation();
707
- try {
708
- const model = this.model;
709
- if (!model)
710
- throw new AgentHarnessError("invalid_state", "No model set for compaction");
711
- const branchEntries = await this.session.getBranch();
712
- const preparationResult = prepareCompaction(branchEntries, DEFAULT_COMPACTION_SETTINGS);
713
- if (!preparationResult.ok)
714
- throw preparationResult.error;
715
- const preparation = preparationResult.value;
716
- if (!preparation)
717
- throw new AgentHarnessError("compaction", "Nothing to compact");
718
- const hookResult = await this.emitHook({
719
- type: "session_before_compact",
720
- preparation,
721
- branchEntries,
722
- customInstructions,
723
- signal: operation.signal,
724
- });
725
- if (hookResult?.cancel)
726
- throw new AgentHarnessError("compaction", "Compaction cancelled");
727
- const provided = hookResult?.compaction;
728
- const compactResult = provided
729
- ? { ok: true, value: provided }
730
- : await compact(preparation, this.models, model, customInstructions, operation.signal, this.thinkingLevel, this.retry, this.retryCallbacks("compaction"));
731
- if (!compactResult.ok)
732
- throw compactResult.error;
733
- const result = compactResult.value;
734
- this.assertNotShutDown();
735
- const entryId = await this.session.appendCompaction(result.summary, result.firstKeptEntryId, result.tokensBefore, result.details, provided !== undefined, result.usage, result.retainedTail);
736
- const entry = await this.session.getEntry(entryId);
737
- if (entry?.type === "compaction") {
738
- await this.emitOwn({ type: "session_compact", compactionEntry: entry, fromHook: provided !== undefined });
739
- }
740
- return result;
741
- }
742
- catch (error) {
743
- throw normalizeHarnessError(error, "compaction");
744
- }
745
- finally {
746
- this.phase = "idle";
747
- operation.finish();
748
- }
142
+ async executeAction() {
143
+ return this.unavailable("executeAction");
749
144
  }
750
- async navigateTree(targetId, options) {
751
- this.assertNotShutDown();
752
- if (this.phase !== "idle")
753
- throw new AgentHarnessError("busy", "navigateTree() requires idle harness");
754
- this.phase = "branch_summary";
755
- const operation = this.startOperation();
756
- try {
757
- const oldLeafId = await this.session.getLeafId();
758
- if (oldLeafId === targetId)
759
- return { cancelled: false };
760
- const targetEntry = await this.session.getEntry(targetId);
761
- if (!targetEntry)
762
- throw new AgentHarnessError("invalid_argument", `Entry ${targetId} not found`);
763
- const { entries, commonAncestorId } = await collectEntriesForBranchSummary(this.session, oldLeafId, targetId);
764
- const preparation = {
765
- targetId,
766
- oldLeafId,
767
- commonAncestorId,
768
- entriesToSummarize: entries,
769
- userWantsSummary: options?.summarize ?? false,
770
- customInstructions: options?.customInstructions,
771
- replaceInstructions: options?.replaceInstructions,
772
- label: options?.label,
773
- };
774
- const hookResult = await this.emitHook({
775
- type: "session_before_tree",
776
- preparation,
777
- signal: operation.signal,
778
- });
779
- if (hookResult?.cancel)
780
- return { cancelled: true };
781
- let summaryEntry;
782
- let summaryText = hookResult?.summary?.summary;
783
- let summaryDetails = hookResult?.summary?.details;
784
- let summaryUsage = hookResult?.summary?.usage;
785
- if (!summaryText && options?.summarize && entries.length > 0) {
786
- const model = this.model;
787
- if (!model)
788
- throw new AgentHarnessError("invalid_state", "No model set for branch summary");
789
- const branchSummary = await generateBranchSummary(entries, {
790
- models: this.models,
791
- model,
792
- signal: operation.signal,
793
- customInstructions: hookResult?.customInstructions ?? options?.customInstructions,
794
- replaceInstructions: hookResult?.replaceInstructions ?? options?.replaceInstructions,
795
- retry: this.retry,
796
- callbacks: this.retryCallbacks("branch_summary"),
797
- });
798
- if (!branchSummary.ok) {
799
- if (branchSummary.error.code === "aborted")
800
- return { cancelled: true };
801
- throw new AgentHarnessError("branch_summary", branchSummary.error.message, branchSummary.error);
802
- }
803
- summaryText = branchSummary.value.summary;
804
- summaryUsage = branchSummary.value.usage;
805
- summaryDetails = {
806
- readFiles: branchSummary.value.readFiles,
807
- modifiedFiles: branchSummary.value.modifiedFiles,
808
- };
809
- }
810
- let editorText;
811
- let newLeafId;
812
- if (targetEntry.type === "message" && targetEntry.message.role === "user") {
813
- newLeafId = targetEntry.parentId;
814
- editorText = contentText(targetEntry.message.content, "");
815
- }
816
- else if (targetEntry.type === "custom_message") {
817
- newLeafId = targetEntry.parentId;
818
- editorText = contentText(targetEntry.content, "");
819
- }
820
- else {
821
- newLeafId = targetId;
822
- }
823
- this.assertNotShutDown();
824
- const summaryId = await this.session.moveTo(newLeafId, summaryText
825
- ? {
826
- summary: summaryText,
827
- details: summaryDetails,
828
- usage: summaryUsage,
829
- fromHook: hookResult?.summary !== undefined,
830
- }
831
- : undefined);
832
- if (summaryId) {
833
- const entry = await this.session.getEntry(summaryId);
834
- if (entry?.type === "branch_summary")
835
- summaryEntry = entry;
836
- }
837
- await this.emitOwn({
838
- type: "session_tree",
839
- newLeafId: await this.session.getLeafId(),
840
- oldLeafId,
841
- summaryEntry,
842
- fromHook: hookResult?.summary !== undefined,
843
- });
844
- return { cancelled: false, editorText, summaryEntry };
845
- }
846
- catch (error) {
847
- throw normalizeHarnessError(error, "branch_summary");
848
- }
849
- finally {
850
- this.phase = "idle";
851
- operation.finish();
852
- }
145
+ async runToCompletion() {
146
+ return this.unavailable("runToCompletion");
853
147
  }
854
- getModel() {
148
+ async getModel() {
855
149
  return this.model;
856
150
  }
857
151
  async setModel(model) {
858
- this.assertNotShutDown();
859
- return this.track("mutation", async () => {
860
- try {
861
- const previousModel = this.model;
862
- if (this.phase === "idle") {
863
- await this.session.appendModelChange(model.provider, model.id);
864
- }
865
- else {
866
- this.pendingSessionWrites.push({ type: "model_change", provider: model.provider, modelId: model.id });
867
- }
868
- this.model = model;
869
- await this.emitOwn({ type: "model_update", model, previousModel, source: "set" });
870
- }
871
- catch (error) {
872
- throw normalizeHarnessError(error, "session");
873
- }
874
- });
152
+ this.model = model;
875
153
  }
876
- getThinkingLevel() {
154
+ async getThinkingLevel() {
877
155
  return this.thinkingLevel;
878
156
  }
879
157
  async setThinkingLevel(level) {
880
- this.assertNotShutDown();
881
- return this.track("mutation", async () => {
882
- try {
883
- const previousLevel = this.thinkingLevel;
884
- if (this.phase === "idle") {
885
- await this.session.appendThinkingLevelChange(level);
886
- }
887
- else {
888
- this.pendingSessionWrites.push({ type: "thinking_level_change", thinkingLevel: level });
889
- }
890
- this.thinkingLevel = level;
891
- await this.emitOwn({ type: "thinking_level_update", level, previousLevel });
892
- }
893
- catch (error) {
894
- throw normalizeHarnessError(error, "session");
895
- }
896
- });
897
- }
898
- getTools() {
899
- return [...this.tools.values()];
158
+ this.thinkingLevel = level;
900
159
  }
901
- async setTools(tools, activeToolNames) {
902
- this.assertNotShutDown();
903
- return this.track("mutation", () => this.applyTools(tools, activeToolNames));
160
+ async getActiveTools() {
161
+ return [...this.activeToolNames];
904
162
  }
905
- async applyTools(tools, activeToolNames) {
906
- try {
907
- this.validateUniqueNames(tools.map((tool) => tool.name), "Duplicate tool name(s)");
908
- const nextTools = new Map(tools.map((tool) => [tool.name, tool]));
909
- const nextActiveToolNames = activeToolNames ? [...activeToolNames] : this.activeToolNames;
910
- this.validateToolNames(nextActiveToolNames, nextTools);
911
- const previousToolNames = [...this.tools.keys()];
912
- const previousActiveToolNames = [...this.activeToolNames];
913
- if (this.phase === "idle") {
914
- await this.session.appendActiveToolsChange(nextActiveToolNames);
915
- }
916
- else {
917
- this.pendingSessionWrites.push({ type: "active_tools_change", activeToolNames: [...nextActiveToolNames] });
918
- }
919
- this.tools = nextTools;
920
- this.activeToolNames = [...nextActiveToolNames];
921
- await this.emitOwn({
922
- type: "tools_update",
923
- toolNames: [...this.tools.keys()],
924
- previousToolNames,
925
- activeToolNames: [...this.activeToolNames],
926
- previousActiveToolNames,
927
- source: "set",
928
- });
929
- }
930
- catch (error) {
931
- throw normalizeHarnessError(error, "invalid_argument");
932
- }
163
+ async setActiveTools(names) {
164
+ this.activeToolNames = [...names];
933
165
  }
934
- getActiveTools() {
935
- return this.activeToolNames.map((name) => this.tools.get(name));
166
+ async watch() {
167
+ return this.unavailable("watch");
936
168
  }
937
- async setActiveTools(toolNames) {
938
- this.assertNotShutDown();
939
- return this.track("mutation", () => this.applyActiveTools(toolNames));
169
+ async lane(_name) {
170
+ return this.unavailable("lane");
940
171
  }
941
- async applyActiveTools(toolNames) {
942
- try {
943
- this.validateToolNames(toolNames);
944
- const previousToolNames = [...this.tools.keys()];
945
- const previousActiveToolNames = [...this.activeToolNames];
946
- if (this.phase === "idle") {
947
- await this.session.appendActiveToolsChange(toolNames);
948
- }
949
- else {
950
- this.pendingSessionWrites.push({ type: "active_tools_change", activeToolNames: [...toolNames] });
951
- }
952
- this.activeToolNames = [...toolNames];
953
- await this.emitOwn({
954
- type: "tools_update",
955
- toolNames: [...this.tools.keys()],
956
- previousToolNames,
957
- activeToolNames: [...this.activeToolNames],
958
- previousActiveToolNames,
959
- source: "set",
960
- });
961
- }
962
- catch (error) {
963
- throw normalizeHarnessError(error, "invalid_argument");
964
- }
172
+ async createLane(_name, _at) {
173
+ return this.unavailable("createLane");
965
174
  }
966
- getSteeringMode() {
967
- return this.steeringQueueMode;
175
+ async lanes() {
176
+ return this.unavailable("lanes");
968
177
  }
969
- async setSteeringMode(mode) {
970
- this.assertNotShutDown();
971
- this.steeringQueueMode = mode;
178
+ async getTools() {
179
+ return [...this.tools];
972
180
  }
973
- getFollowUpMode() {
974
- return this.followUpQueueMode;
181
+ async setTools(tools, activeNames) {
182
+ this.tools = [...tools];
183
+ this.activeToolNames = [...(activeNames ?? tools.map((tool) => tool.name))];
975
184
  }
976
- async setFollowUpMode(mode) {
977
- this.assertNotShutDown();
978
- this.followUpQueueMode = mode;
979
- }
980
- getResources() {
185
+ async getResources() {
981
186
  return {
982
- skills: this.resources.skills?.slice(),
983
- promptTemplates: this.resources.promptTemplates?.slice(),
187
+ skills: this.resources.skills ? [...this.resources.skills] : undefined,
188
+ promptTemplates: this.resources.promptTemplates ? [...this.resources.promptTemplates] : undefined,
984
189
  };
985
190
  }
986
191
  async setResources(resources) {
987
- this.assertNotShutDown();
988
- const previousResources = this.getResources();
989
192
  this.resources = {
990
- skills: resources.skills?.slice(),
991
- promptTemplates: resources.promptTemplates?.slice(),
193
+ skills: resources.skills ? [...resources.skills] : undefined,
194
+ promptTemplates: resources.promptTemplates ? [...resources.promptTemplates] : undefined,
992
195
  };
993
- await this.emitOwn({ type: "resources_update", resources: this.getResources(), previousResources });
994
196
  }
995
- getStreamOptions() {
996
- return cloneStreamOptions(this.streamOptions);
197
+ async getStreamOptions() {
198
+ return { ...this.streamOptions };
997
199
  }
998
- async setStreamOptions(streamOptions) {
999
- this.assertNotShutDown();
1000
- this.streamOptions = cloneStreamOptions(streamOptions);
200
+ async setStreamOptions(options) {
201
+ this.streamOptions = { ...options };
1001
202
  }
1002
- /** Permanently stop this harness instance without deleting its durable session. */
1003
- requestShutdown() {
1004
- if (this.isShutdown)
1005
- return;
1006
- this.isShutdown = true;
1007
- this.pendingSessionWrites = [];
1008
- this.steerQueue = [];
1009
- this.followUpQueue = [];
1010
- this.nextTurnQueue = [];
1011
- this.activeAbortController?.abort();
1012
- this.shutdownPromise = this.waitForTasks();
203
+ async getRetryPolicy() {
204
+ return { ...this.retryPolicy };
1013
205
  }
1014
- /** Waits for work active when shutdown was requested to settle. */
1015
- waitForShutdown() {
1016
- if (!this.shutdownPromise) {
1017
- return Promise.reject(new AgentHarnessError("invalid_state", "Shutdown has not been requested"));
1018
- }
1019
- return this.shutdownPromise;
206
+ async setRetryPolicy(policy) {
207
+ this.retryPolicy = { ...policy };
1020
208
  }
1021
- async abort() {
1022
- this.assertNotShutDown();
1023
- const clearedSteer = [...this.steerQueue];
1024
- const clearedFollowUp = [...this.followUpQueue];
1025
- this.steerQueue = [];
1026
- this.followUpQueue = [];
1027
- this.activeAbortController?.abort();
1028
- const errors = [];
1029
- try {
1030
- await this.emitQueueUpdate();
1031
- }
1032
- catch (error) {
1033
- errors.push(toError(error));
1034
- }
1035
- try {
1036
- await this.waitForIdle();
1037
- }
1038
- catch (error) {
1039
- errors.push(toError(error));
1040
- }
1041
- try {
1042
- await this.emitOwn({ type: "abort", clearedSteer, clearedFollowUp });
1043
- }
1044
- catch (error) {
1045
- errors.push(toError(error));
1046
- }
1047
- if (errors.length > 0) {
1048
- const cause = errors.length === 1 ? errors[0] : new AggregateError(errors, "Abort completed with errors");
1049
- throw normalizeHarnessError(cause, "hook");
1050
- }
1051
- return { clearedSteer, clearedFollowUp };
209
+ async getCompactionSettings() {
210
+ return { ...this.compactionSettings };
1052
211
  }
1053
- async waitForIdle() {
1054
- await this.waitForTasks("operation");
212
+ async setCompactionSettings(settings) {
213
+ this.compactionSettings = { ...settings };
214
+ }
215
+ async getSteeringMode() {
216
+ return this.steeringMode;
217
+ }
218
+ async setSteeringMode(mode) {
219
+ this.steeringMode = mode;
220
+ }
221
+ async getFollowUpMode() {
222
+ return this.followUpMode;
223
+ }
224
+ async setFollowUpMode(mode) {
225
+ this.followUpMode = mode;
1055
226
  }
1056
- subscribe(listener) {
1057
- this.assertNotShutDown();
1058
- let handlers = this.handlers.get(SUBSCRIBER_EVENT_TYPE);
1059
- if (!handlers) {
1060
- handlers = new Set();
1061
- this.handlers.set(SUBSCRIBER_EVENT_TYPE, handlers);
1062
- }
1063
- handlers.add(listener);
1064
- return () => handlers.delete(listener);
227
+ async watchSession() {
228
+ return this.unavailable("watchSession");
1065
229
  }
1066
- on(type, handler) {
1067
- this.assertNotShutDown();
1068
- let handlers = this.handlers.get(type);
1069
- if (!handlers) {
1070
- handlers = new Set();
1071
- this.handlers.set(type, handlers);
1072
- }
1073
- handlers.add(handler);
1074
- return () => handlers.delete(handler);
230
+ async close() {
231
+ this.closed = true;
1075
232
  }
1076
233
  }
1077
234
  //# sourceMappingURL=agent-harness.js.map