harnery 0.17.0 → 0.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/README.md +1 -1
  2. package/dist/commands/browse.d.ts.map +1 -1
  3. package/dist/commands/browse.js +187 -4
  4. package/dist/commands/supervisor.d.ts.map +1 -1
  5. package/dist/commands/supervisor.js +76 -4
  6. package/dist/core/supervisor/index.d.ts +3 -3
  7. package/dist/core/supervisor/index.d.ts.map +1 -1
  8. package/dist/core/supervisor/index.js +2 -2
  9. package/dist/core/supervisor/plan-read.d.ts +2 -1
  10. package/dist/core/supervisor/plan-read.d.ts.map +1 -1
  11. package/dist/core/supervisor/plan-read.js +222 -3
  12. package/dist/core/supervisor/plan-types.d.ts +60 -3
  13. package/dist/core/supervisor/plan-types.d.ts.map +1 -1
  14. package/dist/core/supervisor/plan-types.js +2 -0
  15. package/dist/core/supervisor/planning.d.ts.map +1 -1
  16. package/dist/core/supervisor/planning.js +804 -56
  17. package/dist/core/supervisor/read.d.ts +3 -3
  18. package/dist/core/supervisor/read.d.ts.map +1 -1
  19. package/dist/core/supervisor/read.js +2 -2
  20. package/dist/core/supervisor/runner.d.ts.map +1 -1
  21. package/dist/core/supervisor/runner.js +7 -2
  22. package/dist/core/supervisor/service.js +3 -0
  23. package/dist/core/supervisor/state.d.ts +17 -2
  24. package/dist/core/supervisor/state.d.ts.map +1 -1
  25. package/dist/core/supervisor/state.js +211 -33
  26. package/dist/core/workflow/engine.d.ts.map +1 -1
  27. package/dist/core/workflow/engine.js +24 -6
  28. package/dist/core/workflow/types.d.ts +6 -0
  29. package/dist/core/workflow/types.d.ts.map +1 -1
  30. package/dist/core/workflow/validate.d.ts +3 -2
  31. package/dist/core/workflow/validate.d.ts.map +1 -1
  32. package/dist/core/workflow/validate.js +31 -3
  33. package/dist/lib/browser/client.d.ts +18 -0
  34. package/dist/lib/browser/client.d.ts.map +1 -1
  35. package/dist/lib/browser/client.js +39 -0
  36. package/dist/lib/browser/geometry.d.ts +146 -0
  37. package/dist/lib/browser/geometry.d.ts.map +1 -0
  38. package/dist/lib/browser/geometry.js +525 -0
  39. package/dist/lib/browser/index.d.ts +2 -0
  40. package/dist/lib/browser/index.d.ts.map +1 -1
  41. package/dist/lib/browser/target-size.d.ts +65 -0
  42. package/dist/lib/browser/target-size.d.ts.map +1 -0
  43. package/dist/lib/browser/target-size.js +108 -0
  44. package/package.json +7 -1
  45. package/src/commands/browse.ts +319 -0
  46. package/src/commands/supervisor.ts +92 -5
  47. package/src/core/supervisor/index.ts +17 -1
  48. package/src/core/supervisor/plan-read.ts +292 -2
  49. package/src/core/supervisor/plan-types.ts +69 -1
  50. package/src/core/supervisor/planning.ts +1012 -51
  51. package/src/core/supervisor/read.ts +16 -1
  52. package/src/core/supervisor/runner.ts +9 -2
  53. package/src/core/supervisor/service.ts +3 -0
  54. package/src/core/supervisor/state.ts +272 -31
  55. package/src/core/workflow/engine.ts +29 -6
  56. package/src/core/workflow/types.ts +6 -0
  57. package/src/core/workflow/validate.ts +34 -3
  58. package/src/lib/browser/client.ts +62 -0
  59. package/src/lib/browser/geometry.ts +695 -0
  60. package/src/lib/browser/index.ts +25 -0
  61. package/src/lib/browser/target-size.ts +180 -0
@@ -1,6 +1,6 @@
1
- export { readSupervisorPlan, readSupervisorPlans } from "./plan-read.js";
2
- export { SUPERVISOR_PLAN_SCHEMA_VERSION, type SupervisorPlanEvent, type SupervisorPlanEventType, type SupervisorPlanHistory, type SupervisorPlanOutcome, type SupervisorPlanProposal, type SupervisorPlanRecord, type SupervisorPlanRequest, type SupervisorPlanStatus, type SupervisorPlanTemplate, type SupervisorPlanWorkSpec, type SupervisorReplanningPolicy, } from "./plan-types.js";
1
+ export { readSupervisorPlan, readSupervisorPlanReviewReceipt, readSupervisorPlans, } from "./plan-read.js";
2
+ export { MAX_SUPERVISOR_PLAN_REVIEWERS, MAX_SUPERVISOR_PLAN_REVISION_ROUNDS, SUPERVISOR_PLAN_SCHEMA_VERSION, type SupervisorPlanEvent, type SupervisorPlanEventType, type SupervisorPlanHistory, type SupervisorPlanMilestone, type SupervisorPlanOutcome, type SupervisorPlanProposal, type SupervisorPlanRecord, type SupervisorPlanRequest, type SupervisorPlanReviewFinding, type SupervisorPlanReviewReceipt, type SupervisorPlanReviewReviewer, type SupervisorPlanReviewRound, type SupervisorPlanReviewStatus, type SupervisorPlanReviewSummary, type SupervisorPlanReviewVerdict, type SupervisorPlanStatus, type SupervisorPlanTemplate, type SupervisorPlanWorkSpec, type SupervisorReplanningPolicy, } from "./plan-types.js";
3
3
  export type { SupervisorServiceConfig, SupervisorServiceGoalRuntime, SupervisorServiceGoalState, SupervisorServiceProcessState, SupervisorServiceRuntime, SupervisorServiceStatus, SupervisorServiceStatusRecord, } from "./service.js";
