harness-engineering-agent 0.1.7 → 0.1.9
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 +161 -62
- package/dist/agent/harness-agent-capabilities.d.ts +4 -0
- package/dist/agent/harness-agent-capabilities.d.ts.map +1 -0
- package/dist/agent/harness-agent-capabilities.js +4 -0
- package/dist/agent/harness-agent-capabilities.js.map +1 -0
- package/dist/agent/harness-agent-capability-builders.d.ts +11 -0
- package/dist/agent/harness-agent-capability-builders.d.ts.map +1 -0
- package/dist/agent/harness-agent-capability-builders.js +57 -0
- package/dist/agent/harness-agent-capability-builders.js.map +1 -0
- package/dist/agent/harness-agent-capability-data.d.ts +3 -0
- package/dist/agent/harness-agent-capability-data.d.ts.map +1 -0
- package/dist/agent/harness-agent-capability-data.js +23 -0
- package/dist/agent/harness-agent-capability-data.js.map +1 -0
- package/dist/agent/harness-agent-capability-types.d.ts +50 -0
- package/dist/agent/harness-agent-capability-types.d.ts.map +1 -0
- package/dist/agent/harness-agent-capability-types.js +3 -0
- package/dist/agent/harness-agent-capability-types.js.map +1 -0
- package/dist/agent/harness-role-capability-directory-data.d.ts +3 -0
- package/dist/agent/harness-role-capability-directory-data.d.ts.map +1 -0
- package/dist/agent/harness-role-capability-directory-data.js +208 -0
- package/dist/agent/harness-role-capability-directory-data.js.map +1 -0
- package/dist/agent/harness-role-capability-directory.d.ts +43 -0
- package/dist/agent/harness-role-capability-directory.d.ts.map +1 -0
- package/dist/agent/harness-role-capability-directory.js +57 -0
- package/dist/agent/harness-role-capability-directory.js.map +1 -0
- package/dist/agent/index.d.ts +7 -0
- package/dist/agent/index.d.ts.map +1 -0
- package/dist/agent/index.js +6 -0
- package/dist/agent/index.js.map +1 -0
- package/dist/config/config-defaults.d.ts +22 -0
- package/dist/config/config-defaults.d.ts.map +1 -1
- package/dist/config/config-defaults.js +22 -0
- package/dist/config/config-defaults.js.map +1 -1
- package/dist/config/config-merge.d.ts.map +1 -1
- package/dist/config/config-merge.js +30 -0
- package/dist/config/config-merge.js.map +1 -1
- package/dist/config/config-schema.d.ts +59 -0
- package/dist/config/config-schema.d.ts.map +1 -1
- package/dist/config/config-schema.js +18 -1
- package/dist/config/config-schema.js.map +1 -1
- package/dist/config/config-types.d.ts +5 -1
- package/dist/config/config-types.d.ts.map +1 -1
- package/dist/config/harness-config.d.ts +2 -1
- package/dist/config/harness-config.d.ts.map +1 -1
- package/dist/config/harness-config.js +1 -0
- package/dist/config/harness-config.js.map +1 -1
- package/dist/config/index.d.ts +1 -1
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js.map +1 -1
- package/dist/config/opencode-compatibility.d.ts +37 -0
- package/dist/config/opencode-compatibility.d.ts.map +1 -0
- package/dist/config/opencode-compatibility.js +99 -0
- package/dist/config/opencode-compatibility.js.map +1 -0
- package/dist/controller/agent-output.d.ts +1 -1
- package/dist/controller/agent-output.d.ts.map +1 -1
- package/dist/controller/agent-output.js +18 -1
- package/dist/controller/agent-output.js.map +1 -1
- package/dist/controller/agent-session-types.d.ts +56 -0
- package/dist/controller/agent-session-types.d.ts.map +1 -0
- package/dist/controller/agent-session-types.js +2 -0
- package/dist/controller/agent-session-types.js.map +1 -0
- package/dist/controller/agent-session-utils.d.ts +52 -0
- package/dist/controller/agent-session-utils.d.ts.map +1 -0
- package/dist/controller/agent-session-utils.js +118 -0
- package/dist/controller/agent-session-utils.js.map +1 -0
- package/dist/controller/agent-session.d.ts +2 -40
- package/dist/controller/agent-session.d.ts.map +1 -1
- package/dist/controller/agent-session.js +126 -128
- package/dist/controller/agent-session.js.map +1 -1
- package/dist/controller/contracts.d.ts +4 -2
- package/dist/controller/contracts.d.ts.map +1 -1
- package/dist/controller/contracts.js.map +1 -1
- package/dist/controller/errors.d.ts +5 -0
- package/dist/controller/errors.d.ts.map +1 -1
- package/dist/controller/errors.js +8 -0
- package/dist/controller/errors.js.map +1 -1
- package/dist/controller/evidence-factory.js +7 -1
- package/dist/controller/evidence-factory.js.map +1 -1
- package/dist/controller/failure-analysis.d.ts +12 -0
- package/dist/controller/failure-analysis.d.ts.map +1 -1
- package/dist/controller/failure-analysis.js +41 -0
- package/dist/controller/failure-analysis.js.map +1 -1
- package/dist/controller/failure-analyzer-schemas.d.ts +87 -0
- package/dist/controller/failure-analyzer-schemas.d.ts.map +1 -0
- package/dist/controller/failure-analyzer-schemas.js +117 -0
- package/dist/controller/failure-analyzer-schemas.js.map +1 -0
- package/dist/controller/graph-validator.js +18 -4
- package/dist/controller/graph-validator.js.map +1 -1
- package/dist/controller/index.d.ts +7 -2
- package/dist/controller/index.d.ts.map +1 -1
- package/dist/controller/index.js +4 -1
- package/dist/controller/index.js.map +1 -1
- package/dist/controller/repair-loop.d.ts +1 -1
- package/dist/controller/repair-loop.d.ts.map +1 -1
- package/dist/controller/repair-loop.js +28 -0
- package/dist/controller/repair-loop.js.map +1 -1
- package/dist/controller/report-factory.d.ts.map +1 -1
- package/dist/controller/report-factory.js +49 -21
- package/dist/controller/report-factory.js.map +1 -1
- package/dist/controller/role-prompts.d.ts +2 -1
- package/dist/controller/role-prompts.d.ts.map +1 -1
- package/dist/controller/role-prompts.js +3 -9
- package/dist/controller/role-prompts.js.map +1 -1
- package/dist/controller/run-acceptance.d.ts +17 -0
- package/dist/controller/run-acceptance.d.ts.map +1 -0
- package/dist/controller/run-acceptance.js +179 -0
- package/dist/controller/run-acceptance.js.map +1 -0
- package/dist/controller/run-controller.d.ts.map +1 -1
- package/dist/controller/run-controller.js +379 -96
- package/dist/controller/run-controller.js.map +1 -1
- package/dist/controller/run-state.d.ts +1 -0
- package/dist/controller/run-state.d.ts.map +1 -1
- package/dist/controller/run-state.js +12 -0
- package/dist/controller/run-state.js.map +1 -1
- package/dist/controller/session-tool-authorization.d.ts +14 -0
- package/dist/controller/session-tool-authorization.d.ts.map +1 -0
- package/dist/controller/session-tool-authorization.js +88 -0
- package/dist/controller/session-tool-authorization.js.map +1 -0
- package/dist/controller/task-agent-output.d.ts +13 -2
- package/dist/controller/task-agent-output.d.ts.map +1 -1
- package/dist/controller/task-agent-output.js +58 -1
- package/dist/controller/task-agent-output.js.map +1 -1
- package/dist/controller/task-agent-schemas.d.ts +745 -26
- package/dist/controller/task-agent-schemas.d.ts.map +1 -1
- package/dist/controller/task-agent-schemas.js +70 -21
- package/dist/controller/task-agent-schemas.js.map +1 -1
- package/dist/controller/task-executor.d.ts +2 -1
- package/dist/controller/task-executor.d.ts.map +1 -1
- package/dist/controller/task-executor.js +304 -105
- package/dist/controller/task-executor.js.map +1 -1
- package/dist/doctor/cli.d.ts +3 -0
- package/dist/doctor/cli.d.ts.map +1 -0
- package/dist/doctor/cli.js +10 -0
- package/dist/doctor/cli.js.map +1 -0
- package/dist/doctor/index.d.ts +7 -0
- package/dist/doctor/index.d.ts.map +1 -0
- package/dist/doctor/index.js +16 -0
- package/dist/doctor/index.js.map +1 -0
- package/dist/doctor/local-mcp-probe.d.ts +3 -0
- package/dist/doctor/local-mcp-probe.d.ts.map +1 -0
- package/dist/doctor/local-mcp-probe.js +151 -0
- package/dist/doctor/local-mcp-probe.js.map +1 -0
- package/dist/doctor/opencode-config.d.ts +43 -0
- package/dist/doctor/opencode-config.d.ts.map +1 -0
- package/dist/doctor/opencode-config.js +103 -0
- package/dist/doctor/opencode-config.js.map +1 -0
- package/dist/doctor/run-harness-doctor.d.ts +23 -0
- package/dist/doctor/run-harness-doctor.d.ts.map +1 -0
- package/dist/doctor/run-harness-doctor.js +176 -0
- package/dist/doctor/run-harness-doctor.js.map +1 -0
- package/dist/doctor/types.d.ts +69 -0
- package/dist/doctor/types.d.ts.map +1 -0
- package/dist/doctor/types.js +8 -0
- package/dist/doctor/types.js.map +1 -0
- package/dist/domain/acceptance-criteria.d.ts +9 -0
- package/dist/domain/acceptance-criteria.d.ts.map +1 -0
- package/dist/domain/acceptance-criteria.js +38 -0
- package/dist/domain/acceptance-criteria.js.map +1 -0
- package/dist/domain/context-package.d.ts +43 -0
- package/dist/domain/context-package.d.ts.map +1 -0
- package/dist/domain/context-package.js +54 -0
- package/dist/domain/context-package.js.map +1 -0
- package/dist/domain/evidence.d.ts +1 -0
- package/dist/domain/evidence.d.ts.map +1 -1
- package/dist/domain/evidence.js +1 -2
- package/dist/domain/evidence.js.map +1 -1
- package/dist/domain/index.d.ts +12 -4
- package/dist/domain/index.d.ts.map +1 -1
- package/dist/domain/index.js +6 -2
- package/dist/domain/index.js.map +1 -1
- package/dist/domain/plan-artifacts.d.ts +170 -0
- package/dist/domain/plan-artifacts.d.ts.map +1 -0
- package/dist/domain/plan-artifacts.js +187 -0
- package/dist/domain/plan-artifacts.js.map +1 -0
- package/dist/domain/report.d.ts +608 -11
- package/dist/domain/report.d.ts.map +1 -1
- package/dist/domain/report.js +6 -4
- package/dist/domain/report.js.map +1 -1
- package/dist/domain/requirement.d.ts +22 -2
- package/dist/domain/requirement.d.ts.map +1 -1
- package/dist/domain/requirement.js +26 -3
- package/dist/domain/requirement.js.map +1 -1
- package/dist/domain/run-acceptance.d.ts +33 -0
- package/dist/domain/run-acceptance.d.ts.map +1 -0
- package/dist/domain/run-acceptance.js +29 -0
- package/dist/domain/run-acceptance.js.map +1 -0
- package/dist/domain/run.d.ts +596 -7
- package/dist/domain/run.d.ts.map +1 -1
- package/dist/domain/run.js +58 -0
- package/dist/domain/run.js.map +1 -1
- package/dist/domain/shared.d.ts +40 -2
- package/dist/domain/shared.d.ts.map +1 -1
- package/dist/domain/shared.js +26 -0
- package/dist/domain/shared.js.map +1 -1
- package/dist/domain/task-review.d.ts +57 -0
- package/dist/domain/task-review.d.ts.map +1 -0
- package/dist/domain/task-review.js +63 -0
- package/dist/domain/task-review.js.map +1 -0
- package/dist/domain/task.d.ts +24 -2
- package/dist/domain/task.d.ts.map +1 -1
- package/dist/domain/task.js +20 -12
- package/dist/domain/task.js.map +1 -1
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/plugin/create-harness-plugin.d.ts +4 -28
- package/dist/plugin/create-harness-plugin.d.ts.map +1 -1
- package/dist/plugin/create-harness-plugin.js +33 -118
- package/dist/plugin/create-harness-plugin.js.map +1 -1
- package/dist/plugin/harness-agent-config.d.ts +7 -0
- package/dist/plugin/harness-agent-config.d.ts.map +1 -1
- package/dist/plugin/harness-agent-config.js +72 -118
- package/dist/plugin/harness-agent-config.js.map +1 -1
- package/dist/plugin/harness-chat-hook.d.ts +1 -1
- package/dist/plugin/harness-chat-hook.d.ts.map +1 -1
- package/dist/plugin/harness-chat-hook.js +15 -23
- package/dist/plugin/harness-chat-hook.js.map +1 -1
- package/dist/plugin/harness-chat-protocol.d.ts +2 -2
- package/dist/plugin/harness-chat-protocol.d.ts.map +1 -1
- package/dist/plugin/harness-chat-protocol.js +13 -2
- package/dist/plugin/harness-chat-protocol.js.map +1 -1
- package/dist/plugin/harness-coordinator.d.ts +4 -0
- package/dist/plugin/harness-coordinator.d.ts.map +1 -1
- package/dist/plugin/harness-coordinator.js +7 -1
- package/dist/plugin/harness-coordinator.js.map +1 -1
- package/dist/plugin/harness-plugin-identifiers.d.ts +5 -0
- package/dist/plugin/harness-plugin-identifiers.d.ts.map +1 -0
- package/dist/plugin/harness-plugin-identifiers.js +24 -0
- package/dist/plugin/harness-plugin-identifiers.js.map +1 -0
- package/dist/plugin/harness-plugin-runtime.d.ts +64 -0
- package/dist/plugin/harness-plugin-runtime.d.ts.map +1 -0
- package/dist/plugin/harness-plugin-runtime.js +125 -0
- package/dist/plugin/harness-plugin-runtime.js.map +1 -0
- package/dist/plugin/harness-plugin-scheduler.d.ts +16 -0
- package/dist/plugin/harness-plugin-scheduler.d.ts.map +1 -0
- package/dist/plugin/harness-plugin-scheduler.js +51 -0
- package/dist/plugin/harness-plugin-scheduler.js.map +1 -0
- package/dist/plugin/harness-request-router.d.ts.map +1 -1
- package/dist/plugin/harness-request-router.js +14 -23
- package/dist/plugin/harness-request-router.js.map +1 -1
- package/dist/plugin/harness-requirement.d.ts +1 -1
- package/dist/plugin/harness-requirement.d.ts.map +1 -1
- package/dist/plugin/harness-requirement.js +2 -3
- package/dist/plugin/harness-requirement.js.map +1 -1
- package/dist/session/contracts.d.ts +9 -0
- package/dist/session/contracts.d.ts.map +1 -1
- package/dist/session/contracts.js.map +1 -1
- package/dist/session/fake-session-adapter.d.ts.map +1 -1
- package/dist/session/fake-session-adapter.js +1 -0
- package/dist/session/fake-session-adapter.js.map +1 -1
- package/dist/session/index.d.ts +1 -1
- package/dist/session/index.d.ts.map +1 -1
- package/dist/session/index.js.map +1 -1
- package/dist/session/opencode-session-adapter.d.ts +2 -1
- package/dist/session/opencode-session-adapter.d.ts.map +1 -1
- package/dist/session/opencode-session-adapter.js +7 -2
- package/dist/session/opencode-session-adapter.js.map +1 -1
- package/dist/session/opencode-session-prompts.d.ts +2 -10
- package/dist/session/opencode-session-prompts.d.ts.map +1 -1
- package/dist/session/opencode-session-prompts.js +7 -9
- package/dist/session/opencode-session-prompts.js.map +1 -1
- package/dist/store/run-event.d.ts +596 -7
- package/dist/store/run-event.d.ts.map +1 -1
- package/dist/tools/harness-research-tools.d.ts +22 -0
- package/dist/tools/harness-research-tools.d.ts.map +1 -1
- package/dist/tools/harness-research-tools.js +173 -64
- package/dist/tools/harness-research-tools.js.map +1 -1
- package/dist/tools/harness-tool-capabilities.d.ts +342 -0
- package/dist/tools/harness-tool-capabilities.d.ts.map +1 -0
- package/dist/tools/harness-tool-capabilities.js +170 -0
- package/dist/tools/harness-tool-capabilities.js.map +1 -0
- package/dist/verification/command-policy.d.ts.map +1 -1
- package/dist/verification/command-policy.js +2 -2
- package/dist/verification/command-policy.js.map +1 -1
- package/package.json +6 -1
|
@@ -1,15 +1,36 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { PlanReviewSchema, RequirementSchema, RunSchema, SchemaVersionSchema, TaskGraphSchema, } from "../domain/index.js";
|
|
2
3
|
import { HARNESS_SESSION_ROLE } from "../session/index.js";
|
|
3
4
|
import { createGitWorkspaceAdapter } from "../workspace/index.js";
|
|
4
5
|
import { parseAgentJson } from "./agent-output.js";
|
|
5
6
|
import { createAgentSessionRuntime } from "./agent-session.js";
|
|
6
|
-
import { AgentOutputParseError, AgentRunFailedError, GraphValidationError, RunCancellationError, } from "./errors.js";
|
|
7
|
+
import { AgentOutputParseError, AgentRunFailedError, GraphValidationError, RunCancellationError, RunPausedError, } from "./errors.js";
|
|
7
8
|
import { validateTaskGraph } from "./graph-validator.js";
|
|
8
9
|
import { createReport } from "./report-factory.js";
|
|
9
10
|
import { plannerTaskPrompt } from "./role-prompts.js";
|
|
10
11
|
import { createRunPersistence } from "./run-persistence.js";
|
|
11
|
-
import { appendAnswer, appendWaiver, canAnswer, canCancel, canPause, canWaive, consumeBudget, createBlockedQuestionId, createInitialRunBudgets, createInitialRunGovernance, hasAnswer, hasWaiver, isTerminalRunStatus, parsePlannedRun, RunBudgetExceededError, requireTransition, requireWaivableRequirement, setPaused, withGovernance, withStatus, } from "./run-state.js";
|
|
12
|
+
import { appendAnswer, appendWaiver, canAdvanceRun, canAnswer, canCancel, canPause, canWaive, consumeBudget, createBlockedQuestionId, createInitialRunBudgets, createInitialRunGovernance, hasAnswer, hasWaiver, isTerminalRunStatus, parsePlannedRun, RunBudgetExceededError, requireTransition, requireWaivableRequirement, setPaused, withGovernance, withStatus, } from "./run-state.js";
|
|
13
|
+
import { PlannerContextOutputSchema } from "./task-agent-schemas.js";
|
|
12
14
|
import { createTaskExecutor } from "./task-executor.js";
|
|
15
|
+
const PlanReviewVerifierOutputSchema = z
|
|
16
|
+
.object({
|
|
17
|
+
schemaVersion: SchemaVersionSchema,
|
|
18
|
+
role: z.literal("verifier"),
|
|
19
|
+
status: z.enum(["approved", "rejected"]),
|
|
20
|
+
summary: z.string().trim().min(1),
|
|
21
|
+
evidenceIds: z.array(z.string().trim().min(1)).readonly(),
|
|
22
|
+
planReview: PlanReviewSchema,
|
|
23
|
+
})
|
|
24
|
+
.strict()
|
|
25
|
+
.readonly();
|
|
26
|
+
class PlanningBlockedError extends Error {
|
|
27
|
+
run;
|
|
28
|
+
name = "PlanningBlockedError";
|
|
29
|
+
constructor(run) {
|
|
30
|
+
super(`planning blocked: ${run.status}`);
|
|
31
|
+
this.run = run;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
13
34
|
export const createRunController = (options) => {
|
|
14
35
|
const workspacePolicy = options.workspacePolicy ?? { allowDirty: false };
|
|
15
36
|
const workspaceAdapter = options.workspaceAdapter ?? createGitWorkspaceAdapter(options.workingDirectory);
|
|
@@ -20,11 +41,188 @@ export const createRunController = (options) => {
|
|
|
20
41
|
store: options.store,
|
|
21
42
|
workingDirectory: options.workingDirectory,
|
|
22
43
|
});
|
|
44
|
+
const loadRunWithRetry = async (runId) => {
|
|
45
|
+
for (let attempt = 0; attempt < 3; attempt += 1) {
|
|
46
|
+
try {
|
|
47
|
+
return await options.store.loadState(runId);
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
if (!isMissingRunError(error, runId) || attempt === 2) {
|
|
51
|
+
throw error;
|
|
52
|
+
}
|
|
53
|
+
await waitForNextTurn();
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
throw new TypeError(`missing run ${runId}`);
|
|
57
|
+
};
|
|
23
58
|
const { runTasks } = createTaskExecutor({
|
|
24
59
|
options,
|
|
25
60
|
runtime,
|
|
26
61
|
writer,
|
|
62
|
+
loadRun: loadRunWithRetry,
|
|
27
63
|
});
|
|
64
|
+
const advancingRuns = new Map();
|
|
65
|
+
const persistPlanBlockedState = async (input) => {
|
|
66
|
+
const nextRun = withStatus(withGovernance(input.run, {
|
|
67
|
+
...input.run.governance,
|
|
68
|
+
blockingQuestionId: input.status === "clarification_required" ? createBlockedQuestionId(input.run) : null,
|
|
69
|
+
}), input.status);
|
|
70
|
+
await writer.persist(nextRun, writer.createEvent(input.run.runId, input.eventType, {
|
|
71
|
+
reason: input.reason,
|
|
72
|
+
...(input.status === "clarification_required"
|
|
73
|
+
? { blockingQuestionId: nextRun.governance.blockingQuestionId }
|
|
74
|
+
: {}),
|
|
75
|
+
...input.payload,
|
|
76
|
+
}));
|
|
77
|
+
return nextRun;
|
|
78
|
+
};
|
|
79
|
+
const requestContextPackage = async (run, requirement) => {
|
|
80
|
+
const outputText = await runtime.sendAgent({
|
|
81
|
+
runId: run.runId,
|
|
82
|
+
role: HARNESS_SESSION_ROLE.planner,
|
|
83
|
+
title: `${requirement.title} context`,
|
|
84
|
+
brief: JSON.stringify({ requirement, runId: run.runId }),
|
|
85
|
+
constraints: [
|
|
86
|
+
"先输出可审计 ContextPackage。",
|
|
87
|
+
"上下文不足时只能返回 evidence_gap 或 clarification_required。",
|
|
88
|
+
"不要生成 TaskGraph,不要推进状态。",
|
|
89
|
+
],
|
|
90
|
+
evidence: [],
|
|
91
|
+
outputContract: {
|
|
92
|
+
schemaVersion: "1.0.0",
|
|
93
|
+
type: "PlannerContextOutput",
|
|
94
|
+
requiredFields: ["schemaVersion", "role", "status"],
|
|
95
|
+
},
|
|
96
|
+
systemPrompt: "你是 Fuxi。先输出 PlannerContextOutput JSON。",
|
|
97
|
+
messageLabel: `planner-context-${run.runId}`,
|
|
98
|
+
});
|
|
99
|
+
const output = parseAgentJson(outputText, PlannerContextOutputSchema, "planner");
|
|
100
|
+
switch (output.status) {
|
|
101
|
+
case "completed":
|
|
102
|
+
return { kind: "completed", contextPackage: output.contextPackage };
|
|
103
|
+
case "clarification_required":
|
|
104
|
+
return {
|
|
105
|
+
kind: "blocked",
|
|
106
|
+
run: await persistPlanBlockedState({
|
|
107
|
+
run,
|
|
108
|
+
status: "clarification_required",
|
|
109
|
+
reason: output.summary,
|
|
110
|
+
eventType: "run.planning.context_gap",
|
|
111
|
+
payload: { missingContext: output.missingContext },
|
|
112
|
+
}),
|
|
113
|
+
};
|
|
114
|
+
case "evidence_gap":
|
|
115
|
+
return {
|
|
116
|
+
kind: "blocked",
|
|
117
|
+
run: await persistPlanBlockedState({
|
|
118
|
+
run,
|
|
119
|
+
status: "evidence_gap",
|
|
120
|
+
reason: output.summary,
|
|
121
|
+
eventType: "run.planning.context_gap",
|
|
122
|
+
payload: { missingContext: output.missingContext },
|
|
123
|
+
}),
|
|
124
|
+
};
|
|
125
|
+
default:
|
|
126
|
+
return assertNever(output);
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
const requestTaskGraph = async (input) => {
|
|
130
|
+
const output = await runtime.sendAgent({
|
|
131
|
+
runId: input.run.runId,
|
|
132
|
+
role: HARNESS_SESSION_ROLE.planner,
|
|
133
|
+
title: input.requirement.title,
|
|
134
|
+
brief: plannerTaskPrompt({
|
|
135
|
+
requirement: input.requirement,
|
|
136
|
+
runId: input.run.runId,
|
|
137
|
+
contextPackage: input.contextPackage,
|
|
138
|
+
}),
|
|
139
|
+
constraints: [
|
|
140
|
+
"只允许根据 requirement 和 contextPackage 生成任务图。",
|
|
141
|
+
"不得执行任务或请求父会话完整历史。",
|
|
142
|
+
"只输出符合 TaskGraph 契约的 JSON。",
|
|
143
|
+
],
|
|
144
|
+
evidence: [
|
|
145
|
+
{
|
|
146
|
+
refId: input.contextPackage.contextPackageId,
|
|
147
|
+
kind: "artifact",
|
|
148
|
+
summary: input.contextPackage.summary,
|
|
149
|
+
},
|
|
150
|
+
],
|
|
151
|
+
outputContract: {
|
|
152
|
+
schemaVersion: "1.0.0",
|
|
153
|
+
type: "TaskGraph",
|
|
154
|
+
requiredFields: ["schemaVersion", "graphId", "runId", "version", "tasks", "edges"],
|
|
155
|
+
},
|
|
156
|
+
systemPrompt: "你是 Fuxi。使用已持久化的 ContextPackage 生成 TaskGraph JSON。",
|
|
157
|
+
messageLabel: `planner-graph-${input.run.runId}`,
|
|
158
|
+
});
|
|
159
|
+
return parsePlannerGraph(output);
|
|
160
|
+
};
|
|
161
|
+
const persistPlanningArtifacts = async (input) => {
|
|
162
|
+
const nextRun = RunSchema.parse({
|
|
163
|
+
...input.run,
|
|
164
|
+
...(input.contextPackage === undefined ? {} : { contextPackage: input.contextPackage }),
|
|
165
|
+
...(input.planReview === undefined ? {} : { planReview: input.planReview }),
|
|
166
|
+
...(input.taskGraph === undefined
|
|
167
|
+
? {}
|
|
168
|
+
: { taskGraph: input.taskGraph, status: "plan_ready" }),
|
|
169
|
+
});
|
|
170
|
+
await writer.persist(nextRun, writer.createEvent(input.run.runId, input.eventType, input.payload));
|
|
171
|
+
return nextRun;
|
|
172
|
+
};
|
|
173
|
+
const requestPlanReview = async (input) => {
|
|
174
|
+
const outputText = await runtime.sendAgent({
|
|
175
|
+
runId: input.run.runId,
|
|
176
|
+
role: HARNESS_SESSION_ROLE.verifier,
|
|
177
|
+
title: `Review ${input.requirement.title}`,
|
|
178
|
+
brief: JSON.stringify({
|
|
179
|
+
requirement: input.requirement,
|
|
180
|
+
contextPackage: input.contextPackage,
|
|
181
|
+
taskGraph: input.taskGraph,
|
|
182
|
+
}),
|
|
183
|
+
constraints: [
|
|
184
|
+
"独立审查每个 criterion/path/dependency/verification/category。",
|
|
185
|
+
"只输出包含完整 PlanReview 的 VerifierOutput JSON。",
|
|
186
|
+
"计划未覆盖 criterionId、未知类别、非法路径或不可执行验证时必须 rejected。",
|
|
187
|
+
],
|
|
188
|
+
evidence: [
|
|
189
|
+
{
|
|
190
|
+
refId: input.contextPackage.contextPackageId,
|
|
191
|
+
kind: "artifact",
|
|
192
|
+
summary: input.contextPackage.summary,
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
refId: input.taskGraph.graphId,
|
|
196
|
+
kind: "artifact",
|
|
197
|
+
summary: `Task graph ${input.taskGraph.graphId}`,
|
|
198
|
+
},
|
|
199
|
+
],
|
|
200
|
+
outputContract: {
|
|
201
|
+
schemaVersion: "1.0.0",
|
|
202
|
+
type: "VerifierOutput",
|
|
203
|
+
requiredFields: ["schemaVersion", "role", "status", "summary", "evidenceIds", "planReview"],
|
|
204
|
+
},
|
|
205
|
+
systemPrompt: "你是 Zhulong。只输出 PlanReview 版 VerifierOutput JSON。",
|
|
206
|
+
messageLabel: `plan-review-${input.run.runId}`,
|
|
207
|
+
});
|
|
208
|
+
const output = PlanReviewVerifierOutputSchema.parse(JSON.parse(outputText));
|
|
209
|
+
if (output.status !== "approved") {
|
|
210
|
+
throw new GraphValidationError(output.planReview.findings.map((finding) => finding.message).length === 0
|
|
211
|
+
? [output.summary]
|
|
212
|
+
: output.planReview.findings.map((finding) => finding.message));
|
|
213
|
+
}
|
|
214
|
+
return output.planReview;
|
|
215
|
+
};
|
|
216
|
+
const ensureExecutionCategoriesConfigured = (graph) => {
|
|
217
|
+
const missingCategories = graph.tasks
|
|
218
|
+
.map((task) => task.executionCategory)
|
|
219
|
+
.filter((category) => options.executionCategories?.[category] === undefined);
|
|
220
|
+
if (missingCategories.length > 0) {
|
|
221
|
+
throw new GraphValidationError([
|
|
222
|
+
`Unsupported executionCategory mappings: ${[...new Set(missingCategories)].join(", ")}`,
|
|
223
|
+
]);
|
|
224
|
+
}
|
|
225
|
+
};
|
|
28
226
|
const requestPlan = async (run, requirement) => {
|
|
29
227
|
const maxPlannerAttempts = run.budgets.planner.limit;
|
|
30
228
|
let planningRun = run;
|
|
@@ -33,28 +231,54 @@ export const createRunController = (options) => {
|
|
|
33
231
|
try {
|
|
34
232
|
planningRun = consumeBudget(planningRun, "planner");
|
|
35
233
|
planningRun = consumeBudget(planningRun, "overall");
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
outputContract: {
|
|
48
|
-
schemaVersion: "1.0.0",
|
|
49
|
-
type: "TaskGraph",
|
|
50
|
-
requiredFields: ["schemaVersion", "graphId", "runId", "version", "tasks", "edges"],
|
|
234
|
+
const contextResult = await requestContextPackage(planningRun, requirement);
|
|
235
|
+
if (contextResult.kind === "blocked") {
|
|
236
|
+
throw new PlanningBlockedError(contextResult.run);
|
|
237
|
+
}
|
|
238
|
+
planningRun = await persistPlanningArtifacts({
|
|
239
|
+
run: planningRun,
|
|
240
|
+
contextPackage: contextResult.contextPackage,
|
|
241
|
+
eventType: "run.planning.context_captured",
|
|
242
|
+
payload: {
|
|
243
|
+
contextPackageId: contextResult.contextPackage.contextPackageId,
|
|
244
|
+
requirementId: contextResult.contextPackage.requirementId,
|
|
51
245
|
},
|
|
52
|
-
messageLabel: `planner-${planningRun.runId}-${attempt}`,
|
|
53
246
|
});
|
|
54
|
-
|
|
247
|
+
const taskGraph = await requestTaskGraph({
|
|
248
|
+
run: planningRun,
|
|
249
|
+
requirement,
|
|
250
|
+
contextPackage: contextResult.contextPackage,
|
|
251
|
+
});
|
|
252
|
+
validateTaskGraph(taskGraph, requirement, run.runId);
|
|
253
|
+
ensureExecutionCategoriesConfigured(taskGraph);
|
|
254
|
+
const planReview = await requestPlanReview({
|
|
255
|
+
run: planningRun,
|
|
256
|
+
requirement,
|
|
257
|
+
contextPackage: contextResult.contextPackage,
|
|
258
|
+
taskGraph,
|
|
259
|
+
});
|
|
260
|
+
planningRun = await persistPlanningArtifacts({
|
|
261
|
+
run: planningRun,
|
|
262
|
+
contextPackage: contextResult.contextPackage,
|
|
263
|
+
taskGraph,
|
|
264
|
+
planReview,
|
|
265
|
+
eventType: "run.planning.plan_review_approved",
|
|
266
|
+
payload: {
|
|
267
|
+
graphId: taskGraph.graphId,
|
|
268
|
+
reviewId: planReview.reviewId,
|
|
269
|
+
},
|
|
270
|
+
});
|
|
271
|
+
return {
|
|
272
|
+
contextPackage: contextResult.contextPackage,
|
|
273
|
+
taskGraph,
|
|
274
|
+
planReview,
|
|
275
|
+
};
|
|
55
276
|
}
|
|
56
277
|
catch (error) {
|
|
57
|
-
if (error instanceof RunBudgetExceededError) {
|
|
278
|
+
if (error instanceof RunBudgetExceededError || error instanceof RunCancellationError) {
|
|
279
|
+
throw error;
|
|
280
|
+
}
|
|
281
|
+
if (error instanceof PlanningBlockedError) {
|
|
58
282
|
throw error;
|
|
59
283
|
}
|
|
60
284
|
if (!(error instanceof AgentRunFailedError || error instanceof AgentOutputParseError)) {
|
|
@@ -72,21 +296,124 @@ export const createRunController = (options) => {
|
|
|
72
296
|
}
|
|
73
297
|
throw lastError;
|
|
74
298
|
};
|
|
75
|
-
const
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
299
|
+
const persistPlanningState = async (run) => {
|
|
300
|
+
if (run.status === "planning") {
|
|
301
|
+
return run;
|
|
302
|
+
}
|
|
303
|
+
const planning = withStatus(run, "planning");
|
|
304
|
+
await writer.persist(planning, writer.createEvent(run.runId, "run.planning", { status: "planning" }));
|
|
305
|
+
return planning;
|
|
306
|
+
};
|
|
307
|
+
const persistExecutingState = async (run) => {
|
|
308
|
+
const executing = parsePlannedRun({ ...run, status: "executing" });
|
|
309
|
+
await writer.persist(executing, writer.createEvent(executing.runId, "run.executing", { status: "executing" }));
|
|
310
|
+
return executing;
|
|
311
|
+
};
|
|
312
|
+
const continueRun = async (runId) => {
|
|
313
|
+
const current = await loadRunWithRetry(runId);
|
|
314
|
+
if (!canAdvanceRun(current)) {
|
|
315
|
+
return current;
|
|
316
|
+
}
|
|
317
|
+
const reconciliation = await runtime.reconcileOrphanSessions({
|
|
318
|
+
runId,
|
|
319
|
+
actorId: "harness-recovery",
|
|
320
|
+
});
|
|
321
|
+
if (reconciliation.kind === "rebound") {
|
|
322
|
+
return current;
|
|
323
|
+
}
|
|
324
|
+
if (reconciliation.kind === "abandoned") {
|
|
325
|
+
const interrupted = "taskGraph" in current
|
|
326
|
+
? withStatus(current, "paused")
|
|
327
|
+
: withStatus(withGovernance(current, {
|
|
328
|
+
...current.governance,
|
|
329
|
+
blockingQuestionId: createBlockedQuestionId(current),
|
|
330
|
+
}), "clarification_required");
|
|
331
|
+
await writer.persist(interrupted, writer.createEvent(runId, "run.recovery.session_abandoned", {
|
|
332
|
+
sessionIds: reconciliation.sessionIds,
|
|
333
|
+
status: interrupted.status,
|
|
334
|
+
}));
|
|
335
|
+
return interrupted;
|
|
336
|
+
}
|
|
337
|
+
if (current.status === "created" ||
|
|
338
|
+
current.status === "analyzing" ||
|
|
339
|
+
current.status === "planning") {
|
|
340
|
+
const planning = await persistPlanningState(current);
|
|
341
|
+
const planningArtifacts = await requestPlan(planning, planning.requirement);
|
|
342
|
+
validateTaskGraph(planningArtifacts.taskGraph, planning.requirement, runId);
|
|
343
|
+
runtime.clearInterruption(runId);
|
|
344
|
+
return await runTasks(await persistExecutingState(parsePlannedRun({
|
|
345
|
+
...planning,
|
|
346
|
+
status: "executing",
|
|
347
|
+
taskGraph: planningArtifacts.taskGraph,
|
|
348
|
+
contextPackage: planningArtifacts.contextPackage,
|
|
349
|
+
planReview: planningArtifacts.planReview,
|
|
350
|
+
})));
|
|
351
|
+
}
|
|
352
|
+
const planned = parsePlannedRun(setPaused(current, null));
|
|
353
|
+
runtime.clearInterruption(runId);
|
|
354
|
+
if (planned.status !== "executing" || current.governance.paused !== null) {
|
|
355
|
+
return await runTasks(await persistExecutingState(planned));
|
|
356
|
+
}
|
|
357
|
+
return await runTasks(planned);
|
|
358
|
+
};
|
|
359
|
+
const finalizeAdvanceError = async (runId, error) => {
|
|
360
|
+
if (error instanceof GraphValidationError ||
|
|
361
|
+
error instanceof PlanningBlockedError ||
|
|
362
|
+
error instanceof AgentRunFailedError ||
|
|
363
|
+
error instanceof AgentOutputParseError ||
|
|
364
|
+
error instanceof RunBudgetExceededError) {
|
|
365
|
+
const latest = await loadRunWithRetry(runId);
|
|
366
|
+
if (error instanceof PlanningBlockedError) {
|
|
367
|
+
return error.run;
|
|
79
368
|
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
369
|
+
const planning = withStatus(latest, "planning");
|
|
370
|
+
const blocked = withStatus(withGovernance(planning, {
|
|
371
|
+
...planning.governance,
|
|
372
|
+
blockingQuestionId: error instanceof RunBudgetExceededError ? createBlockedQuestionId(planning) : null,
|
|
373
|
+
}), error instanceof RunBudgetExceededError ? "paused" : "failed");
|
|
374
|
+
await writer.persist(blocked, writer.createEvent(runId, error instanceof RunBudgetExceededError ? "run.paused" : "run.failed", {
|
|
375
|
+
reason: error.message,
|
|
376
|
+
...(error instanceof RunBudgetExceededError
|
|
377
|
+
? {
|
|
378
|
+
budget: error.budget,
|
|
379
|
+
blockingQuestionId: blocked.governance.blockingQuestionId,
|
|
380
|
+
}
|
|
381
|
+
: {}),
|
|
382
|
+
}));
|
|
383
|
+
return blocked;
|
|
384
|
+
}
|
|
385
|
+
if (error instanceof RunPausedError) {
|
|
386
|
+
const latest = await loadRunWithRetry(runId);
|
|
387
|
+
if (latest.status === "paused") {
|
|
388
|
+
return latest;
|
|
85
389
|
}
|
|
390
|
+
return withStatus(setPaused(latest, latest.governance.paused), "paused");
|
|
86
391
|
}
|
|
87
|
-
|
|
392
|
+
if (error instanceof RunCancellationError) {
|
|
393
|
+
const latest = await loadRunWithRetry(runId);
|
|
394
|
+
if (latest.status === "cancelled") {
|
|
395
|
+
return latest;
|
|
396
|
+
}
|
|
397
|
+
const cancelled = withStatus(latest, "cancelled");
|
|
398
|
+
await writer.persist(cancelled, writer.createEvent(runId, "run.cancelled", { status: "cancelled" }));
|
|
399
|
+
return cancelled;
|
|
400
|
+
}
|
|
401
|
+
throw error;
|
|
88
402
|
};
|
|
89
|
-
|
|
403
|
+
const advanceRun = async (runId) => {
|
|
404
|
+
const active = advancingRuns.get(runId);
|
|
405
|
+
if (active !== undefined) {
|
|
406
|
+
return active;
|
|
407
|
+
}
|
|
408
|
+
const pending = continueRun(runId)
|
|
409
|
+
.catch(async (error) => finalizeAdvanceError(runId, error))
|
|
410
|
+
.finally(() => {
|
|
411
|
+
advancingRuns.delete(runId);
|
|
412
|
+
});
|
|
413
|
+
advancingRuns.set(runId, pending);
|
|
414
|
+
return pending;
|
|
415
|
+
};
|
|
416
|
+
const controller = {
|
|
90
417
|
async start(input) {
|
|
91
418
|
const requirement = RequirementSchema.parse({ schemaVersion: "1.0.0", ...input });
|
|
92
419
|
const created = RunSchema.parse({
|
|
@@ -124,75 +451,35 @@ export const createRunController = (options) => {
|
|
|
124
451
|
}));
|
|
125
452
|
return blocked;
|
|
126
453
|
}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
validateTaskGraph(graph, requirement, created.runId);
|
|
132
|
-
const executing = parsePlannedRun({ ...planning, status: "executing", taskGraph: graph });
|
|
133
|
-
await writer.persist(executing, writer.createEvent(created.runId, "run.executing", { status: "executing" }));
|
|
134
|
-
return await runTasks(executing);
|
|
135
|
-
}
|
|
136
|
-
catch (error) {
|
|
137
|
-
if (error instanceof GraphValidationError ||
|
|
138
|
-
error instanceof AgentRunFailedError ||
|
|
139
|
-
error instanceof AgentOutputParseError ||
|
|
140
|
-
error instanceof RunBudgetExceededError) {
|
|
141
|
-
const failed = withStatus(withGovernance(planning, {
|
|
142
|
-
...planning.governance,
|
|
143
|
-
blockingQuestionId: error instanceof RunBudgetExceededError ? createBlockedQuestionId(planning) : null,
|
|
144
|
-
}), error instanceof RunBudgetExceededError ? "paused" : "failed");
|
|
145
|
-
await writer.persist(failed, writer.createEvent(created.runId, error instanceof RunBudgetExceededError ? "run.paused" : "run.failed", {
|
|
146
|
-
reason: error.message,
|
|
147
|
-
...(error instanceof RunBudgetExceededError
|
|
148
|
-
? {
|
|
149
|
-
budget: error.budget,
|
|
150
|
-
blockingQuestionId: failed.governance.blockingQuestionId,
|
|
151
|
-
}
|
|
152
|
-
: {}),
|
|
153
|
-
}));
|
|
154
|
-
if (error instanceof RunBudgetExceededError) {
|
|
155
|
-
return failed;
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
if (error instanceof RunCancellationError) {
|
|
159
|
-
const latest = await options.store.loadState(created.runId);
|
|
160
|
-
if (latest.status === "cancelled") {
|
|
161
|
-
return latest;
|
|
162
|
-
}
|
|
163
|
-
const cancelled = withStatus(latest, "cancelled");
|
|
164
|
-
await writer.persist(cancelled, writer.createEvent(created.runId, "run.cancelled", { status: "cancelled" }));
|
|
165
|
-
return cancelled;
|
|
166
|
-
}
|
|
167
|
-
throw error;
|
|
168
|
-
}
|
|
454
|
+
return created;
|
|
455
|
+
},
|
|
456
|
+
async advanceRun(runId) {
|
|
457
|
+
return advanceRun(runId);
|
|
169
458
|
},
|
|
170
459
|
async status(runId) {
|
|
171
460
|
return loadRunWithRetry(runId);
|
|
172
461
|
},
|
|
173
462
|
async pause(input) {
|
|
174
463
|
const current = await loadRunWithRetry(input.runId);
|
|
175
|
-
if (current.status === "paused") {
|
|
176
|
-
return current;
|
|
177
|
-
}
|
|
178
|
-
if (isTerminalRunStatus(current)) {
|
|
464
|
+
if (current.status === "paused" || isTerminalRunStatus(current)) {
|
|
179
465
|
return current;
|
|
180
466
|
}
|
|
181
467
|
requireTransition(current, "pause", canPause);
|
|
182
|
-
await runtime.abortActiveSession(input.runId);
|
|
183
|
-
const pausedAt = options.clock.now().toISOString();
|
|
184
468
|
const paused = withStatus(setPaused(current, {
|
|
185
469
|
pauseId: options.ids.createEventId(`pause-${input.runId}`),
|
|
186
470
|
actor: input.actor,
|
|
187
471
|
reason: input.reason,
|
|
188
|
-
pausedAt,
|
|
472
|
+
pausedAt: options.clock.now().toISOString(),
|
|
189
473
|
}), "paused");
|
|
474
|
+
runtime.markPaused(input.runId);
|
|
190
475
|
await writer.persist(paused, writer.createEvent(input.runId, "run.paused", {
|
|
191
476
|
pauseId: paused.governance.paused?.pauseId ?? null,
|
|
192
477
|
actor: input.actor,
|
|
193
478
|
reason: input.reason,
|
|
194
479
|
}));
|
|
195
|
-
|
|
480
|
+
await runtime.abortActiveSession(input.runId);
|
|
481
|
+
const latest = await loadRunWithRetry(input.runId);
|
|
482
|
+
return latest.status === "paused" ? latest : paused;
|
|
196
483
|
},
|
|
197
484
|
async answer(input) {
|
|
198
485
|
const current = await loadRunWithRetry(input.runId);
|
|
@@ -200,13 +487,12 @@ export const createRunController = (options) => {
|
|
|
200
487
|
return current;
|
|
201
488
|
}
|
|
202
489
|
requireTransition(current, "answer", canAnswer);
|
|
203
|
-
const answeredAt = options.clock.now().toISOString();
|
|
204
490
|
const updated = withStatus(appendAnswer(current, {
|
|
205
491
|
answerId: options.ids.createEventId(`answer-${input.questionId}`),
|
|
206
492
|
questionId: input.questionId,
|
|
207
493
|
answer: input.answer,
|
|
208
494
|
actor: input.actor,
|
|
209
|
-
answeredAt,
|
|
495
|
+
answeredAt: options.clock.now().toISOString(),
|
|
210
496
|
}), "planning");
|
|
211
497
|
await writer.persist(updated, writer.createEvent(input.runId, "run.answered", {
|
|
212
498
|
answerId: updated.governance.answers.at(-1)?.answerId ?? null,
|
|
@@ -221,37 +507,30 @@ export const createRunController = (options) => {
|
|
|
221
507
|
case "completed":
|
|
222
508
|
case "cancelled":
|
|
223
509
|
case "failed":
|
|
510
|
+
case "clarification_required":
|
|
224
511
|
return run;
|
|
225
512
|
case "created":
|
|
226
513
|
case "analyzing":
|
|
227
514
|
case "planning":
|
|
228
|
-
case "clarification_required":
|
|
229
|
-
return run;
|
|
230
515
|
case "plan_ready":
|
|
231
516
|
case "executing":
|
|
232
517
|
case "verifying":
|
|
233
518
|
case "paused":
|
|
234
|
-
|
|
235
|
-
return run;
|
|
236
|
-
}
|
|
237
|
-
return "taskGraph" in run ? await runTasks(parsePlannedRun(setPaused(run, null))) : run;
|
|
519
|
+
return advanceRun(runId);
|
|
238
520
|
default:
|
|
239
521
|
return run;
|
|
240
522
|
}
|
|
241
523
|
},
|
|
242
524
|
async cancel(runId) {
|
|
243
525
|
const current = await loadRunWithRetry(runId);
|
|
244
|
-
if (current
|
|
245
|
-
current.status === "cancelled" ||
|
|
246
|
-
current.status === "failed") {
|
|
526
|
+
if (isTerminalRunStatus(current)) {
|
|
247
527
|
return current;
|
|
248
528
|
}
|
|
249
529
|
requireTransition(current, "cancel", canCancel);
|
|
530
|
+
runtime.markCancelled(runId);
|
|
250
531
|
await runtime.abortActiveSession(runId);
|
|
251
532
|
const latest = await loadRunWithRetry(runId);
|
|
252
|
-
if (latest
|
|
253
|
-
latest.status === "cancelled" ||
|
|
254
|
-
latest.status === "failed") {
|
|
533
|
+
if (isTerminalRunStatus(latest)) {
|
|
255
534
|
return latest;
|
|
256
535
|
}
|
|
257
536
|
const cancelled = withStatus(latest, "cancelled");
|
|
@@ -282,10 +561,14 @@ export const createRunController = (options) => {
|
|
|
282
561
|
return createReport(run, options.clock);
|
|
283
562
|
},
|
|
284
563
|
};
|
|
564
|
+
return controller;
|
|
285
565
|
};
|
|
286
566
|
const parsePlannerGraph = (text) => parseAgentJson(text, TaskGraphSchema, "planner");
|
|
287
567
|
const waitForNextTurn = async () => await new Promise((resolve) => {
|
|
288
568
|
setTimeout(resolve, 0);
|
|
289
569
|
});
|
|
290
570
|
const isMissingRunError = (error, runId) => error instanceof TypeError && error.message === `missing run ${runId}`;
|
|
571
|
+
const assertNever = (value) => {
|
|
572
|
+
throw new TypeError(`Unexpected planner output: ${JSON.stringify(value)}`);
|
|
573
|
+
};
|
|
291
574
|
//# sourceMappingURL=run-controller.js.map
|