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