4
4
  export { readSupervisorServiceConfig, readSupervisorServiceRuntime, readSupervisorServiceStatus, supervisorServiceLogPath, } from "./service-read.js";
5
- export { assertSupervisorId, collectSupervisorWork, listSupervisors, readSupervisor, SUPERVISOR_INTENT_SCHEMA_VERSION, type SupervisorAutomationPolicy, type SupervisorIntent, type SupervisorLimits, type SupervisorNextAction, type SupervisorProjection, type SupervisorRecord, type SupervisorState, } from "./state.js";
5
+ export { assertSupervisorId, collectSupervisorWork, listSupervisors, readSupervisor, SUPERVISOR_INTENT_SCHEMA_VERSION, type SupervisorAutomationPolicy, type SupervisorIntent, type SupervisorLimits, type SupervisorMission, type SupervisorNextAction, type SupervisorProjection, type SupervisorRecord, type SupervisorState, } from "./state.js";
6
6
  //# sourceMappingURL=read.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"read.d.ts","sourceRoot":"","sources":["../../../src/core/supervisor/read.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AACzE,OAAO,EACL,8BAA8B,EAC9B,KAAK,mBAAmB,EACxB,KAAK,uBAAuB,EAC5B,KAAK,qBAAqB,EAC1B,KAAK,qBAAqB,EAC1B,KAAK,sBAAsB,EAC3B,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,EACzB,KAAK,sBAAsB,EAC3B,KAAK,sBAAsB,EAC3B,KAAK,0BAA0B,GAChC,MAAM,iBAAiB,CAAC;AACzB,YAAY,EACV,uBAAuB,EACvB,4BAA4B,EAC5B,0BAA0B,EAC1B,6BAA6B,EAC7B,wBAAwB,EACxB,uBAAuB,EACvB,6BAA6B,GAC9B,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,2BAA2B,EAC3B,4BAA4B,EAC5B,2BAA2B,EAC3B,wBAAwB,GACzB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,kBAAkB,EAClB,qBAAqB,EACrB,eAAe,EACf,cAAc,EACd,gCAAgC,EAChC,KAAK,0BAA0B,EAC/B,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,EACzB,KAAK,oBAAoB,EACzB,KAAK,gBAAgB,EACrB,KAAK,eAAe,GACrB,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"read.d.ts","sourceRoot":"","sources":["../../../src/core/supervisor/read.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,+BAA+B,EAC/B,mBAAmB,GACpB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,6BAA6B,EAC7B,mCAAmC,EACnC,8BAA8B,EAC9B,KAAK,mBAAmB,EACxB,KAAK,uBAAuB,EAC5B,KAAK,qBAAqB,EAC1B,KAAK,uBAAuB,EAC5B,KAAK,qBAAqB,EAC1B,KAAK,sBAAsB,EAC3B,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,EAC1B,KAAK,2BAA2B,EAChC,KAAK,2BAA2B,EAChC,KAAK,4BAA4B,EACjC,KAAK,yBAAyB,EAC9B,KAAK,0BAA0B,EAC/B,KAAK,2BAA2B,EAChC,KAAK,2BAA2B,EAChC,KAAK,oBAAoB,EACzB,KAAK,sBAAsB,EAC3B,KAAK,sBAAsB,EAC3B,KAAK,0BAA0B,GAChC,MAAM,iBAAiB,CAAC;AACzB,YAAY,EACV,uBAAuB,EACvB,4BAA4B,EAC5B,0BAA0B,EAC1B,6BAA6B,EAC7B,wBAAwB,EACxB,uBAAuB,EACvB,6BAA6B,GAC9B,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,2BAA2B,EAC3B,4BAA4B,EAC5B,2BAA2B,EAC3B,wBAAwB,GACzB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,kBAAkB,EAClB,qBAAqB,EACrB,eAAe,EACf,cAAc,EACd,gCAAgC,EAChC,KAAK,0BAA0B,EAC/B,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EACtB,KAAK,oBAAoB,EACzB,KAAK,oBAAoB,EACzB,KAAK,gBAAgB,EACrB,KAAK,eAAe,GACrB,MAAM,YAAY,CAAC"}
@@ -1,4 +1,4 @@
1
- export { readSupervisorPlan, readSupervisorPlans } from "./plan-read.js";
2
- export { SUPERVISOR_PLAN_SCHEMA_VERSION, } from "./plan-types.js";
1
+ export { readSupervisorPlan, readSupervisorPlanReviewReceipt, readSupervisorPlans, } from "./plan-read.js";
2
+ export { MAX_SUPERVISOR_PLAN_REVIEWERS, MAX_SUPERVISOR_PLAN_REVISION_ROUNDS, SUPERVISOR_PLAN_SCHEMA_VERSION, } from "./plan-types.js";
3
3
  export { readSupervisorServiceConfig, readSupervisorServiceRuntime, readSupervisorServiceStatus, supervisorServiceLogPath, } from "./service-read.js";
4
4
  export { assertSupervisorId, collectSupervisorWork, listSupervisors, readSupervisor, SUPERVISOR_INTENT_SCHEMA_VERSION, } from "./state.js";
