@akagilnc/pi-workflow-roles 0.1.5204 → 0.1.5212
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 +1 -1
- package/dist/acp-host/production-host.js +133 -289
- package/dist/headless-host/production-host.js +109 -265
- package/dist/public-cli/main.js +0 -1
- package/dist/sitian-appender.js +0 -1
- package/dist/submission-ledger.js +8 -29
- package/package.json +2 -3
- package/scripts/build-package.mjs +1 -3
- package/souls/audit-law.md +1 -1
- package/souls/judge-auditor.md +1 -1
- package/src/host-contracts.ts +0 -100
- package/src/role-runtime.ts +4 -57
- package/src/sitian-appender.ts +0 -1
- package/src/sitian-contracts.ts +0 -3
- package/src/submission-ledger.ts +10 -31
- package/dist/pi/in-process-session.js +0 -660
- package/dist/stream-idle-guard.js +0 -67
- package/schemas/tool-execution-observation.schema.json +0 -107
- package/scripts/generate-tool-execution-observation-schema.ts +0 -7
- package/src/in-process-session.ts +0 -1
- package/src/pi/in-process-session.ts +0 -861
- package/src/stream-idle-guard.ts +0 -98
- package/src/tool-execution-observation.ts +0 -168
|
@@ -1,660 +0,0 @@
|
|
|
1
|
-
import { mkdtemp, rm } from "node:fs/promises";
|
|
2
|
-
import { tmpdir } from "node:os";
|
|
3
|
-
import { join } from "node:path";
|
|
4
|
-
import {
|
|
5
|
-
createAgentSession,
|
|
6
|
-
DefaultResourceLoader,
|
|
7
|
-
ModelRegistry,
|
|
8
|
-
ModelRuntime,
|
|
9
|
-
SettingsManager
|
|
10
|
-
} from "@earendil-works/pi-coding-agent";
|
|
11
|
-
import {
|
|
12
|
-
createAssistantMessageEventStream,
|
|
13
|
-
InMemoryCredentialStore
|
|
14
|
-
} from "@earendil-works/pi-ai";
|
|
15
|
-
import { createRecordSession } from "../archivist-record-entry.js";
|
|
16
|
-
import {
|
|
17
|
-
createStreamIdleGuard,
|
|
18
|
-
isStreamIdleTimeoutError,
|
|
19
|
-
StreamIdleTimeoutError
|
|
20
|
-
} from "../stream-idle-guard.js";
|
|
21
|
-
import {
|
|
22
|
-
hasUpstreamErrorTestimony,
|
|
23
|
-
isNonSuccessHttpStatus,
|
|
24
|
-
projectConfirmedRemotePayload
|
|
25
|
-
} from "../upstream-error-testimony.js";
|
|
26
|
-
const DEFAULT_COMPLIANCE_IDLE_MAX_RETRIES = 2;
|
|
27
|
-
function streamIdleTimeoutFromUnknown(value) {
|
|
28
|
-
if (isStreamIdleTimeoutError(value)) return value;
|
|
29
|
-
const message = value instanceof Error ? value.message : typeof value === "string" ? value : void 0;
|
|
30
|
-
if (message === void 0) return void 0;
|
|
31
|
-
const match = /stream idle timeout after (\d+)ms/i.exec(message);
|
|
32
|
-
return match !== null && match[1] !== void 0 ? new StreamIdleTimeoutError(Number(match[1])) : void 0;
|
|
33
|
-
}
|
|
34
|
-
function emptyUsage() {
|
|
35
|
-
return {
|
|
36
|
-
input: 0,
|
|
37
|
-
output: 0,
|
|
38
|
-
cacheRead: 0,
|
|
39
|
-
cacheWrite: 0,
|
|
40
|
-
totalTokens: 0,
|
|
41
|
-
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 }
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
function addUsage(total, next) {
|
|
45
|
-
if (!next) return;
|
|
46
|
-
total.input += next.input;
|
|
47
|
-
total.output += next.output;
|
|
48
|
-
total.cacheRead += next.cacheRead;
|
|
49
|
-
total.cacheWrite += next.cacheWrite;
|
|
50
|
-
total.totalTokens += next.totalTokens;
|
|
51
|
-
total.cost.input += next.cost?.input ?? 0;
|
|
52
|
-
total.cost.output += next.cost?.output ?? 0;
|
|
53
|
-
total.cost.cacheRead += next.cost?.cacheRead ?? 0;
|
|
54
|
-
total.cost.cacheWrite += next.cost?.cacheWrite ?? 0;
|
|
55
|
-
total.cost.total += next.cost?.total ?? 0;
|
|
56
|
-
}
|
|
57
|
-
function numericHttpStatus(value) {
|
|
58
|
-
return isNonSuccessHttpStatus(value) ? value : void 0;
|
|
59
|
-
}
|
|
60
|
-
function projectStructuredRemote(error) {
|
|
61
|
-
let httpStatus;
|
|
62
|
-
let diagnostics;
|
|
63
|
-
let body;
|
|
64
|
-
let code;
|
|
65
|
-
let errno;
|
|
66
|
-
let cursor = error;
|
|
67
|
-
const seen = /* @__PURE__ */ new Set();
|
|
68
|
-
while (typeof cursor === "object" && cursor !== null && !seen.has(cursor)) {
|
|
69
|
-
seen.add(cursor);
|
|
70
|
-
const record = cursor;
|
|
71
|
-
const nodeStatus = numericHttpStatus(record.statusCode) ?? numericHttpStatus(record.status) ?? numericHttpStatus(record.httpStatus);
|
|
72
|
-
const nodeDiagnostics = Array.isArray(record.diagnostics) && record.diagnostics.length > 0 ? record.diagnostics : void 0;
|
|
73
|
-
const nodeHasTestimony = hasUpstreamErrorTestimony({
|
|
74
|
-
...nodeStatus === void 0 ? {} : { httpStatus: nodeStatus },
|
|
75
|
-
...nodeDiagnostics === void 0 ? {} : { diagnostics: nodeDiagnostics }
|
|
76
|
-
});
|
|
77
|
-
if (httpStatus === void 0 && nodeStatus !== void 0) httpStatus = nodeStatus;
|
|
78
|
-
if (diagnostics === void 0 && nodeDiagnostics !== void 0) diagnostics = nodeDiagnostics;
|
|
79
|
-
if (nodeHasTestimony) {
|
|
80
|
-
const payload = projectConfirmedRemotePayload(record);
|
|
81
|
-
if (body === void 0 && payload.body !== void 0) body = payload.body;
|
|
82
|
-
if (code === void 0 && payload.code !== void 0) code = payload.code;
|
|
83
|
-
if (errno === void 0 && payload.errno !== void 0) errno = payload.errno;
|
|
84
|
-
}
|
|
85
|
-
cursor = record.cause;
|
|
86
|
-
}
|
|
87
|
-
return {
|
|
88
|
-
hasTestimony: hasUpstreamErrorTestimony({
|
|
89
|
-
...httpStatus === void 0 ? {} : { httpStatus },
|
|
90
|
-
...diagnostics === void 0 ? {} : { diagnostics }
|
|
91
|
-
}),
|
|
92
|
-
...httpStatus === void 0 ? {} : { httpStatus },
|
|
93
|
-
...diagnostics === void 0 ? {} : { diagnostics },
|
|
94
|
-
...body === void 0 ? {} : { body },
|
|
95
|
-
...code === void 0 ? {} : { code },
|
|
96
|
-
...errno === void 0 ? {} : { errno }
|
|
97
|
-
};
|
|
98
|
-
}
|
|
99
|
-
function attachObservedHttpStatus(message, observedHttpStatus) {
|
|
100
|
-
if (observedHttpStatus === void 0) return message;
|
|
101
|
-
if (message.stopReason !== "error" && message.stopReason !== "aborted") return message;
|
|
102
|
-
if (numericHttpStatus(observedHttpStatus) === void 0) return message;
|
|
103
|
-
if (projectStructuredRemote(message).httpStatus !== void 0) return message;
|
|
104
|
-
return Object.assign(message, {
|
|
105
|
-
status: observedHttpStatus,
|
|
106
|
-
statusCode: observedHttpStatus
|
|
107
|
-
});
|
|
108
|
-
}
|
|
109
|
-
function enrichStreamEvent(event, observedHttpStatus) {
|
|
110
|
-
if (observedHttpStatus === void 0 || event === null || typeof event !== "object") return event;
|
|
111
|
-
const record = event;
|
|
112
|
-
if (record.type === "error" && record.error !== null && typeof record.error === "object") {
|
|
113
|
-
return {
|
|
114
|
-
...record,
|
|
115
|
-
error: attachObservedHttpStatus(record.error, observedHttpStatus)
|
|
116
|
-
};
|
|
117
|
-
}
|
|
118
|
-
if (record.type === "done" && record.message !== null && typeof record.message === "object") {
|
|
119
|
-
return {
|
|
120
|
-
...record,
|
|
121
|
-
message: attachObservedHttpStatus(record.message, observedHttpStatus)
|
|
122
|
-
};
|
|
123
|
-
}
|
|
124
|
-
if (record.partial !== null && typeof record.partial === "object") {
|
|
125
|
-
return {
|
|
126
|
-
...record,
|
|
127
|
-
partial: attachObservedHttpStatus(record.partial, observedHttpStatus)
|
|
128
|
-
};
|
|
129
|
-
}
|
|
130
|
-
return event;
|
|
131
|
-
}
|
|
132
|
-
async function openPiInProcessSession(options) {
|
|
133
|
-
const label = options.label ?? "Institutional sub-session";
|
|
134
|
-
const selection = options.selection;
|
|
135
|
-
let scratchDir;
|
|
136
|
-
let resolvedAgentDir = options.agentDir;
|
|
137
|
-
if (resolvedAgentDir === void 0) {
|
|
138
|
-
scratchDir = await mkdtemp(join(options.credentialScratchParent ?? tmpdir(), "ak-institutional-"));
|
|
139
|
-
resolvedAgentDir = scratchDir;
|
|
140
|
-
}
|
|
141
|
-
try {
|
|
142
|
-
const childRuntime = await ModelRuntime.create();
|
|
143
|
-
const childRegistry = new ModelRegistry(childRuntime);
|
|
144
|
-
const childProvider = typeof childRegistry.getProvider === "function" ? childRegistry.getProvider(selection.provider) : void 0;
|
|
145
|
-
const foundModel = typeof childRegistry.find === "function" ? childRegistry.find(selection.provider, selection.model) : void 0;
|
|
146
|
-
const withTypedReason = (error, reason) => Object.assign(error, { reason });
|
|
147
|
-
if (childProvider === void 0) {
|
|
148
|
-
throw withTypedReason(
|
|
149
|
-
new Error(`${label} model is unavailable: ${selection.provider}/${selection.model}`),
|
|
150
|
-
"model"
|
|
151
|
-
);
|
|
152
|
-
}
|
|
153
|
-
const providerDefaultModel = childProvider.getModels?.()[0];
|
|
154
|
-
const fallbackApi = providerDefaultModel?.api ?? childProvider?.api ?? (selection.provider === "openai-codex" ? "openai-codex-responses" : "openai-completions");
|
|
155
|
-
const modelToUse = foundModel ?? {
|
|
156
|
-
id: selection.model,
|
|
157
|
-
name: selection.model,
|
|
158
|
-
api: fallbackApi,
|
|
159
|
-
provider: selection.provider,
|
|
160
|
-
baseUrl: providerDefaultModel?.baseUrl ?? "",
|
|
161
|
-
reasoning: providerDefaultModel?.reasoning ?? false,
|
|
162
|
-
input: ["text"],
|
|
163
|
-
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
164
|
-
contextWindow: 128e3,
|
|
165
|
-
maxTokens: 16384
|
|
166
|
-
};
|
|
167
|
-
let resolution;
|
|
168
|
-
if (typeof childRegistry.getProviderAuth === "function") {
|
|
169
|
-
resolution = await childRegistry.getProviderAuth(selection.provider).catch((error) => {
|
|
170
|
-
throw withTypedReason(
|
|
171
|
-
new Error(`${label} authentication failed: ${error instanceof Error ? error.message : String(error)}`, { cause: error }),
|
|
172
|
-
"auth"
|
|
173
|
-
);
|
|
174
|
-
});
|
|
175
|
-
if (resolution === void 0) {
|
|
176
|
-
throw withTypedReason(
|
|
177
|
-
new Error(`${label} authentication failed: provider is not configured: ${selection.provider}`),
|
|
178
|
-
"auth"
|
|
179
|
-
);
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
let authResult;
|
|
183
|
-
if (typeof childRegistry.getApiKeyAndHeaders === "function") {
|
|
184
|
-
authResult = await childRegistry.getApiKeyAndHeaders(modelToUse);
|
|
185
|
-
if (authResult && !authResult.ok) {
|
|
186
|
-
throw withTypedReason(
|
|
187
|
-
new Error(`${label} authentication failed: ${authResult.error}`),
|
|
188
|
-
"auth"
|
|
189
|
-
);
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
const resolvedApiKey = authResult?.apiKey ?? resolution?.auth?.apiKey;
|
|
193
|
-
const resolvedHeaders = authResult?.headers ?? resolution?.auth?.headers;
|
|
194
|
-
const resolvedEnv = authResult?.env ?? resolution?.env;
|
|
195
|
-
const effectiveBaseUrl = resolution?.auth?.baseUrl ?? modelToUse.baseUrl;
|
|
196
|
-
const effectiveModel = {
|
|
197
|
-
...modelToUse,
|
|
198
|
-
baseUrl: effectiveBaseUrl
|
|
199
|
-
};
|
|
200
|
-
const credentials = new InMemoryCredentialStore();
|
|
201
|
-
const runtime = await ModelRuntime.create({
|
|
202
|
-
credentials,
|
|
203
|
-
modelsPath: null
|
|
204
|
-
});
|
|
205
|
-
if (resolvedApiKey !== void 0) {
|
|
206
|
-
await credentials.modify(selection.provider, async () => ({
|
|
207
|
-
type: "api_key",
|
|
208
|
-
key: resolvedApiKey,
|
|
209
|
-
...resolvedEnv === void 0 ? {} : { env: resolvedEnv }
|
|
210
|
-
}));
|
|
211
|
-
}
|
|
212
|
-
const abortReason = (signal) => signal.reason ?? new Error(`${label} provider stream aborted`);
|
|
213
|
-
let streamFailureValue;
|
|
214
|
-
async function waitForStream(promise, signal) {
|
|
215
|
-
if (signal.aborted) throw abortReason(signal);
|
|
216
|
-
let onAbort;
|
|
217
|
-
try {
|
|
218
|
-
return await Promise.race([
|
|
219
|
-
promise,
|
|
220
|
-
new Promise((_resolve, reject) => {
|
|
221
|
-
onAbort = () => reject(abortReason(signal));
|
|
222
|
-
signal.addEventListener("abort", onAbort, { once: true });
|
|
223
|
-
})
|
|
224
|
-
]);
|
|
225
|
-
} finally {
|
|
226
|
-
if (onAbort !== void 0) signal.removeEventListener("abort", onAbort);
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
const createRetriedStream = (simple, model, context, request) => {
|
|
230
|
-
const wrapped = createAssistantMessageEventStream();
|
|
231
|
-
void (async () => {
|
|
232
|
-
for (let attempt = 0; ; attempt += 1) {
|
|
233
|
-
const idle = createStreamIdleGuard(
|
|
234
|
-
options.signal === void 0 ? {} : { parentSignal: options.signal }
|
|
235
|
-
);
|
|
236
|
-
let observedHttpStatus;
|
|
237
|
-
let observedHttpPayload;
|
|
238
|
-
try {
|
|
239
|
-
const requestSignal = request?.signal;
|
|
240
|
-
const streamSignal = requestSignal === void 0 ? idle.signal : AbortSignal.any([idle.signal, requestSignal]);
|
|
241
|
-
const priorOnResponse = request?.onResponse;
|
|
242
|
-
const priorFetch = request?.fetch;
|
|
243
|
-
const baseFetch = priorFetch ?? globalThis.fetch.bind(globalThis);
|
|
244
|
-
const statusAwareFetch = async (input, init) => {
|
|
245
|
-
const response2 = await baseFetch(input, init);
|
|
246
|
-
if (isNonSuccessHttpStatus(response2?.status)) {
|
|
247
|
-
observedHttpStatus = response2.status;
|
|
248
|
-
try {
|
|
249
|
-
const parsed = JSON.parse(await response2.clone().text());
|
|
250
|
-
if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
251
|
-
observedHttpPayload = projectConfirmedRemotePayload(parsed);
|
|
252
|
-
}
|
|
253
|
-
} catch {
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
return response2;
|
|
257
|
-
};
|
|
258
|
-
const retriedRequest = {
|
|
259
|
-
...request ?? {},
|
|
260
|
-
...resolvedEnv === void 0 ? {} : { env: resolvedEnv },
|
|
261
|
-
signal: streamSignal,
|
|
262
|
-
maxRetries: 0,
|
|
263
|
-
fetch: statusAwareFetch,
|
|
264
|
-
onResponse: async (response2, resModel) => {
|
|
265
|
-
if (typeof response2?.status === "number") observedHttpStatus = response2.status;
|
|
266
|
-
await priorOnResponse?.(response2, resModel);
|
|
267
|
-
}
|
|
268
|
-
};
|
|
269
|
-
if (childProvider === void 0) {
|
|
270
|
-
throw withTypedReason(
|
|
271
|
-
new Error(`${label} provider not found: ${model.provider}`),
|
|
272
|
-
"model"
|
|
273
|
-
);
|
|
274
|
-
}
|
|
275
|
-
const source = simple ? childProvider.streamSimple(model, context, retriedRequest) : childProvider.stream(model, context, retriedRequest);
|
|
276
|
-
let sawEvent = false;
|
|
277
|
-
const attemptEvents = [];
|
|
278
|
-
const iterator = source[Symbol.asyncIterator]();
|
|
279
|
-
while (true) {
|
|
280
|
-
const next = await waitForStream(iterator.next(), idle.signal);
|
|
281
|
-
if (next.done) break;
|
|
282
|
-
sawEvent = true;
|
|
283
|
-
idle.poke();
|
|
284
|
-
attemptEvents.push(enrichStreamEvent(next.value, observedHttpStatus));
|
|
285
|
-
}
|
|
286
|
-
const response = attachObservedHttpStatus(
|
|
287
|
-
await waitForStream(source.result(), idle.signal),
|
|
288
|
-
observedHttpStatus
|
|
289
|
-
);
|
|
290
|
-
if (response.stopReason === "error") {
|
|
291
|
-
const errorMessage = response.errorMessage ?? `${label} provider stream failed`;
|
|
292
|
-
const idleFailure = streamIdleTimeoutFromUnknown(errorMessage);
|
|
293
|
-
if (options.idleRetry !== false && idleFailure !== void 0 && attempt < DEFAULT_COMPLIANCE_IDLE_MAX_RETRIES && options.signal?.aborted !== true) {
|
|
294
|
-
continue;
|
|
295
|
-
}
|
|
296
|
-
const failure = idleFailure ?? new Error(errorMessage, { cause: response });
|
|
297
|
-
const httpStatus = numericHttpStatus(observedHttpStatus) ?? numericHttpStatus(response.statusCode) ?? numericHttpStatus(response.status);
|
|
298
|
-
if (httpStatus !== void 0) {
|
|
299
|
-
Object.assign(failure, {
|
|
300
|
-
statusCode: httpStatus,
|
|
301
|
-
status: httpStatus,
|
|
302
|
-
...observedHttpPayload ?? {}
|
|
303
|
-
});
|
|
304
|
-
Object.assign(response, {
|
|
305
|
-
statusCode: httpStatus,
|
|
306
|
-
status: httpStatus,
|
|
307
|
-
...observedHttpPayload ?? {}
|
|
308
|
-
});
|
|
309
|
-
}
|
|
310
|
-
streamFailureValue = failure;
|
|
311
|
-
}
|
|
312
|
-
for (const ev of attemptEvents) {
|
|
313
|
-
wrapped.push(ev);
|
|
314
|
-
}
|
|
315
|
-
wrapped.end(response);
|
|
316
|
-
return;
|
|
317
|
-
} catch (error) {
|
|
318
|
-
if (request?.signal?.aborted) {
|
|
319
|
-
const response2 = {
|
|
320
|
-
role: "assistant",
|
|
321
|
-
content: [],
|
|
322
|
-
api: model.api,
|
|
323
|
-
provider: model.provider,
|
|
324
|
-
model: model.id,
|
|
325
|
-
usage: emptyUsage(),
|
|
326
|
-
stopReason: "aborted",
|
|
327
|
-
errorMessage: `${label} session aborted`,
|
|
328
|
-
timestamp: Date.now()
|
|
329
|
-
};
|
|
330
|
-
wrapped.push({ type: "error", reason: "aborted", error: response2 });
|
|
331
|
-
wrapped.end(response2);
|
|
332
|
-
return;
|
|
333
|
-
}
|
|
334
|
-
const failure = isStreamIdleTimeoutError(idle.signal.reason) ? idle.signal.reason : error;
|
|
335
|
-
const idleFailure = streamIdleTimeoutFromUnknown(failure);
|
|
336
|
-
if (options.idleRetry !== false && idleFailure !== void 0 && attempt < DEFAULT_COMPLIANCE_IDLE_MAX_RETRIES && options.signal?.aborted !== true) {
|
|
337
|
-
continue;
|
|
338
|
-
}
|
|
339
|
-
const typedFailure = idleFailure ?? failure;
|
|
340
|
-
const projected = projectStructuredRemote(failure);
|
|
341
|
-
const httpStatus = projected.httpStatus ?? numericHttpStatus(observedHttpStatus);
|
|
342
|
-
const payload = projectConfirmedRemotePayload({
|
|
343
|
-
body: projected.body ?? observedHttpPayload?.body,
|
|
344
|
-
code: projected.code ?? observedHttpPayload?.code,
|
|
345
|
-
errno: projected.errno ?? observedHttpPayload?.errno
|
|
346
|
-
});
|
|
347
|
-
if (httpStatus !== void 0 && typeof typedFailure === "object" && typedFailure !== null) {
|
|
348
|
-
Object.assign(typedFailure, { statusCode: httpStatus, status: httpStatus, ...payload });
|
|
349
|
-
}
|
|
350
|
-
streamFailureValue = typedFailure;
|
|
351
|
-
const response = {
|
|
352
|
-
role: "assistant",
|
|
353
|
-
content: [],
|
|
354
|
-
api: model.api,
|
|
355
|
-
provider: model.provider,
|
|
356
|
-
model: model.id,
|
|
357
|
-
usage: emptyUsage(),
|
|
358
|
-
stopReason: "error",
|
|
359
|
-
errorMessage: failure instanceof Error ? failure.message : String(failure),
|
|
360
|
-
timestamp: Date.now(),
|
|
361
|
-
...projected.diagnostics === void 0 ? {} : { diagnostics: projected.diagnostics },
|
|
362
|
-
...httpStatus === void 0 ? {} : { status: httpStatus, statusCode: httpStatus },
|
|
363
|
-
...payload
|
|
364
|
-
};
|
|
365
|
-
wrapped.push({ type: "error", reason: "error", error: response });
|
|
366
|
-
wrapped.end(response);
|
|
367
|
-
return;
|
|
368
|
-
} finally {
|
|
369
|
-
idle.dispose();
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
})();
|
|
373
|
-
return wrapped;
|
|
374
|
-
};
|
|
375
|
-
const provider = {
|
|
376
|
-
id: selection.provider,
|
|
377
|
-
name: childProvider?.name ?? label,
|
|
378
|
-
...effectiveBaseUrl ? { baseUrl: effectiveBaseUrl } : {},
|
|
379
|
-
...resolvedHeaders ? { headers: resolvedHeaders } : {},
|
|
380
|
-
auth: {
|
|
381
|
-
apiKey: {
|
|
382
|
-
name: `${label} authentication`,
|
|
383
|
-
async resolve() {
|
|
384
|
-
return {
|
|
385
|
-
auth: {
|
|
386
|
-
...resolvedApiKey === void 0 ? {} : { apiKey: resolvedApiKey },
|
|
387
|
-
...resolvedHeaders === void 0 ? {} : { headers: resolvedHeaders },
|
|
388
|
-
...effectiveBaseUrl === void 0 ? {} : { baseUrl: effectiveBaseUrl }
|
|
389
|
-
},
|
|
390
|
-
...resolvedEnv === void 0 ? {} : { env: resolvedEnv }
|
|
391
|
-
};
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
},
|
|
395
|
-
getModels() {
|
|
396
|
-
return [effectiveModel];
|
|
397
|
-
},
|
|
398
|
-
stream(model, childContext, request) {
|
|
399
|
-
return createRetriedStream(false, model, childContext, request);
|
|
400
|
-
},
|
|
401
|
-
streamSimple(model, childContext, request) {
|
|
402
|
-
return createRetriedStream(true, model, childContext, request);
|
|
403
|
-
}
|
|
404
|
-
};
|
|
405
|
-
runtime.registerNativeProvider(provider);
|
|
406
|
-
await runtime.refresh({ allowNetwork: false });
|
|
407
|
-
const settings = SettingsManager.inMemory({ compaction: { enabled: false }, retry: { enabled: false } });
|
|
408
|
-
const loader = new DefaultResourceLoader({
|
|
409
|
-
cwd: options.cwd,
|
|
410
|
-
agentDir: resolvedAgentDir,
|
|
411
|
-
settingsManager: settings,
|
|
412
|
-
noExtensions: true,
|
|
413
|
-
noSkills: true,
|
|
414
|
-
noPromptTemplates: true,
|
|
415
|
-
noThemes: true,
|
|
416
|
-
noContextFiles: true,
|
|
417
|
-
systemPrompt: options.systemPrompt
|
|
418
|
-
});
|
|
419
|
-
await loader.reload();
|
|
420
|
-
let sessionManager;
|
|
421
|
-
if (options.sessionManager !== void 0) {
|
|
422
|
-
sessionManager = options.sessionManager;
|
|
423
|
-
} else if (options.sessionIdentity !== void 0) {
|
|
424
|
-
sessionManager = createRecordSession({
|
|
425
|
-
cwd: options.cwd,
|
|
426
|
-
kind: options.sessionIdentity.kind,
|
|
427
|
-
...options.sessionIdentity.subject === void 0 ? {} : { subject: options.sessionIdentity.subject },
|
|
428
|
-
...options.sessionIdentity.parent === void 0 ? {} : { parent: options.sessionIdentity.parent }
|
|
429
|
-
});
|
|
430
|
-
} else {
|
|
431
|
-
sessionManager = createRecordSession({
|
|
432
|
-
cwd: options.cwd,
|
|
433
|
-
kind: "institutional"
|
|
434
|
-
});
|
|
435
|
-
}
|
|
436
|
-
const customTools = [];
|
|
437
|
-
if (options.customTools !== void 0) {
|
|
438
|
-
customTools.push(...options.customTools);
|
|
439
|
-
}
|
|
440
|
-
if (options.tools !== void 0) {
|
|
441
|
-
for (const hostTool of options.tools) {
|
|
442
|
-
customTools.push({
|
|
443
|
-
name: hostTool.name,
|
|
444
|
-
label: hostTool.label,
|
|
445
|
-
description: hostTool.description,
|
|
446
|
-
parameters: hostTool.parameters,
|
|
447
|
-
execute: async (toolCallId, params, signal, update, _ctx) => {
|
|
448
|
-
const res = await hostTool.execute(
|
|
449
|
-
toolCallId,
|
|
450
|
-
params,
|
|
451
|
-
signal,
|
|
452
|
-
update === void 0 ? void 0 : (u) => update(u),
|
|
453
|
-
void 0
|
|
454
|
-
);
|
|
455
|
-
return res;
|
|
456
|
-
}
|
|
457
|
-
});
|
|
458
|
-
}
|
|
459
|
-
}
|
|
460
|
-
const requestedThinking = selection.thinking;
|
|
461
|
-
const priorEntries = typeof sessionManager.getEntries === "function" ? sessionManager.getEntries() : [];
|
|
462
|
-
const reusedSession = priorEntries.some((entry) => {
|
|
463
|
-
if (typeof entry !== "object" || entry === null) return false;
|
|
464
|
-
const type = entry.type;
|
|
465
|
-
return type === "message" || type === "model_change" || type === "thinking_level_change";
|
|
466
|
-
});
|
|
467
|
-
const { session } = await createAgentSession({
|
|
468
|
-
cwd: options.cwd,
|
|
469
|
-
model: effectiveModel,
|
|
470
|
-
...requestedThinking === void 0 ? {} : { thinkingLevel: requestedThinking },
|
|
471
|
-
modelRuntime: runtime,
|
|
472
|
-
sessionManager,
|
|
473
|
-
settingsManager: settings,
|
|
474
|
-
agentDir: resolvedAgentDir,
|
|
475
|
-
resourceLoader: loader,
|
|
476
|
-
...options.noTools === void 0 ? {} : { noTools: options.noTools },
|
|
477
|
-
...options.toolsAllowlist === void 0 ? {} : { tools: options.toolsAllowlist },
|
|
478
|
-
...customTools.length === 0 ? {} : { customTools }
|
|
479
|
-
});
|
|
480
|
-
if (reusedSession) {
|
|
481
|
-
try {
|
|
482
|
-
await session.setModel(effectiveModel);
|
|
483
|
-
if (requestedThinking !== void 0) {
|
|
484
|
-
session.setThinkingLevel(requestedThinking);
|
|
485
|
-
}
|
|
486
|
-
} catch (error) {
|
|
487
|
-
session.dispose();
|
|
488
|
-
throw withTypedReason(
|
|
489
|
-
error instanceof Error ? error : new Error(
|
|
490
|
-
`${label} failed to apply seat model/thinking for ${selection.provider}/${selection.model}`
|
|
491
|
-
),
|
|
492
|
-
requestedThinking !== void 0 ? "thinking" : "model"
|
|
493
|
-
);
|
|
494
|
-
}
|
|
495
|
-
}
|
|
496
|
-
const listeners = /* @__PURE__ */ new Set();
|
|
497
|
-
const accumulatedUsage = emptyUsage();
|
|
498
|
-
let lastEmittedAssistant;
|
|
499
|
-
const unsubscribeSession = session.subscribe((event) => {
|
|
500
|
-
if (event.type === "message_end") {
|
|
501
|
-
const msg = event.message;
|
|
502
|
-
if (msg.role === "assistant") {
|
|
503
|
-
lastEmittedAssistant = msg;
|
|
504
|
-
if (msg.usage) {
|
|
505
|
-
addUsage(accumulatedUsage, msg.usage);
|
|
506
|
-
}
|
|
507
|
-
}
|
|
508
|
-
for (const listener of listeners) {
|
|
509
|
-
listener({
|
|
510
|
-
type: "message_end",
|
|
511
|
-
role: msg.role,
|
|
512
|
-
message: msg,
|
|
513
|
-
...msg.usage === void 0 ? {} : { usage: msg.usage }
|
|
514
|
-
});
|
|
515
|
-
}
|
|
516
|
-
} else if (event.type === "turn_end") {
|
|
517
|
-
const msg = event.message;
|
|
518
|
-
for (const listener of listeners) {
|
|
519
|
-
listener({
|
|
520
|
-
type: "turn_end",
|
|
521
|
-
...msg.stopReason === void 0 ? {} : { stopReason: msg.stopReason }
|
|
522
|
-
});
|
|
523
|
-
}
|
|
524
|
-
} else if (event.type === "tool_execution_start") {
|
|
525
|
-
for (const listener of listeners) {
|
|
526
|
-
listener({
|
|
527
|
-
type: "tool_call",
|
|
528
|
-
toolCallId: event.toolCallId,
|
|
529
|
-
toolName: event.toolName,
|
|
530
|
-
args: event.args ?? event.input
|
|
531
|
-
});
|
|
532
|
-
}
|
|
533
|
-
} else if (event.type === "tool_execution_end") {
|
|
534
|
-
for (const listener of listeners) {
|
|
535
|
-
listener({
|
|
536
|
-
type: "tool_result",
|
|
537
|
-
toolCallId: event.toolCallId,
|
|
538
|
-
toolName: event.toolName,
|
|
539
|
-
isError: event.isError,
|
|
540
|
-
details: event.result ?? event.details
|
|
541
|
-
});
|
|
542
|
-
}
|
|
543
|
-
}
|
|
544
|
-
});
|
|
545
|
-
let closed = false;
|
|
546
|
-
const sessionFile = sessionManager.getSessionFile();
|
|
547
|
-
const sessionId = sessionManager.getHeader?.()?.id;
|
|
548
|
-
const handle = {
|
|
549
|
-
...sessionFile === void 0 ? {} : { sessionFile },
|
|
550
|
-
...sessionId === void 0 ? {} : { sessionId },
|
|
551
|
-
async prompt(text) {
|
|
552
|
-
const abortSession = () => {
|
|
553
|
-
void session.abort();
|
|
554
|
-
};
|
|
555
|
-
if (options.signal?.aborted) abortSession();
|
|
556
|
-
else options.signal?.addEventListener("abort", abortSession, { once: true });
|
|
557
|
-
const assistantCountBefore = session.messages.filter(
|
|
558
|
-
(message) => message.role === "assistant"
|
|
559
|
-
).length;
|
|
560
|
-
let promptError;
|
|
561
|
-
try {
|
|
562
|
-
await session.prompt(text);
|
|
563
|
-
} catch (error) {
|
|
564
|
-
promptError = error;
|
|
565
|
-
} finally {
|
|
566
|
-
options.signal?.removeEventListener("abort", abortSession);
|
|
567
|
-
}
|
|
568
|
-
const lastAssistant = [...session.messages].reverse().find((message) => message.role === "assistant");
|
|
569
|
-
if (lastAssistant !== void 0 && lastAssistant !== lastEmittedAssistant) {
|
|
570
|
-
lastEmittedAssistant = lastAssistant;
|
|
571
|
-
for (const listener of listeners) {
|
|
572
|
-
listener({
|
|
573
|
-
type: "message_end",
|
|
574
|
-
role: lastAssistant.role,
|
|
575
|
-
message: lastAssistant,
|
|
576
|
-
...lastAssistant.usage === void 0 ? {} : { usage: lastAssistant.usage }
|
|
577
|
-
});
|
|
578
|
-
}
|
|
579
|
-
}
|
|
580
|
-
const producedAssistant = session.messages.filter(
|
|
581
|
-
(message) => message.role === "assistant"
|
|
582
|
-
).length > assistantCountBefore;
|
|
583
|
-
if (promptError !== void 0 && !producedAssistant) {
|
|
584
|
-
throw promptError;
|
|
585
|
-
}
|
|
586
|
-
return {
|
|
587
|
-
text: session.getLastAssistantText() ?? "",
|
|
588
|
-
...lastAssistant?.stopReason === void 0 ? {} : { stopReason: lastAssistant.stopReason },
|
|
589
|
-
...lastAssistant?.errorMessage === void 0 ? {} : { errorMessage: lastAssistant.errorMessage },
|
|
590
|
-
usage: accumulatedUsage,
|
|
591
|
-
messages: session.messages
|
|
592
|
-
};
|
|
593
|
-
},
|
|
594
|
-
subscribe(listener) {
|
|
595
|
-
listeners.add(listener);
|
|
596
|
-
return () => {
|
|
597
|
-
listeners.delete(listener);
|
|
598
|
-
};
|
|
599
|
-
},
|
|
600
|
-
abort() {
|
|
601
|
-
void session.abort();
|
|
602
|
-
},
|
|
603
|
-
async close() {
|
|
604
|
-
if (closed) return;
|
|
605
|
-
closed = true;
|
|
606
|
-
listeners.clear();
|
|
607
|
-
const cleanupFailures = [];
|
|
608
|
-
try {
|
|
609
|
-
unsubscribeSession();
|
|
610
|
-
} catch (error) {
|
|
611
|
-
cleanupFailures.push(error);
|
|
612
|
-
}
|
|
613
|
-
try {
|
|
614
|
-
session.dispose();
|
|
615
|
-
} catch (error) {
|
|
616
|
-
cleanupFailures.push(error);
|
|
617
|
-
}
|
|
618
|
-
if (scratchDir !== void 0) {
|
|
619
|
-
try {
|
|
620
|
-
await rm(scratchDir, { recursive: true, force: true });
|
|
621
|
-
} catch (error) {
|
|
622
|
-
cleanupFailures.push(error);
|
|
623
|
-
}
|
|
624
|
-
}
|
|
625
|
-
if (cleanupFailures.length === 1) throw cleanupFailures[0];
|
|
626
|
-
if (cleanupFailures.length > 1) {
|
|
627
|
-
throw new AggregateError(cleanupFailures, `${label} close cleanup failures`, {
|
|
628
|
-
cause: cleanupFailures[0]
|
|
629
|
-
});
|
|
630
|
-
}
|
|
631
|
-
}
|
|
632
|
-
};
|
|
633
|
-
return {
|
|
634
|
-
handle,
|
|
635
|
-
// Read lazily: the provider stream runs during session.prompt, so the
|
|
636
|
-
// primary failure is only known after that turn completes. A getter keeps
|
|
637
|
-
// this reflecting the latest value instead of freezing it at open time.
|
|
638
|
-
get streamFailure() {
|
|
639
|
-
return streamFailureValue;
|
|
640
|
-
}
|
|
641
|
-
};
|
|
642
|
-
} catch (openError) {
|
|
643
|
-
if (scratchDir !== void 0) {
|
|
644
|
-
try {
|
|
645
|
-
await rm(scratchDir, { recursive: true, force: true });
|
|
646
|
-
} catch (cleanupFailure) {
|
|
647
|
-
throw new AggregateError(
|
|
648
|
-
[openError, cleanupFailure],
|
|
649
|
-
`${label} open failed and its scratch cleanup also failed`,
|
|
650
|
-
{ cause: openError }
|
|
651
|
-
);
|
|
652
|
-
}
|
|
653
|
-
}
|
|
654
|
-
throw openError;
|
|
655
|
-
}
|
|
656
|
-
}
|
|
657
|
-
export {
|
|
658
|
-
DEFAULT_COMPLIANCE_IDLE_MAX_RETRIES,
|
|
659
|
-
openPiInProcessSession
|
|
660
|
-
};
|