@astrosheep/keiyaku 2.9.4 → 2.9.5
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/build/.tsbuildinfo +1 -1
- package/build/agents/call-terms.js +1 -0
- package/build/agents/harness/execution-handle.js +1 -0
- package/build/agents/harness/outcome.js +21 -1
- package/build/agents/harness/projection.js +147 -75
- package/build/agents/providers/codex-app-server/adapter.js +32 -0
- package/build/agents/providers/codex-app-server/events.js +23 -0
- package/build/agents/providers/pi/events.js +4 -3
- package/build/agents/types.js +2 -0
- package/build/cli/commands/akuma/akuma/meta.js +1 -1
- package/build/cli/commands/akuma/list/meta-ls.js +1 -1
- package/build/cli/commands/akuma/view/meta.js +1 -1
- package/build/cli/commands/contract/amend/meta.js +4 -4
- package/build/cli/commands/contract/arc/handler.js +1 -1
- package/build/cli/commands/contract/arc/meta.js +4 -4
- package/build/cli/commands/contract/audit/handler.js +16 -0
- package/build/cli/commands/contract/audit/meta.js +16 -0
- package/build/cli/commands/contract/bind/meta.js +20 -11
- package/build/cli/commands/contract/catalog.js +2 -0
- package/build/cli/commands/contract/forfeit/meta.js +1 -1
- package/build/cli/commands/contract/log/meta.js +1 -1
- package/build/cli/commands/contract/petition/handler.js +1 -2
- package/build/cli/commands/contract/petition/meta.js +6 -6
- package/build/cli/commands/contract/renew/handler.js +2 -2
- package/build/cli/commands/contract/renew/meta.js +4 -4
- package/build/cli/commands/metadata.js +3 -2
- package/build/cli/commands/projection/call/meta.js +4 -1
- package/build/cli/commands/projection/kill/meta.js +1 -1
- package/build/cli/commands/projection/revive/meta.js +4 -1
- package/build/cli/commands/projection/status/meta.js +1 -1
- package/build/cli/commands/projection/tell/handler.js +1 -1
- package/build/cli/commands/projection/tell/meta.js +4 -1
- package/build/cli/commands/projection/wait/meta.js +1 -1
- package/build/cli/commands/skills/install/meta.js +1 -1
- package/build/cli/commands/skills/skills/meta.js +1 -1
- package/build/cli/commands/system/completion/meta.js +1 -1
- package/build/cli/commands/system/dump-env/meta.js +1 -1
- package/build/cli/commands/system/guide/meta.js +1 -1
- package/build/cli/commands/task/add/handler.js +2 -2
- package/build/cli/commands/task/add/meta.js +4 -1
- package/build/cli/commands/task/doctor/meta.js +1 -1
- package/build/cli/commands/task/done/meta.js +1 -1
- package/build/cli/commands/task/drop/meta.js +1 -1
- package/build/cli/commands/task/ls/handler.js +10 -4
- package/build/cli/commands/task/ls/meta.js +3 -3
- package/build/cli/commands/task/show/meta.js +1 -1
- package/build/cli/commands/task/start/meta.js +1 -1
- package/build/cli/commands/task/stop/meta.js +1 -1
- package/build/cli/commands/task/task/meta.js +1 -1
- package/build/cli/commands/task/update/handler.js +2 -3
- package/build/cli/commands/task/update/meta.js +4 -1
- package/build/cli/flags.js +18 -3
- package/build/cli/help.js +3 -3
- package/build/cli/index.js +59 -75
- package/build/cli/output-stream-error-policy.js +19 -5
- package/build/cli/parse-flags.js +19 -2
- package/build/cli/parse-metadata.js +1 -7
- package/build/cli/parse-selectors.js +1 -0
- package/build/cli/parse.js +16 -7
- package/build/cli/projection-address.js +6 -1
- package/build/cli/render/audit.js +121 -0
- package/build/cli/render/misc.js +3 -1
- package/build/cli/render/projection-activity.js +12 -6
- package/build/cli/render/status.js +28 -18
- package/build/cli/render/success-response.js +6 -5
- package/build/cli/render/task.js +12 -43
- package/build/cli/render/terminal-failure.js +7 -2
- package/build/cli/render/wait.js +36 -8
- package/build/config/env-keys.js +2 -0
- package/build/config/env.js +3 -0
- package/build/core/amend.js +20 -94
- package/build/core/arc.js +14 -6
- package/build/core/audit.js +650 -0
- package/build/core/bind.js +1 -1
- package/build/core/call/execution.js +1 -0
- package/build/core/contract-view.js +2 -3
- package/build/core/draft.js +33 -20
- package/build/core/entry.js +3 -4
- package/build/core/markdown/lex.js +2 -1
- package/build/core/projection/generation/database.js +41 -16
- package/build/core/projection/generation/model.js +22 -2
- package/build/core/projection/generation/projection-generation-execution.js +20 -7
- package/build/core/projection/generation/projection-generation-launcher.js +4 -4
- package/build/core/projection/generation/projection-generation-runner.js +1 -0
- package/build/core/projection/generation/store.js +1 -1
- package/build/core/projection/generation/transitions.js +19 -3
- package/build/core/projection/index.js +2 -2
- package/build/core/projection/projection-execution-observer.js +35 -21
- package/build/core/projection/projection-life-observer.js +16 -2
- package/build/core/projection/projection-status.js +67 -22
- package/build/core/projection/projection-terminal-failure.js +2 -0
- package/build/core/projection/projection-wait.js +6 -9
- package/build/core/projection/projection-wake.js +30 -6
- package/build/core/renew.js +41 -22
- package/build/core/scope.js +129 -2
- package/build/core/seal.js +36 -15
- package/build/core/settlement/petition-claim-gates.js +4 -33
- package/build/core/settlement/petition-preview.js +1 -1
- package/build/core/settlement/petition.js +10 -3
- package/build/core/settlement/settlement.js +3 -10
- package/build/core/settlement/verification.js +59 -0
- package/build/core/status/board.js +48 -28
- package/build/core/stored-agent-event.js +3 -2
- package/build/core/task/board.js +1 -0
- package/build/core/task/commands.js +20 -12
- package/build/core/task/document.js +5 -0
- package/build/core/task/index.js +1 -1
- package/build/core/task/model.js +8 -1
- package/build/core/task/query.js +172 -0
- package/build/core/task/settlement-git.js +115 -16
- package/build/core/task/settlement-policy.js +17 -9
- package/build/core/task/source-board.js +1 -0
- package/build/core/task/task-contract.js +125 -51
- package/build/core/task/task-store-repository.js +1 -0
- package/build/core/task/task.js +2 -0
- package/build/flow-error.js +2 -4
- package/build/generated/version.js +2 -2
- package/build/git/diff/parsers.js +23 -13
- package/build/git/diff/structured.js +127 -0
- package/build/index.js +7 -7
- package/build/telemetry/logger.js +4 -2
- package/package.json +1 -1
- package/skills/keiyaku/SKILL.md +2 -2
- package/skills/keiyaku-akuma/SKILL.md +17 -6
- package/skills/keiyaku-task/SKILL.md +16 -7
- package/skills/keiyaku-workflow/SKILL.md +42 -13
|
@@ -15,6 +15,7 @@ export function buildCallTerms(snapshot, prompt, cwd, options) {
|
|
|
15
15
|
prompt,
|
|
16
16
|
sessionContinuationPromptPrefix,
|
|
17
17
|
idleTimeoutMs: options.idleTimeoutMs ?? runtimeConfig.subagent.execIdleTimeoutMs,
|
|
18
|
+
executionTimeoutMs: options.executionTimeoutMs ?? runtimeConfig.subagent.execMaxDurationMs,
|
|
18
19
|
maxCaptureChars: registration.maxCaptureChars(runtimeConfig),
|
|
19
20
|
signal: options.signal,
|
|
20
21
|
...(options.initialTurn !== undefined ? { initialTurn: options.initialTurn } : {}),
|
|
@@ -64,7 +64,15 @@ export function failFromFailEvent(shared, state, failEvent) {
|
|
|
64
64
|
exitCode: failEvent.exitCode ?? null,
|
|
65
65
|
}, state.finalMessageCandidate, failEvent.diagnostics ?? diagnostics);
|
|
66
66
|
}
|
|
67
|
-
export function classifyFailure(shared, state, error, idleTimedOut) {
|
|
67
|
+
export function classifyFailure(shared, state, error, idleTimedOut, transportFailure, policyBudgetExceeded = false) {
|
|
68
|
+
if (policyBudgetExceeded) {
|
|
69
|
+
return failWithError(shared, state, {
|
|
70
|
+
code: "SUBAGENT_POLICY_BUDGET",
|
|
71
|
+
message: `${shared.terms.provider} execution policy budget expired`,
|
|
72
|
+
timeoutMs: shared.terms.executionTimeoutMs,
|
|
73
|
+
exitCode: null,
|
|
74
|
+
}, state.finalMessageCandidate);
|
|
75
|
+
}
|
|
68
76
|
if (shared.dismissed || shared.externallyAborted) {
|
|
69
77
|
return mintOutcome({
|
|
70
78
|
status: "dismissed",
|
|
@@ -75,6 +83,18 @@ export function classifyFailure(shared, state, error, idleTimedOut) {
|
|
|
75
83
|
warnings: [...state.warnings],
|
|
76
84
|
});
|
|
77
85
|
}
|
|
86
|
+
if (transportFailure) {
|
|
87
|
+
const message = transportFailure instanceof Error ? transportFailure.message : `${shared.terms.provider} session transport probe failed`;
|
|
88
|
+
const timeoutMs = isProviderTerminalError(transportFailure) && transportFailure.fact.kind === "failed"
|
|
89
|
+
? transportFailure.fact.timeoutMs
|
|
90
|
+
: shared.terms.idleTimeoutMs;
|
|
91
|
+
return failWithError(shared, state, {
|
|
92
|
+
code: "SUBAGENT_TRANSPORT_ERROR",
|
|
93
|
+
message,
|
|
94
|
+
timeoutMs,
|
|
95
|
+
exitCode: null,
|
|
96
|
+
}, state.finalMessageCandidate);
|
|
97
|
+
}
|
|
78
98
|
if (idleTimedOut) {
|
|
79
99
|
return failWithError(shared, state, {
|
|
80
100
|
code: "SUBAGENT_TIMEOUT",
|
|
@@ -5,6 +5,7 @@ import { overflowMarkerFromDropped, prepareAgentEventForPersistence, } from "./e
|
|
|
5
5
|
import { classifyFailure, classifySettlementFailure, completeOutcome, createOutcomeState, failFromFailEvent, failWithError, processEvent, renderOutcomeCapturedText, } from "./outcome.js";
|
|
6
6
|
import { startLiveProjection } from "./router.js";
|
|
7
7
|
import { createAbortError } from "./runtime.js";
|
|
8
|
+
const POLICY_BUDGET_CLEANUP_GRACE_MS = 5_000;
|
|
8
9
|
export function call(terms, options) {
|
|
9
10
|
return createProjection(terms, undefined, options);
|
|
10
11
|
}
|
|
@@ -154,7 +155,21 @@ function requestControlledGracefulAbort(shared, reason) {
|
|
|
154
155
|
shared.gracefulAbort.catch(() => undefined);
|
|
155
156
|
return shared.gracefulAbort;
|
|
156
157
|
}
|
|
157
|
-
function
|
|
158
|
+
function requestPolicyBudgetCleanup(shared, reason) {
|
|
159
|
+
const graceful = requestControlledGracefulAbort(shared, reason);
|
|
160
|
+
const force = () => {
|
|
161
|
+
void shared.live?.abort("force").catch(() => undefined);
|
|
162
|
+
};
|
|
163
|
+
const cleanupTimeout = setTimeout(force, POLICY_BUDGET_CLEANUP_GRACE_MS);
|
|
164
|
+
cleanupTimeout.unref?.();
|
|
165
|
+
void graceful.then(() => clearTimeout(cleanupTimeout), () => {
|
|
166
|
+
clearTimeout(cleanupTimeout);
|
|
167
|
+
force();
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
function deliverDriverEvent(shared, state, live, event, refreshIdleTimeout, knownActiveTools, observerEnabled) {
|
|
171
|
+
if (shared.terminal)
|
|
172
|
+
return;
|
|
158
173
|
const prepared = prepareAgentEventForPersistence(event);
|
|
159
174
|
if (observerEnabled.value && shared.observer) {
|
|
160
175
|
try {
|
|
@@ -173,24 +188,63 @@ function deliverDriverEvent(shared, state, live, event, refreshIdleTimeout, obse
|
|
|
173
188
|
}
|
|
174
189
|
}
|
|
175
190
|
shared.publicEvents.push(event);
|
|
191
|
+
if (event.type === "activity") {
|
|
192
|
+
if (event.phase === "started")
|
|
193
|
+
knownActiveTools.add(event.id);
|
|
194
|
+
if (event.phase === "completed")
|
|
195
|
+
knownActiveTools.delete(event.id);
|
|
196
|
+
}
|
|
176
197
|
refreshIdleTimeout();
|
|
177
198
|
processEvent(state, event);
|
|
178
199
|
}
|
|
179
200
|
async function settleProjection(shared) {
|
|
180
201
|
const state = createOutcomeState(shared.terms.maxCaptureChars);
|
|
181
202
|
let idleTimedOut = false;
|
|
203
|
+
let transportFailure;
|
|
204
|
+
let policyBudgetExceeded = false;
|
|
205
|
+
const knownActiveTools = new Set();
|
|
182
206
|
let abortRequested = false;
|
|
183
207
|
const observerEnabled = { value: shared.observer !== undefined };
|
|
184
208
|
let idleTimeout;
|
|
209
|
+
let executionTimeout;
|
|
210
|
+
let liveDriver;
|
|
211
|
+
let probeInFlight;
|
|
212
|
+
let resolvePolicyBudget;
|
|
213
|
+
const policyBudget = new Promise((resolve) => {
|
|
214
|
+
resolvePolicyBudget = resolve;
|
|
215
|
+
});
|
|
185
216
|
const refreshIdleTimeout = () => {
|
|
217
|
+
if (shared.terminal)
|
|
218
|
+
return;
|
|
186
219
|
if (idleTimeout)
|
|
187
220
|
clearTimeout(idleTimeout);
|
|
188
221
|
idleTimeout = setTimeout(() => {
|
|
222
|
+
if (knownActiveTools.size > 0) {
|
|
223
|
+
if (!liveDriver?.probe || probeInFlight)
|
|
224
|
+
return;
|
|
225
|
+
probeInFlight = liveDriver.probe()
|
|
226
|
+
.then(() => refreshIdleTimeout())
|
|
227
|
+
.catch((error) => {
|
|
228
|
+
transportFailure = error;
|
|
229
|
+
return requestControlledGracefulAbort(shared, error);
|
|
230
|
+
})
|
|
231
|
+
.finally(() => {
|
|
232
|
+
probeInFlight = undefined;
|
|
233
|
+
});
|
|
234
|
+
probeInFlight.catch(() => undefined);
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
189
237
|
idleTimedOut = true;
|
|
190
238
|
requestControlledGracefulAbort(shared, createAbortError(`${shared.terms.provider} exec idle timed out`));
|
|
191
239
|
}, shared.terms.idleTimeoutMs);
|
|
192
240
|
idleTimeout.unref?.();
|
|
193
241
|
};
|
|
242
|
+
executionTimeout = setTimeout(() => {
|
|
243
|
+
policyBudgetExceeded = true;
|
|
244
|
+
requestPolicyBudgetCleanup(shared, createAbortError(`${shared.terms.provider} execution policy budget expired`));
|
|
245
|
+
resolvePolicyBudget();
|
|
246
|
+
}, shared.terms.executionTimeoutMs);
|
|
247
|
+
executionTimeout.unref?.();
|
|
194
248
|
refreshIdleTimeout();
|
|
195
249
|
const requestLiveAbort = () => {
|
|
196
250
|
if (shared.explicitlyAborted)
|
|
@@ -201,90 +255,108 @@ async function settleProjection(shared) {
|
|
|
201
255
|
requestControlledGracefulAbort(shared, shared.lifecycleAbort.signal.reason);
|
|
202
256
|
};
|
|
203
257
|
shared.lifecycleAbort.signal.addEventListener("abort", requestLiveAbort, { once: true });
|
|
204
|
-
|
|
205
|
-
const live = await startLiveProjection(shared.terms, shared.lifecycleAbort.signal, shared.reviveTerms, refreshIdleTimeout, shared.observer);
|
|
206
|
-
shared.onLive(live);
|
|
207
|
-
resolveForceWaiters(shared, live);
|
|
208
|
-
if (shared.lifecycleAbort.signal.aborted) {
|
|
209
|
-
requestLiveAbort();
|
|
210
|
-
}
|
|
258
|
+
const providerSettlement = (async () => {
|
|
211
259
|
try {
|
|
212
|
-
|
|
213
|
-
|
|
260
|
+
const live = await startLiveProjection(shared.terms, shared.lifecycleAbort.signal, shared.reviveTerms, refreshIdleTimeout, shared.observer);
|
|
261
|
+
liveDriver = live;
|
|
262
|
+
shared.onLive(live);
|
|
263
|
+
resolveForceWaiters(shared, live);
|
|
264
|
+
if (shared.lifecycleAbort.signal.aborted) {
|
|
265
|
+
requestLiveAbort();
|
|
214
266
|
}
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
type: "fail",
|
|
220
|
-
code: "PROJECTION_STATE_ERROR",
|
|
221
|
-
message: error.message,
|
|
222
|
-
});
|
|
223
|
-
if (event)
|
|
224
|
-
deliverDriverEvent(shared, state, live, event, refreshIdleTimeout, observerEnabled);
|
|
267
|
+
try {
|
|
268
|
+
for await (const event of live.events) {
|
|
269
|
+
deliverDriverEvent(shared, state, live, event, refreshIdleTimeout, knownActiveTools, observerEnabled);
|
|
270
|
+
}
|
|
225
271
|
}
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
272
|
+
catch (error) {
|
|
273
|
+
if (error instanceof Error && error.code === "PROJECTION_STATE_ERROR") {
|
|
274
|
+
const event = live.mintEvent({
|
|
275
|
+
type: "fail",
|
|
276
|
+
code: "PROJECTION_STATE_ERROR",
|
|
277
|
+
message: error.message,
|
|
278
|
+
});
|
|
279
|
+
if (event)
|
|
280
|
+
deliverDriverEvent(shared, state, live, event, refreshIdleTimeout, knownActiveTools, observerEnabled);
|
|
281
|
+
}
|
|
282
|
+
else {
|
|
283
|
+
const event = live.mintEvent({
|
|
284
|
+
type: "diagnostic",
|
|
285
|
+
text: `pump error: ${String(error)}`,
|
|
286
|
+
});
|
|
287
|
+
if (event)
|
|
288
|
+
deliverDriverEvent(shared, state, live, event, refreshIdleTimeout, knownActiveTools, observerEnabled);
|
|
289
|
+
}
|
|
233
290
|
}
|
|
291
|
+
const completionResult = await live.completion.then((value) => ({ ok: true, value }), (error) => ({ ok: false, error }));
|
|
292
|
+
const completionOutcome = completionResult.ok ? completionResult.value : undefined;
|
|
293
|
+
// Outcome classification is the terminal publication boundary. A
|
|
294
|
+
// controlled abort may let the provider run settle before its graceful
|
|
295
|
+
// cleanup promise does, so prove that shared settlement before publishing
|
|
296
|
+
// dismissed, failed-for-another-reason, or completed truth.
|
|
297
|
+
const gracefulResult = shared.gracefulAbort
|
|
298
|
+
? await shared.gracefulAbort.then(() => ({ ok: true }), (error) => ({ ok: false, error }))
|
|
299
|
+
: undefined;
|
|
300
|
+
if (gracefulResult && !gracefulResult.ok && !transportFailure) {
|
|
301
|
+
return classifySettlementFailure(shared, state, gracefulResult.error);
|
|
302
|
+
}
|
|
303
|
+
if (policyBudgetExceeded || transportFailure) {
|
|
304
|
+
return classifyFailure(shared, state, completionResult.ok ? undefined : completionResult.error, idleTimedOut, transportFailure, policyBudgetExceeded);
|
|
305
|
+
}
|
|
306
|
+
if (state.failEvent) {
|
|
307
|
+
return failFromFailEvent(shared, state, state.failEvent);
|
|
308
|
+
}
|
|
309
|
+
if (!completionResult.ok) {
|
|
310
|
+
return classifyFailure(shared, state, completionResult.error, idleTimedOut, transportFailure, policyBudgetExceeded);
|
|
311
|
+
}
|
|
312
|
+
if (shared.lifecycleAbort.signal.aborted) {
|
|
313
|
+
return classifyFailure(shared, state, shared.lifecycleAbort.signal.reason, idleTimedOut, transportFailure, policyBudgetExceeded);
|
|
314
|
+
}
|
|
315
|
+
if (!state.doneEvent && !completionOutcome) {
|
|
316
|
+
return failWithError(shared, state, {
|
|
317
|
+
code: "SUBAGENT_EXEC_ERROR",
|
|
318
|
+
message: `${shared.terms.provider} exec ended before completion`,
|
|
319
|
+
timeoutMs: null,
|
|
320
|
+
exitCode: null,
|
|
321
|
+
}, state.finalMessageCandidate);
|
|
322
|
+
}
|
|
323
|
+
const finalMessage = state.doneEvent?.finalMessage ??
|
|
324
|
+
completionOutcome?.finalMessage ??
|
|
325
|
+
state.finalMessageCandidate ??
|
|
326
|
+
renderOutcomeCapturedText(state.outputBuffer).trim();
|
|
327
|
+
const session = state.doneEvent?.session ?? completionOutcome?.session;
|
|
328
|
+
if (!session) {
|
|
329
|
+
return failWithError(shared, state, {
|
|
330
|
+
code: "SUBAGENT_EXEC_ERROR",
|
|
331
|
+
message: `${shared.terms.provider} exec ended without a session handle`,
|
|
332
|
+
timeoutMs: null,
|
|
333
|
+
exitCode: null,
|
|
334
|
+
}, finalMessage);
|
|
335
|
+
}
|
|
336
|
+
return completeOutcome(shared, state, finalMessage, session);
|
|
234
337
|
}
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
// dismissed, failed-for-another-reason, or completed truth.
|
|
241
|
-
const gracefulResult = shared.gracefulAbort
|
|
242
|
-
? await shared.gracefulAbort.then(() => ({ ok: true }), (error) => ({ ok: false, error }))
|
|
243
|
-
: undefined;
|
|
244
|
-
if (gracefulResult && !gracefulResult.ok) {
|
|
245
|
-
return classifySettlementFailure(shared, state, gracefulResult.error);
|
|
246
|
-
}
|
|
247
|
-
if (state.failEvent) {
|
|
248
|
-
return failFromFailEvent(shared, state, state.failEvent);
|
|
249
|
-
}
|
|
250
|
-
if (!completionResult.ok) {
|
|
251
|
-
return classifyFailure(shared, state, completionResult.error, idleTimedOut);
|
|
252
|
-
}
|
|
253
|
-
if (shared.lifecycleAbort.signal.aborted) {
|
|
254
|
-
return classifyFailure(shared, state, shared.lifecycleAbort.signal.reason, idleTimedOut);
|
|
255
|
-
}
|
|
256
|
-
if (!state.doneEvent && !completionOutcome) {
|
|
257
|
-
return failWithError(shared, state, {
|
|
258
|
-
code: "SUBAGENT_EXEC_ERROR",
|
|
259
|
-
message: `${shared.terms.provider} exec ended before completion`,
|
|
260
|
-
timeoutMs: null,
|
|
261
|
-
exitCode: null,
|
|
262
|
-
}, state.finalMessageCandidate);
|
|
263
|
-
}
|
|
264
|
-
const finalMessage = state.doneEvent?.finalMessage ??
|
|
265
|
-
completionOutcome?.finalMessage ??
|
|
266
|
-
state.finalMessageCandidate ??
|
|
267
|
-
renderOutcomeCapturedText(state.outputBuffer).trim();
|
|
268
|
-
const session = state.doneEvent?.session ?? completionOutcome?.session;
|
|
269
|
-
if (!session) {
|
|
270
|
-
return failWithError(shared, state, {
|
|
271
|
-
code: "SUBAGENT_EXEC_ERROR",
|
|
272
|
-
message: `${shared.terms.provider} exec ended without a session handle`,
|
|
273
|
-
timeoutMs: null,
|
|
274
|
-
exitCode: null,
|
|
275
|
-
}, finalMessage);
|
|
276
|
-
}
|
|
277
|
-
return completeOutcome(shared, state, finalMessage, session);
|
|
278
|
-
}
|
|
279
|
-
catch (error) {
|
|
280
|
-
if (error instanceof FlowError) {
|
|
281
|
-
throw error;
|
|
338
|
+
catch (error) {
|
|
339
|
+
if (error instanceof FlowError) {
|
|
340
|
+
throw error;
|
|
341
|
+
}
|
|
342
|
+
return classifyFailure(shared, state, error, idleTimedOut, transportFailure, policyBudgetExceeded);
|
|
282
343
|
}
|
|
283
|
-
|
|
344
|
+
})();
|
|
345
|
+
providerSettlement.catch(() => undefined);
|
|
346
|
+
try {
|
|
347
|
+
const settled = await Promise.race([
|
|
348
|
+
providerSettlement.then((outcome) => ({ kind: "provider", outcome })),
|
|
349
|
+
policyBudget.then(() => ({ kind: "policy-budget" })),
|
|
350
|
+
]);
|
|
351
|
+
return settled.kind === "provider"
|
|
352
|
+
? settled.outcome
|
|
353
|
+
: classifyFailure(shared, state, undefined, idleTimedOut, transportFailure, true);
|
|
284
354
|
}
|
|
285
355
|
finally {
|
|
286
356
|
if (idleTimeout)
|
|
287
357
|
clearTimeout(idleTimeout);
|
|
358
|
+
if (executionTimeout)
|
|
359
|
+
clearTimeout(executionTimeout);
|
|
288
360
|
shared.lifecycleAbort.signal.removeEventListener("abort", requestLiveAbort);
|
|
289
361
|
shared.terminal = true;
|
|
290
362
|
resolveForceWaiters(shared, undefined);
|
|
@@ -13,6 +13,7 @@ function toCodexAppServerEffort(effort) {
|
|
|
13
13
|
}
|
|
14
14
|
export { codexAppServerSessionSchema } from "./session-schema.js";
|
|
15
15
|
const MINIMUM_CODEX_APP_SERVER_VERSION = { major: 0, minor: 143, patch: 0 };
|
|
16
|
+
const CODEX_APP_SERVER_PROBE_TIMEOUT_MS = 1_000;
|
|
16
17
|
/** Non-interactive defaults for turn/start (faye #316 policy A). */
|
|
17
18
|
export const CODEX_APP_SERVER_TURN_APPROVAL_POLICY = "never";
|
|
18
19
|
export { buildCodexAppServerWorkspaceWriteSandboxPolicy, configOwnsApprovalPolicy, configOwnsSandboxPolicy, } from "./policy.js";
|
|
@@ -172,10 +173,41 @@ export async function startCodexAppServer(prompt, cwd, options = {}) {
|
|
|
172
173
|
void drainPendingTells();
|
|
173
174
|
});
|
|
174
175
|
};
|
|
176
|
+
const probe = async () => {
|
|
177
|
+
if (!server || !activeThreadId) {
|
|
178
|
+
throw createProviderFailure(`${CODEX_APP_SERVER_PROVIDER} session probe has no active thread`, {
|
|
179
|
+
code: "SUBAGENT_TRANSPORT_ERROR",
|
|
180
|
+
timeoutMs: CODEX_APP_SERVER_PROBE_TIMEOUT_MS,
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
let timer;
|
|
184
|
+
const deadline = new Promise((_, reject) => {
|
|
185
|
+
timer = setTimeout(() => reject(new Error("session probe timed out")), CODEX_APP_SERVER_PROBE_TIMEOUT_MS);
|
|
186
|
+
timer.unref?.();
|
|
187
|
+
});
|
|
188
|
+
try {
|
|
189
|
+
await Promise.race([
|
|
190
|
+
server.request("thread/read", { threadId: activeThreadId }),
|
|
191
|
+
deadline,
|
|
192
|
+
]);
|
|
193
|
+
}
|
|
194
|
+
catch (error) {
|
|
195
|
+
throw createProviderFailure(`${CODEX_APP_SERVER_PROVIDER} session transport probe failed`, {
|
|
196
|
+
code: "SUBAGENT_TRANSPORT_ERROR",
|
|
197
|
+
timeoutMs: CODEX_APP_SERVER_PROBE_TIMEOUT_MS,
|
|
198
|
+
cause: error,
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
finally {
|
|
202
|
+
if (timer)
|
|
203
|
+
clearTimeout(timer);
|
|
204
|
+
}
|
|
205
|
+
};
|
|
175
206
|
return createProjectionDriver({
|
|
176
207
|
steerMode: "mid-execution",
|
|
177
208
|
initialTurn: options.initialTurn,
|
|
178
209
|
enqueue,
|
|
210
|
+
probe,
|
|
179
211
|
onIngress: options.onIngress,
|
|
180
212
|
async abort(mode) {
|
|
181
213
|
interruptRequested = true;
|
|
@@ -22,6 +22,11 @@ export function codexAppServerNotificationDisposition(method, params) {
|
|
|
22
22
|
return "acknowledged-unpersisted";
|
|
23
23
|
if (CODEX_APP_SERVER_NOTIFICATION_MAPPED.has(method))
|
|
24
24
|
return "mapped";
|
|
25
|
+
if (method === "item/started") {
|
|
26
|
+
const item = appServerRecord(appServerRecord(params)?.item);
|
|
27
|
+
if (item && typeof item.type === "string" && isCodexAppServerActivityItemType(item.type))
|
|
28
|
+
return "mapped";
|
|
29
|
+
}
|
|
25
30
|
if (method === "account/rateLimits/updated" && codexAppServerRateLimitCause(params))
|
|
26
31
|
return "mapped";
|
|
27
32
|
return "unknown";
|
|
@@ -303,6 +308,24 @@ export function createCodexAppServerTurnMonitor(options) {
|
|
|
303
308
|
});
|
|
304
309
|
}
|
|
305
310
|
}
|
|
311
|
+
if (notification.method === "item/started") {
|
|
312
|
+
const item = notification.params?.item;
|
|
313
|
+
if (!item)
|
|
314
|
+
throw new Error(`${CODEX_APP_SERVER_PROVIDER} item/started lacked required item`);
|
|
315
|
+
const id = coerceString(item.id);
|
|
316
|
+
const itemType = coerceString(item.type);
|
|
317
|
+
if (!id || !itemType)
|
|
318
|
+
throw new Error(`${CODEX_APP_SERVER_PROVIDER} item/started lacked required item id or type`);
|
|
319
|
+
if (isCodexAppServerActivityItemType(itemType)) {
|
|
320
|
+
builder.emit({
|
|
321
|
+
type: "activity",
|
|
322
|
+
phase: "started",
|
|
323
|
+
id,
|
|
324
|
+
tool: itemType,
|
|
325
|
+
call: appServerActivityCall(itemType, item),
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
}
|
|
306
329
|
if (notification.method === "turn/started") {
|
|
307
330
|
const turn = notification.params?.turn;
|
|
308
331
|
const turnId = recordActiveTurnId(state, turn?.id, "notification");
|
|
@@ -142,14 +142,15 @@ function piUsageBody(event) {
|
|
|
142
142
|
if (message?.role !== "assistant")
|
|
143
143
|
return undefined;
|
|
144
144
|
const usage = message.usage;
|
|
145
|
-
if (!usage || typeof usage.input !== "number" ||
|
|
145
|
+
if (!usage || typeof usage.input !== "number" || !Number.isFinite(usage.input)
|
|
146
|
+
|| typeof usage.output !== "number" || !Number.isFinite(usage.output))
|
|
146
147
|
return undefined;
|
|
147
148
|
return {
|
|
148
149
|
type: "usage",
|
|
149
150
|
inputTokens: usage.input,
|
|
150
151
|
outputTokens: usage.output,
|
|
151
|
-
...(typeof usage.cacheRead === "number" ? { cachedInputTokens: usage.cacheRead } : {}),
|
|
152
|
-
...(typeof usage.cost?.total === "number" ? { costUsd: usage.cost.total } : {}),
|
|
152
|
+
...(typeof usage.cacheRead === "number" && Number.isFinite(usage.cacheRead) ? { cachedInputTokens: usage.cacheRead } : {}),
|
|
153
|
+
...(typeof usage.cost?.total === "number" && Number.isFinite(usage.cost.total) ? { costUsd: usage.cost.total } : {}),
|
|
153
154
|
...(typeof message.responseModel === "string"
|
|
154
155
|
? { model: message.responseModel }
|
|
155
156
|
: typeof message.model === "string"
|
package/build/agents/types.js
CHANGED
|
@@ -2,7 +2,7 @@ export const meta = {
|
|
|
2
2
|
command: "akuma ls",
|
|
3
3
|
summary: "List Akuma profiles",
|
|
4
4
|
usage: ["keiyaku akuma ls [-C|--cwd DIR] [--repo DIR]"],
|
|
5
|
-
stdin: "
|
|
5
|
+
stdin: { mode: "argument" },
|
|
6
6
|
flags: ["cwd", "repo"],
|
|
7
7
|
purpose: "List configured helper profiles.",
|
|
8
8
|
notes: ["Project profiles override user profiles, which override builtins."],
|
|
@@ -2,7 +2,7 @@ export const meta = {
|
|
|
2
2
|
command: "akuma view",
|
|
3
3
|
summary: "View one Akuma profile",
|
|
4
4
|
usage: ["keiyaku akuma view NAME [-C|--cwd DIR] [--repo DIR]"],
|
|
5
|
-
stdin: "
|
|
5
|
+
stdin: { mode: "argument" },
|
|
6
6
|
flags: ["cwd", "repo"],
|
|
7
7
|
purpose: "Read one configured helper profile and its current nonterminal projections.",
|
|
8
8
|
};
|
|
@@ -2,11 +2,11 @@ export const meta = {
|
|
|
2
2
|
command: "amend",
|
|
3
3
|
summary: "Record an amendment",
|
|
4
4
|
usage: [
|
|
5
|
-
"keiyaku amend [-C|--cwd DIR] [--repo DIR] [--contract ADDR] < amendment.md",
|
|
6
|
-
"keiyaku @addr amend [-C|--cwd DIR] [--repo DIR] < amendment.md",
|
|
5
|
+
"keiyaku amend [-C|--cwd DIR] [--repo DIR] [--contract ADDR] - < amendment.md",
|
|
6
|
+
"keiyaku @addr amend [-C|--cwd DIR] [--repo DIR] - < amendment.md",
|
|
7
7
|
],
|
|
8
|
-
stdin: "
|
|
8
|
+
stdin: { mode: "document", selector: { kind: "positional", index: 0, required: true, rejectBlank: true } },
|
|
9
9
|
flags: ["cwd", "repo", "contract"],
|
|
10
|
-
purpose: "Append a prose amendment and optional
|
|
10
|
+
purpose: "Append a prose amendment and optional Scope Append gitignore-pattern delta.",
|
|
11
11
|
completionRank: 8,
|
|
12
12
|
};
|
|
@@ -4,7 +4,7 @@ import { buildArcResponse } from "../../../render/arc.js";
|
|
|
4
4
|
import { renderCoreResult } from "../../../render/shared.js";
|
|
5
5
|
import { effectiveDirectory, repositoryDirectory } from "../../shared.js";
|
|
6
6
|
export const handler = async (stdin, flags) => {
|
|
7
|
-
const parsed = buildArcInput(stdin, effectiveDirectory(flags), flags.
|
|
7
|
+
const parsed = buildArcInput(stdin, effectiveDirectory(flags), flags.appendScope, flags.contractId, flags.contractAddressSource);
|
|
8
8
|
const cwd = await repositoryDirectory(flags, "arc");
|
|
9
9
|
const address = await resolveExistingContractAddress(cwd, flags.contractId, flags.contractAddressSource, effectiveDirectory(flags));
|
|
10
10
|
return renderCoreResult(arcKeiyaku({
|
|
@@ -2,11 +2,11 @@ export const meta = {
|
|
|
2
2
|
command: "arc",
|
|
3
3
|
summary: "Optional iteration; seals current intent first",
|
|
4
4
|
usage: [
|
|
5
|
-
"keiyaku arc [-C|--cwd DIR] [--repo DIR] [--contract ADDR] [--
|
|
6
|
-
"keiyaku @addr arc [-C|--cwd DIR] [--repo DIR] [--
|
|
5
|
+
"keiyaku arc [-C|--cwd DIR] [--repo DIR] [--contract ADDR] [--append-scope PATTERN] - < arc.md",
|
|
6
|
+
"keiyaku @addr arc [-C|--cwd DIR] [--repo DIR] [--append-scope PATTERN] - < arc.md",
|
|
7
7
|
],
|
|
8
|
-
stdin: "
|
|
9
|
-
flags: ["cwd", "repo", "contract", "
|
|
8
|
+
stdin: { mode: "document", selector: { kind: "positional", index: 0, required: true, rejectBlank: true } },
|
|
9
|
+
flags: ["cwd", "repo", "contract", "append-scope"],
|
|
10
10
|
purpose: "Optional iteration boundary: record the next title, objective, and brief, and seal the current intent first.",
|
|
11
11
|
input: [
|
|
12
12
|
"# <arc title>",
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { auditContract } from "../../../../core/audit.js";
|
|
2
|
+
import { resolveContractAddress, withResolvedAddress } from "../../../../core/addressing.js";
|
|
3
|
+
import { buildAuditConstructionFailure, buildAuditResponse } from "../../../render/audit.js";
|
|
4
|
+
import { effectiveDirectory, repositoryDirectory } from "../../shared.js";
|
|
5
|
+
export const handler = async (_stdin, flags) => {
|
|
6
|
+
try {
|
|
7
|
+
const cwd = await repositoryDirectory(flags, "audit");
|
|
8
|
+
const address = await resolveContractAddress(cwd, flags.contractId, flags.contractAddressSource, effectiveDirectory(flags));
|
|
9
|
+
return await withResolvedAddress(address, async () => {
|
|
10
|
+
return buildAuditResponse(await auditContract({ cwd, address, diffBudgetBytes: flags.auditDiffBudgetBytes }), flags.json === true);
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
catch (error) {
|
|
14
|
+
return buildAuditConstructionFailure(error, flags.json === true);
|
|
15
|
+
}
|
|
16
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export const meta = {
|
|
2
|
+
command: "audit",
|
|
3
|
+
summary: "Read settlement facts from one pinned delivery candidate",
|
|
4
|
+
usage: [
|
|
5
|
+
"keiyaku audit [-C|--cwd DIR] [--repo DIR] [--contract ADDR] [--diff-budget BYTES] [--json]",
|
|
6
|
+
"keiyaku @<id> audit [--diff-budget BYTES] [--json]",
|
|
7
|
+
],
|
|
8
|
+
stdin: { mode: "argument" },
|
|
9
|
+
flags: ["cwd", "repo", "contract", "diff-budget", "json"],
|
|
10
|
+
purpose: "Inspect one pinned delivery candidate, report settlement facts, and recheck its coordinates without mutating the source repository.",
|
|
11
|
+
notes: [
|
|
12
|
+
"Audit never invokes an Akuma or settles the contract.",
|
|
13
|
+
"Exit 0 means the report was constructed; exit 1 carries a typed construction cause.",
|
|
14
|
+
],
|
|
15
|
+
completionRank: 9,
|
|
16
|
+
};
|
|
@@ -2,14 +2,14 @@ export const meta = {
|
|
|
2
2
|
command: "bind",
|
|
3
3
|
summary: "Create a contract ledger and workspace files",
|
|
4
4
|
usage: [
|
|
5
|
-
"keiyaku bind [-C|--cwd DIR] [--repo DIR] [--task ID]...
|
|
5
|
+
"keiyaku bind [-C|--cwd DIR] [--repo DIR] [--task ID]... [- < contract.md]",
|
|
6
6
|
"keiyaku bind [-C|--cwd DIR] [--repo DIR] [--task ID]... --place NAME --objective TEXT --scope GLOB --checks CHECK [--dry-run]",
|
|
7
7
|
],
|
|
8
|
-
stdin: "
|
|
8
|
+
stdin: { mode: "document", selector: { kind: "positional", index: 0, required: false, rejectBlank: false } },
|
|
9
9
|
flags: ["cwd", "repo", "after", "exclusive", "draft-only", "place", "objective", "scope", "checks", "task", "dry-run"],
|
|
10
10
|
// contract is parseable only so the mouth can reject it with bind-specific copy.
|
|
11
11
|
parseFlags: ["cwd", "repo", "contract", "after", "exclusive", "draft-only", "place", "objective", "scope", "checks", "task", "dry-run"],
|
|
12
|
-
purpose: "Bind a Keiyaku from contract Markdown
|
|
12
|
+
purpose: "Bind a Keiyaku from contract Markdown selected by literal -.",
|
|
13
13
|
input: [
|
|
14
14
|
"# <name>",
|
|
15
15
|
"",
|
|
@@ -17,36 +17,45 @@ export const meta = {
|
|
|
17
17
|
"<what the commission should accomplish>",
|
|
18
18
|
"",
|
|
19
19
|
"## Scope",
|
|
20
|
-
"
|
|
20
|
+
"```",
|
|
21
|
+
"<pattern>",
|
|
22
|
+
"<another-pattern>",
|
|
23
|
+
"```",
|
|
21
24
|
"",
|
|
22
25
|
"## Checks",
|
|
23
26
|
"- <verification>",
|
|
24
27
|
],
|
|
25
28
|
notes: [
|
|
26
29
|
"bind creates a contract and does not accept @addr or --contract.",
|
|
27
|
-
"Primary form is
|
|
28
|
-
"With --task, title and body supply name/objective defaults;
|
|
29
|
-
"Domain flags remain available as a full-document alternative; they cannot mix with
|
|
30
|
+
"Primary document form is literal - followed by Markdown on stdin (full document below).",
|
|
31
|
+
"With --task, title and body supply name/objective defaults; literal - may send only the missing sections and any present section overrides the task default.",
|
|
32
|
+
"Domain flags remain available as a full-document alternative; they cannot mix with Markdown selected by literal -.",
|
|
30
33
|
],
|
|
31
34
|
examples: [
|
|
32
35
|
[
|
|
33
|
-
"keiyaku bind <<'KEIYAKU'",
|
|
36
|
+
"keiyaku bind - <<'KEIYAKU'",
|
|
34
37
|
"# <name>",
|
|
35
38
|
"",
|
|
36
39
|
"## Objective",
|
|
37
40
|
"<what the commission should accomplish>",
|
|
38
41
|
"",
|
|
39
42
|
"## Scope",
|
|
40
|
-
"
|
|
43
|
+
"```",
|
|
44
|
+
"<pattern>",
|
|
45
|
+
"<another-pattern>",
|
|
46
|
+
"```",
|
|
41
47
|
"",
|
|
42
48
|
"## Checks",
|
|
43
49
|
"- <verification>",
|
|
44
50
|
"KEIYAKU",
|
|
45
51
|
].join("\n"),
|
|
46
52
|
[
|
|
47
|
-
"keiyaku bind --task fix-flaky-pump <<'KEIYAKU'",
|
|
53
|
+
"keiyaku bind --task fix-flaky-pump - <<'KEIYAKU'",
|
|
48
54
|
"## Scope",
|
|
49
|
-
"
|
|
55
|
+
"```",
|
|
56
|
+
"<pattern>",
|
|
57
|
+
"<another-pattern>",
|
|
58
|
+
"```",
|
|
50
59
|
"",
|
|
51
60
|
"## Checks",
|
|
52
61
|
"- <verification>",
|
|
@@ -2,6 +2,7 @@ import { meta as bindMeta } from "./bind/meta.js";
|
|
|
2
2
|
import { meta as arcMeta } from "./arc/meta.js";
|
|
3
3
|
import { meta as logMeta } from "./log/meta.js";
|
|
4
4
|
import { meta as amendMeta } from "./amend/meta.js";
|
|
5
|
+
import { meta as auditMeta } from "./audit/meta.js";
|
|
5
6
|
import { meta as renewMeta } from "./renew/meta.js";
|
|
6
7
|
import { meta as petitionMeta } from "./petition/meta.js";
|
|
7
8
|
import { meta as forfeitMeta } from "./forfeit/meta.js";
|
|
@@ -10,6 +11,7 @@ export const contractCatalog = [
|
|
|
10
11
|
{ meta: arcMeta, load: () => import("./arc/handler.js") },
|
|
11
12
|
{ meta: logMeta, load: () => import("./log/handler.js") },
|
|
12
13
|
{ meta: amendMeta, load: () => import("./amend/handler.js") },
|
|
14
|
+
{ meta: auditMeta, load: () => import("./audit/handler.js") },
|
|
13
15
|
{ meta: renewMeta, load: () => import("./renew/handler.js") },
|
|
14
16
|
{ meta: petitionMeta, load: () => import("./petition/handler.js") },
|
|
15
17
|
{ meta: forfeitMeta, load: () => import("./forfeit/handler.js") },
|