@@ -1 +1 @@
1
- {"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../../src/core/supervisor/runner.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,gBAAgB,EAItB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAE7D,OAAO,EAGL,KAAK,oBAAoB,EAE1B,MAAM,YAAY,CAAC;AAEpB,MAAM,MAAM,oBAAoB,GAC5B,WAAW,GACX,oBAAoB,GACpB,SAAS,GACT,kBAAkB,GAClB,aAAa,GACb,eAAe,CAAC;AAEpB,MAAM,WAAW,yBAAyB;IACxC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,KAAK,GAAG,QAAQ,GAAG,OAAO,CAAC;IACnC,MAAM,EAAE,WAAW,GAAG,QAAQ,GAAG,QAAQ,CAAC;IAC1C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,GAAG,KAAK,CAAC;IACrB,WAAW,EAAE,oBAAoB,CAAC;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,yBAAyB,EAAE,CAAC;IACtC,aAAa,EAAE,qBAAqB,EAAE,CAAC;IACvC,UAAU,EAAE,oBAAoB,CAAC;CAClC;AAED,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,EAAE,WAAW,GAAG,aAAa,GAAG,aAAa,CAAC,CAAC;IACtF,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAChC;AAQD,wBAAsB,aAAa,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAqL3F"}
1
+ {"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../../src/core/supervisor/runner.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,gBAAgB,EAItB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAE7D,OAAO,EAGL,KAAK,oBAAoB,EAE1B,MAAM,YAAY,CAAC;AAEpB,MAAM,MAAM,oBAAoB,GAC5B,WAAW,GACX,oBAAoB,GACpB,SAAS,GACT,kBAAkB,GAClB,aAAa,GACb,eAAe,CAAC;AAEpB,MAAM,WAAW,yBAAyB;IACxC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,KAAK,GAAG,QAAQ,GAAG,OAAO,CAAC;IACnC,MAAM,EAAE,WAAW,GAAG,QAAQ,GAAG,QAAQ,CAAC;IAC1C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,GAAG,KAAK,CAAC;IACrB,WAAW,EAAE,oBAAoB,CAAC;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,yBAAyB,EAAE,CAAC;IACtC,aAAa,EAAE,qBAAqB,EAAE,CAAC;IACvC,UAAU,EAAE,oBAAoB,CAAC;CAClC;AAED,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,EAAE,WAAW,GAAG,aAAa,GAAG,aAAa,CAAC,CAAC;IACtF,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAChC;AAQD,wBAAsB,aAAa,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CA4L3F"}
@@ -33,8 +33,10 @@ export async function runSupervisor(input) {
33
33
  }
34
34
  const before = graphFingerprint(record);
35
35
  let changed = false;
36
- if (record.projection.next_action === "replan") {
37
- log(`[${record.intent.title}] replan active graph generation ${record.projection.plan_generation}`);
36
+ if (record.projection.next_action === "replan" ||
37
+ record.projection.next_action === "plan_initial" ||
38
+ record.projection.next_action === "plan_milestone") {
39
+ log(`[${record.intent.title}] ${record.projection.next_action} at graph generation ${record.projection.plan_generation}`);
38
40
  const plan = await runSupervisorPlanner({
39
41
  coordRoot,
40
42
  record,
@@ -48,6 +50,9 @@ export async function runSupervisor(input) {
48
50
  if (mode === "tick") {
49
51
  return report("tick_complete", `planner produced ${plan.status} plan ${plan.plan_id}`, record);
50
52
  }
53
+ if (record.projection.state === "succeeded") {
54
+ return report("succeeded", record.projection.reason, record);
55
+ }
51
56
  if (record.projection.state !== "ready") {
52
57
  return report(stopForProjection(record.projection), record.projection.reason, record);
53
58
  }
@@ -434,9 +434,12 @@ function projectionFingerprint(projection) {
434
434
  projection.attempts_used,
435
435
  projection.attempts_remaining,
436
436
  projection.root_work_id,
437
+ projection.root_materialized,
437
438
  projection.plan_generation,
438
439
  projection.replans_used,
439
440
  projection.replans_remaining,
441
+ projection.milestones_completed,
442
+ projection.milestones_remaining,
440
443
  projection.pending_plan_id,
441
444
  projection.latest_plan_status,
442
445
  projection.ready_work,
@@ -15,6 +15,16 @@ export interface SupervisorAutomationPolicy {
15
15
  resume_approved: boolean;
16
16
  retry_blocked: boolean;
17
17
  }
18
+ export interface SupervisorMission {
19
+ objective: string;
20
+ acceptance: string[];
21
+ max_milestones: number;
22
+ }
23
+ export interface CreateSupervisorMissionInput {
24
+ objective: string;
25
+ acceptance: readonly string[];
26
+ maxMilestones?: number;
27
+ }
18
28
  export interface SupervisorIntent {
19
29
  schema_version: typeof SUPERVISOR_INTENT_SCHEMA_VERSION;
20
30
  id: string;
@@ -23,15 +33,17 @@ export interface SupervisorIntent {
23
33
  specialists: Record<string, WorkflowSpecialistProfile>;
24
34
  limits: SupervisorLimits;
25
35
  automation: SupervisorAutomationPolicy;
36
+ mission?: SupervisorMission;
26
37
  replanning?: SupervisorReplanningPolicy;
27
38
  created_at: string;
28
39
  }
29
40
  export type SupervisorState = "ready" | "running" | "awaiting_attention" | "blocked" | "budget_exhausted" | "succeeded";
30
- export type SupervisorNextAction = "run" | "wait_for_run" | "resolve_approval" | "review" | "retry" | "replan" | "review_plan" | "none";
41
+ export type SupervisorNextAction = "run" | "wait_for_run" | "resolve_approval" | "review" | "retry" | "replan" | "plan_initial" | "plan_milestone" | "review_plan" | "none";
31
42
  export interface SupervisorProjection {
32
43
  id: string;
33
44
  title: string;
34
45
  root_work_id: string;
46
+ root_materialized: boolean;
35
47
  state: SupervisorState;
36
48
  reason: string;
37
49
  next_action: SupervisorNextAction;
@@ -46,6 +58,8 @@ export interface SupervisorProjection {
46
58
  plan_generation: number;
47
59
  replans_used: number;
48
60
  replans_remaining: number;
61
+ milestones_completed: number;
62
+ milestones_remaining: number;
49
63
  pending_plan_id?: string;
50
64
  latest_plan_status?: SupervisorPlanRecord["status"];
51
65
  governed_work_ids: string[];
@@ -58,12 +72,13 @@ export interface SupervisorRecord {
58
72
  }
59
73
  export interface CreateSupervisorInput {
60
74
  coordRoot: string;
61
- rootWorkId: string;
75
+ rootWorkId?: string;
62
76
  specialists: Readonly<Record<string, WorkflowSpecialistProfile>>;
63
77
  title?: string;
64
78
  id?: string;
65
79
  limits?: Partial<SupervisorLimits>;
66
80
  automation?: Partial<SupervisorAutomationPolicy>;
81
+ mission?: CreateSupervisorMissionInput;
67
82
  replanning?: CreateSupervisorReplanningInput;
68
83
  }
69
84
  export declare function createSupervisor(input: CreateSupervisorInput): SupervisorRecord;
@@ -1 +1 @@
1
- {"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../../src/core/supervisor/state.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../../src/core/supervisor/state.ts"],"names":[],"mappings":"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"}
@@ -6,31 +6,49 @@ import { assertWorkId, readWorkItem } from "../work/read.js";
6
6
  import { workflowScriptDigest } from "../workflow/run-state.js";
7
7
  import { normalizeWorkflowSpecialists } from "../workflow/specialists.js";
8
8
  import { readSupervisorPlans } from "./plan-read.js";
9
- import { supervisorGraphFingerprint, } from "./plan-types.js";
9
+ import { MAX_SUPERVISOR_PLAN_REVIEWERS, MAX_SUPERVISOR_PLAN_REVISION_ROUNDS, supervisorGraphFingerprint, } from "./plan-types.js";
10
10
  export const SUPERVISOR_INTENT_SCHEMA_VERSION = 1;
11
11
  const GOAL_ID = /^[A-Za-z0-9][A-Za-z0-9._-]{0,99}$/;
12
12
  const MAX_TITLE = 200;
13
+ const MAX_OBJECTIVE = 4_000;
14
+ const MAX_ACCEPTANCE = 50;
13
15
  const MAX_INTENT_BYTES = 256 * 1024;
14
16
  const MAX_TEMPLATES = 20;
15
17
  const TEMPLATE_ID = /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/;
16
18
  const FOREIGN_LEASE_STALE_MS = 24 * 60 * 60 * 1_000;
17
19
  export function createSupervisor(input) {
18
20
  const coordRoot = resolve(input.coordRoot);
19
- assertWorkId(input.rootWorkId);
20
- const root = readWorkItem(coordRoot, input.rootWorkId);
21
21
  const id = input.id ?? newSupervisorId();
22
22
  assertSupervisorId(id);
23
+ const mission = input.mission ? normalizeMission(input.mission) : undefined;
24
+ if (mission && !input.replanning) {
25
+ throw new Error("supervisor mission requires a replanning policy");
26
+ }
27
+ if (!input.rootWorkId && !mission) {
28
+ throw new Error("supervisor creation without root work requires a mission and replanning policy");
29
+ }
30
+ if (input.rootWorkId)
31
+ assertWorkId(input.rootWorkId);
32
+ const root = input.rootWorkId ? readWorkItem(coordRoot, input.rootWorkId) : undefined;
33
+ const limits = normalizeLimits(input.limits);
23
34
  const replanning = input.replanning
24
- ? normalizeReplanning(input.replanning, input.specialists)
35
+ ? normalizeReplanning(input.replanning, input.specialists, limits)
25
36
  : undefined;
37
+ if (mission &&
38
+ !input.rootWorkId &&
39
+ replanning &&
40
+ replanning.max_replans <= mission.max_milestones) {
41
+ throw new Error("objective-first mission max_replans must exceed max_milestones to reserve completion review");
42
+ }
26
43
  const intent = {
27
44
  schema_version: SUPERVISOR_INTENT_SCHEMA_VERSION,
28
45
  id,
29
- title: bounded(input.title ?? root.intent.title, "supervisor title", MAX_TITLE),
30
- root_work_id: input.rootWorkId,
46
+ title: bounded(input.title ?? root?.intent.title ?? missionTitle(mission), "supervisor title", MAX_TITLE),
47
+ root_work_id: input.rootWorkId ?? missionRootId(id),
31
48
  specialists: normalizeWorkflowSpecialists(input.specialists),
32
- limits: normalizeLimits(input.limits),
49
+ limits,
33
50
  automation: normalizeAutomation(input.automation),
51
+ ...(mission ? { mission } : {}),
34
52
  ...(replanning ? { replanning } : {}),
35
53
  created_at: new Date().toISOString(),
36
54
  };
@@ -136,7 +154,11 @@ function readSupervisorInternal(coordRootRaw, goalId, ignoreLease) {
136
154
  const coordRoot = resolve(coordRootRaw);
137
155
  const intent = readSupervisorIntent(coordRoot, goalId);
138
156
  const plans = readSupervisorPlans(coordRoot, intent.id, intent.root_work_id);
139
- const work = collectSupervisorWork(coordRoot, plans.active_root_work_id);
157
+ const activeRootExists = workIntentExists(coordRoot, plans.active_root_work_id);
158
+ if (!activeRootExists && (!intent.mission || plans.generation > 0)) {
159
+ throw new Error(`supervisor ${intent.id} root work is missing`);
160
+ }
161
+ const work = activeRootExists ? collectSupervisorWork(coordRoot, plans.active_root_work_id) : [];
140
162
  const governed = collectGovernedWork(coordRoot, intent.root_work_id, plans, work);
141
163
  return {
142
164
  intent,
@@ -147,8 +169,6 @@ function readSupervisorInternal(coordRootRaw, goalId, ignoreLease) {
147
169
  }
148
170
  function deriveProjection(coordRoot, intent, work, governed, plans, ignoreLease) {
149
171
  const root = work.find((record) => record.intent.id === plans.active_root_work_id);
150
- if (!root)
151
- throw new Error(`supervisor ${intent.id} root work is missing`);
152
172
  const attemptsUsed = governed.reduce((sum, record) => sum + record.projection.attempts_used, 0);
153
173
  const readyWork = work
154
174
  .filter((record) => record.projection.state === "ready")
@@ -181,10 +201,14 @@ function deriveProjection(coordRoot, intent, work, governed, plans, ignoreLease)
181
201
  ...cancelled,
182
202
  ...terminalBlocked,
183
203
  ]);
204
+ const initialRootAccepted = intent.mission !== undefined &&
205
+ governed.some((record) => record.intent.id === intent.root_work_id && record.projection.state === "succeeded");
206
+ const milestonesCompleted = plans.milestones_completed + (initialRootAccepted ? 1 : 0);
184
207
  const base = {
185
208
  id: intent.id,
186
209
  title: intent.title,
187
210
  root_work_id: plans.active_root_work_id,
211
+ root_materialized: root !== undefined,
188
212
  work_ids: work.map((record) => record.intent.id),
189
213
  ready_work: readyWork,
190
214
  resumable_work: resumableWork,
@@ -196,6 +220,8 @@ function deriveProjection(coordRoot, intent, work, governed, plans, ignoreLease)
196
220
  plan_generation: plans.generation,
197
221
  replans_used: plans.plans.length,
198
222
  replans_remaining: Math.max(0, (intent.replanning?.max_replans ?? 0) - plans.plans.length),
223
+ milestones_completed: milestonesCompleted,
224
+ milestones_remaining: Math.max(0, (intent.mission?.max_milestones ?? 0) - milestonesCompleted),
199
225
  pending_plan_id: plans.latest?.status === "proposed" ? plans.latest.request.id : undefined,
200
226
  latest_plan_status: plans.latest?.status,
201
227
  governed_work_ids: governed.map((record) => record.intent.id),
@@ -208,11 +234,11 @@ function deriveProjection(coordRoot, intent, work, governed, plans, ignoreLease)
208
234
  next_action: "wait_for_run",
209
235
  };
210
236
  }
211
- if (root.projection.state === "succeeded") {
237
+ if (intent.mission && plans.completed) {
212
238
  return {
213
239
  ...base,
214
240
  state: "succeeded",
215
- reason: "root work was explicitly accepted",
241
+ reason: "mission completion was explicitly accepted",
216
242
  next_action: "none",
217
243
  };
218
244
  }
@@ -240,6 +266,64 @@ function deriveProjection(coordRoot, intent, work, governed, plans, ignoreLease)
240
266
  next_action: "replan",
241
267
  };
242
268
  }
269
+ const triggerFingerprint = supervisorGraphFingerprint({
270
+ rootWorkId: plans.active_root_work_id,
271
+ generation: plans.generation,
272
+ work,
273
+ });
274
+ const latestHandledSameGraph = plans.latest?.request.trigger_fingerprint === triggerFingerprint &&
275
+ plans.latest.request.prior_root_work_id === plans.active_root_work_id &&
276
+ plans.latest.status === "attention";
277
+ if (latestHandledSameGraph && plans.latest) {
278
+ return {
279
+ ...base,
280
+ state: "awaiting_attention",
281
+ reason: plans.latest.reason ?? `plan ${plans.latest.request.id} requires attention`,
282
+ next_action: "none",
283
+ };
284
+ }
285
+ if (!root && intent.mission) {
286
+ if (!intent.replanning || plans.plans.length >= intent.replanning.max_replans) {
287
+ return {
288
+ ...base,
289
+ state: "budget_exhausted",
290
+ reason: "mission exhausted its planning budget before creating an initial milestone",
291
+ next_action: "none",
292
+ };
293
+ }
294
+ return {
295
+ ...base,
296
+ state: "ready",
297
+ reason: "mission is ready for its initial bounded milestone plan",
298
+ next_action: "plan_initial",
299
+ };
300
+ }
301
+ if (!root)
302
+ throw new Error(`supervisor ${intent.id} root work is missing`);
303
+ if (root.projection.state === "succeeded" && intent.mission) {
304
+ if (!intent.replanning || plans.plans.length >= intent.replanning.max_replans) {
305
+ return {
306
+ ...base,
307
+ state: "budget_exhausted",
308
+ reason: "mission exhausted its planning budget at a milestone boundary",
309
+ next_action: "none",
310
+ };
311
+ }
312
+ return {
313
+ ...base,
314
+ state: "ready",
315
+ reason: `milestone ${plans.milestones_completed} is accepted and requires mission reassessment`,
316
+ next_action: "plan_milestone",
317
+ };
318
+ }
319
+ if (root.projection.state === "succeeded") {
320
+ return {
321
+ ...base,
322
+ state: "succeeded",
323
+ reason: "root work was explicitly accepted",
324
+ next_action: "none",
325
+ };
326
+ }
243
327
  const resumableDispatchable = intent.automation.resume_approved ? resumableWork : [];
244
328
  const attemptDispatchable = [
245
329
  ...readyWork,
@@ -318,14 +402,6 @@ function deriveProjection(coordRoot, intent, work, governed, plans, ignoreLease)
318
402
  next_action: "none",
319
403
  };
320
404
  }
321
- const triggerFingerprint = supervisorGraphFingerprint({
322
- rootWorkId: plans.active_root_work_id,
323
- generation: plans.generation,
324
- work,
325
- });
326
- const latestHandledSameGraph = plans.latest?.request.trigger_fingerprint === triggerFingerprint &&
327
- plans.latest.request.prior_root_work_id === plans.active_root_work_id &&
328
- plans.latest.status === "attention";
329
405
  const canReplan = intent.replanning !== undefined &&
330
406
  plans.plans.length < intent.replanning.max_replans &&
331
407
  cancelled.length === 0 &&
@@ -350,14 +426,6 @@ function deriveProjection(coordRoot, intent, work, governed, plans, ignoreLease)
350
426
  next_action: "none",
351
427
  };
352
428
  }
353
- if (latestHandledSameGraph && plans.latest) {
354
- return {
355
- ...base,
356
- state: "awaiting_attention",
357
- reason: plans.latest.reason ?? `plan ${plans.latest.request.id} requires attention`,
358
- next_action: "none",
359
- };
360
- }
361
429
  return {
362
430
  ...base,
363
431
  state: "blocked",
@@ -394,6 +462,19 @@ function validateIntent(intent, goalId) {
394
462
  }
395
463
  bounded(intent.title, "supervisor title", MAX_TITLE);
396
464
  assertWorkId(intent.root_work_id);
465
+ if (intent.mission) {
466
+ const normalizedMission = normalizeMission({
467
+ objective: intent.mission.objective,
468
+ acceptance: intent.mission.acceptance,
469
+ maxMilestones: intent.mission.max_milestones,
470
+ });
471
+ if (JSON.stringify(normalizedMission) !== JSON.stringify(intent.mission)) {
472
+ throw new Error(`supervisor intent ${goalId} mission is not canonical`);
473
+ }
474
+ if (!intent.replanning) {
475
+ throw new Error(`supervisor intent ${goalId} mission requires replanning`);
476
+ }
477
+ }
397
478
  const specialists = normalizeWorkflowSpecialists(intent.specialists);
398
479
  if (JSON.stringify(specialists) !== JSON.stringify(intent.specialists)) {
399
480
  throw new Error(`supervisor intent ${goalId} specialists are not canonical`);
@@ -405,7 +486,29 @@ function validateIntent(intent, goalId) {
405
486
  throw new Error(`supervisor intent ${goalId} automation policy is not canonical`);
406
487
  }
407
488
  if (intent.replanning)
408
- validateReplanning(intent.replanning, specialists, goalId);
489
+ validateReplanning(intent.replanning, specialists, intent.limits, goalId);
490
+ }
491
+ function normalizeMission(input) {
492
+ if (!Array.isArray(input.acceptance)) {
493
+ throw new Error("supervisor mission acceptance must be an array");
494
+ }
495
+ if (input.acceptance.length < 1 || input.acceptance.length > MAX_ACCEPTANCE) {
496
+ throw new Error(`supervisor mission acceptance must contain 1 to ${MAX_ACCEPTANCE} criteria`);
497
+ }
498
+ const acceptance = input.acceptance.map((criterion, index) => bounded(criterion, `supervisor mission acceptance[${index}]`, 500));
499
+ if (new Set(acceptance).size !== acceptance.length) {
500
+ throw new Error("supervisor mission acceptance criteria must be unique");
501
+ }
502
+ return {
503
+ objective: bounded(input.objective, "supervisor mission objective", MAX_OBJECTIVE),
504
+ acceptance,
505
+ max_milestones: positive(input.maxMilestones ?? 4, "supervisor mission max_milestones", 20),
506
+ };
507
+ }
508
+ function missionTitle(mission) {
509
+ return mission.objective.length <= MAX_TITLE
510
+ ? mission.objective
511
+ : `${mission.objective.slice(0, MAX_TITLE - 1).trimEnd()}…`;
409
512
  }
410
513
  function normalizeLimits(input) {
411
514
  return {
@@ -424,7 +527,7 @@ function normalizeAutomation(input) {
424
527
  retry_blocked: boolean(input?.retry_blocked ?? false, "retry_blocked"),
425
528
  };
426
529
  }
427
- function normalizeReplanning(input, specialistsInput) {
530
+ function normalizeReplanning(input, specialistsInput, limits) {
428
531
  const specialists = normalizeWorkflowSpecialists(specialistsInput);
429
532
  const plannerSpecialist = bounded(input.plannerSpecialist, "planner specialist", 100);
430
533
  if (!specialists[plannerSpecialist]) {
@@ -460,6 +563,9 @@ function normalizeReplanning(input, specialistsInput) {
460
563
  if (maxWorkItemsPerPlan > maxTotalWorkItems) {
461
564
  throw new Error("replanning max_work_items_per_plan cannot exceed max_total_work_items");
462
565
  }
566
+ const review = input.review
567
+ ? normalizeReviewPolicy(input.review, specialists, plannerSpecialist, limits)
568
+ : undefined;
463
569
  return {
464
570
  planner_specialist: plannerSpecialist,
465
571
  auto_apply: boolean(input.autoApply ?? false, "replanning auto_apply"),
@@ -467,9 +573,39 @@ function normalizeReplanning(input, specialistsInput) {
467
573
  max_work_items_per_plan: maxWorkItemsPerPlan,
468
574
  max_total_work_items: maxTotalWorkItems,
469
575
  templates,
576
+ ...(review ? { review } : {}),
470
577
  };
471
578
  }
472
- function validateReplanning(policy, specialists, goalId) {
579
+ function normalizeReviewPolicy(input, specialists, plannerSpecialist, limits) {
580
+ if (!Array.isArray(input.reviewerSpecialists) || input.reviewerSpecialists.length < 1) {
581
+ throw new Error("replanning review requires at least one reviewer specialist");
582
+ }
583
+ if (input.reviewerSpecialists.length > MAX_SUPERVISOR_PLAN_REVIEWERS) {
584
+ throw new Error(`replanning review cannot exceed ${MAX_SUPERVISOR_PLAN_REVIEWERS} reviewer specialists`);
585
+ }
586
+ const reviewerSpecialists = input.reviewerSpecialists.map((specialist, index) => bounded(specialist, `reviewer specialist[${index}]`, 100));
587
+ if (new Set(reviewerSpecialists).size !== reviewerSpecialists.length) {
588
+ throw new Error("replanning reviewer specialists must be unique");
589
+ }
590
+ for (const specialist of reviewerSpecialists) {
591
+ if (!specialists[specialist]) {
592
+ throw new Error(`reviewer specialist ${specialist} is not present in the frozen team`);
593
+ }
594
+ if (specialist === plannerSpecialist) {
595
+ throw new Error("reviewer specialist cannot be the planner specialist");
596
+ }
597
+ }
598
+ const maxRevisionRounds = nonNegative(input.maxRevisionRounds, "replanning review max_revision_rounds", MAX_SUPERVISOR_PLAN_REVISION_ROUNDS);
599
+ const worstCaseAgents = 1 + reviewerSpecialists.length * (maxRevisionRounds + 1) + maxRevisionRounds;
600
+ if (worstCaseAgents > limits.max_agents_per_work) {
601
+ throw new Error(`replanning review worst-case ${worstCaseAgents} agents exceeds max_agents_per_work ${limits.max_agents_per_work}`);
602
+ }
603
+ return {
604
+ reviewer_specialists: reviewerSpecialists,
605
+ max_revision_rounds: maxRevisionRounds,
606
+ };
607
+ }
608
+ function validateReplanning(policy, specialists, limits, goalId) {
473
609
  if (!specialists[policy.planner_specialist]) {
474
610
  throw new Error(`supervisor ${goalId} planner specialist is not in the frozen team`);
475
611
  }
@@ -499,11 +635,41 @@ function validateReplanning(policy, specialists, goalId) {
499
635
  }
500
636
  if (!rootCapable)
501
637
  throw new Error(`supervisor ${goalId} has no root-capable replanning template`);
638
+ if (policy.review !== undefined) {
639
+ const review = policy.review;
640
+ if (!Array.isArray(review.reviewer_specialists) ||
641
+ review.reviewer_specialists.length < 1 ||
642
+ review.reviewer_specialists.length > MAX_SUPERVISOR_PLAN_REVIEWERS ||
643
+ !Number.isSafeInteger(review.max_revision_rounds) ||
644
+ review.max_revision_rounds < 0 ||
645
+ review.max_revision_rounds > MAX_SUPERVISOR_PLAN_REVISION_ROUNDS) {
646
+ throw new Error(`supervisor ${goalId} replanning review policy is invalid`);
647
+ }
648
+ if (new Set(review.reviewer_specialists).size !== review.reviewer_specialists.length) {
649
+ throw new Error(`supervisor ${goalId} replanning reviewers are not unique`);
650
+ }
651
+ for (const specialist of review.reviewer_specialists) {
652
+ if (!specialists[specialist]) {
653
+ throw new Error(`supervisor ${goalId} reviewer specialist is not in the frozen team`);
654
+ }
655
+ if (specialist === policy.planner_specialist) {
656
+ throw new Error(`supervisor ${goalId} reviewer specialist cannot be planner`);
657
+ }
658
+ }
659
+ const worstCaseAgents = 1 +
660
+ review.reviewer_specialists.length * (review.max_revision_rounds + 1) +
661
+ review.max_revision_rounds;
662
+ if (worstCaseAgents > limits.max_agents_per_work) {
663
+ throw new Error(`supervisor ${goalId} review policy exceeds the agent budget`);
664
+ }
665
+ }
502
666
  }
503
667
  function collectGovernedWork(coordRoot, originalRootWorkId, plans, active) {
504
668
  const governed = new Map();
505
- for (const record of collectSupervisorWork(coordRoot, originalRootWorkId)) {
506
- governed.set(record.intent.id, record);
669
+ if (workIntentExists(coordRoot, originalRootWorkId)) {
670
+ for (const record of collectSupervisorWork(coordRoot, originalRootWorkId)) {
671
+ governed.set(record.intent.id, record);
672
+ }
507
673
  }
508
674
  for (const workId of plans.applied_work_ids)
509
675
  governed.set(workId, readWorkItem(coordRoot, workId));
@@ -511,6 +677,12 @@ function collectGovernedWork(coordRoot, originalRootWorkId, plans, active) {
511
677
  governed.set(record.intent.id, record);
512
678
  return [...governed.values()];
513
679
  }
680
+ function workIntentExists(coordRoot, workId) {
681
+ return existsSync(join(resolve(coordRoot), ".harnery", "work", workId, "intent.json"));
682
+ }
683
+ function missionRootId(goalId) {
684
+ return `${goalId.slice(0, 87)}-mission-root`;
685
+ }
514
686
  function supervisorDir(coordRoot, goalId) {
515
687
  assertSupervisorId(goalId);
516
688
  return join(resolve(coordRoot), ".harnery", "supervisors", goalId);
@@ -579,6 +751,12 @@ function positive(value, field, max) {
579
751
  }
580
752
  return value;
581
753
  }
754
+ function nonNegative(value, field, max) {
755
+ if (!Number.isSafeInteger(value) || value < 0 || value > max) {
756
+ throw new Error(`${field} must be an integer between 0 and ${max}`);
757
+ }
758
+ return value;
759
+ }
582
760
  function boolean(value, field) {
583
761
  if (typeof value !== "boolean")
584
762
  throw new Error(`supervisor ${field} must be boolean`);
@@ -1 +1 @@
1
- {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../../src/core/workflow/engine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAqCH,OAAO,KAAK,EAEV,UAAU,EAEV,SAAS,EAOV,MAAM,YAAY,CAAC;AAYpB,qBAAa,gBAAiB,SAAQ,KAAK;IACzC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;gBAEf,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO;CAM/E;AAED,qBAAa,mBAAoB,SAAQ,KAAK;IAC5C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;gBAEjB,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM;CAOpF;AAED,wBAAsB,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC,CAyC1F"}
1
+ {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../../src/core/workflow/engine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAqCH,OAAO,KAAK,EAEV,UAAU,EAEV,SAAS,EAQV,MAAM,YAAY,CAAC;AAYpB,qBAAa,gBAAiB,SAAQ,KAAK;IACzC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;gBAEf,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO;CAM/E;AAED,qBAAa,mBAAoB,SAAQ,KAAK;IAC5C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;gBAEjB,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM;CAOpF;AAED,wBAAsB,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC,CAyC1F"}
@@ -350,6 +350,9 @@ async function executeWorkflow(scriptPath, absScript, opts, resumeState) {
350
350
  const assignment = resolveSpecialistAssignment(specialists, prompt, requestedOpts);
351
351
  const agentOpts = assignment.opts;
352
352
  const assignmentPrompt = assignment.prompt;
353
+ const dispatchPrompt = agentOpts.schema
354
+ ? withSchemaContract(assignmentPrompt, agentOpts.schema)
355
+ : assignmentPrompt;
353
356
  let reservedForDispatch = 0;
354
357
  let spawnCountClaimed = false;
355
358
  const harness = agentOpts.harness ?? defaultHarness;
@@ -409,7 +412,7 @@ async function executeWorkflow(scriptPath, absScript, opts, resumeState) {
409
412
  max_attempts: maxAttempts,
410
413
  max_turns: agentOpts.maxTurns ?? DEFAULT_MAX_TURNS,
411
414
  timeout_ms: agentOpts.timeoutMs ?? DEFAULT_TIMEOUT_MS,
412
- prompt_bytes: Buffer.byteLength(assignmentPrompt),
415
+ prompt_bytes: Buffer.byteLength(dispatchPrompt),
413
416
  isolation,
414
417
  network_access: networkAccess,
415
418
  current_cost_usd: round4(costUsd + reservedCostUsd),
@@ -529,7 +532,7 @@ async function executeWorkflow(scriptPath, absScript, opts, resumeState) {
529
532
  effort: agentOpts.effort ?? null,
530
533
  });
531
534
  log(`[${name}] ${currentStage || "(no stage)"} → ${id} [${harness}] ${label}`);
532
- let attemptPrompt = assignmentPrompt;
535
+ let attemptPrompt = dispatchPrompt;
533
536
  let last = null;
534
537
  let agentCostUsd = 0;
535
538
  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
@@ -594,12 +597,16 @@ async function executeWorkflow(scriptPath, absScript, opts, resumeState) {
594
597
  return parsed.value;
595
598
  }
596
599
  journal("agent.schema_retry", { id, attempt, problems });
597
- // Feed the validation failure back verbatim — the retry prompt carries
598
- // exactly what was wrong, which is what makes bounded retry converge.
600
+ // Keep the original cache identity while making the actual output
601
+ // contract explicit. A full bounded copy of the rejected value lets the
602
+ // child repair omissions instead of reconstructing an unseen object.
599
603
  attemptPrompt =
600
- `${assignmentPrompt}\n\nYour previous reply failed validation:\n` +
604
+ `${dispatchPrompt}\n\nYour previous reply failed validation. ` +
605
+ `Return a complete replacement value, not a patch.\n\n` +
606
+ `Previous reply (JSON string): ${JSON.stringify(boundedSchemaReply(last.text))}\n\n` +
607
+ `Validation problems:\n` +
601
608
  `${problems.map((p) => ` - ${p}`).join("\n")}\n` +
602
- `Reply with ONLY the corrected JSON object. No prose, no code fences.`;
609
+ `Reply with ONLY the corrected JSON value. No prose, no code fences.`;
603
610
  }
604
611
  const reason = last?.ok
605
612
  ? `schema validation failed after ${maxAttempts} attempt(s)`
@@ -793,6 +800,17 @@ async function executeWorkflow(scriptPath, absScript, opts, resumeState) {
793
800
  throw new WorkflowRunError(err.message, runId, proofPath, err);
794
801
  }
795
802
  }
803
+ const MAX_SCHEMA_RETRY_REPLY = 16_000;
804
+ function withSchemaContract(prompt, schema) {
805
+ return (`${prompt}\n\nOutput contract:\n` +
806
+ `Return ONLY one JSON value matching this schema. Do not use prose or code fences.\n` +
807
+ `${JSON.stringify(schema)}`);
808
+ }
809
+ function boundedSchemaReply(value) {
810
+ if (value.length <= MAX_SCHEMA_RETRY_REPLY)
811
+ return value;
812
+ return `${value.slice(0, MAX_SCHEMA_RETRY_REPLY)}\n[truncated by Harnery]`;
813
+ }
796
814
  /** Stable identity for one agent() call, for the resume cache. The ORIGINAL
797
815
  * prompt (never a retry-mutated one) plus everything that changes behavior. */
798
816
  function agentCallKey(stage, harness, agentOpts, prompt) {
@@ -174,6 +174,12 @@ export interface StageSchema {
174
174
  required?: string[];
175
175
  /** type=array */
176
176
  items?: StageSchema;
177
+ minItems?: number;
178
+ maxItems?: number;
179
+ /** type=string */
180
+ minLength?: number;
181
+ maxLength?: number;
182
+ pattern?: string;
177
183
  /** any type: closed value set (compared with ===) */
178
184
  enum?: Array<string | number | boolean>;
179
185
  }