@buildaharness/aielia 0.3.3 → 0.3.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/README.md +63 -20
- package/dist/PlanGraphPane.d.ts +19 -0
- package/dist/_memory-core-generated.d.ts +1764 -0
- package/dist/agent-loop.d.ts +31 -8
- package/dist/ambiguity-guard-flag.d.ts +12 -0
- package/dist/ambiguity-guard.d.ts +20 -0
- package/dist/answer-claim.d.ts +13 -1
- package/dist/ask-clarification-service.d.ts +12 -1
- package/dist/ask-response-format.d.ts +6 -0
- package/dist/assistant-session.d.ts +16 -5
- package/dist/assistant-source.d.ts +7 -0
- package/dist/assistant-types.d.ts +25 -1
- package/dist/assistant.d.ts +166 -5
- package/dist/benchmark-injected-failure.d.ts +6 -0
- package/dist/bin-CjKpxDxl.js +4836 -0
- package/dist/bin-CjKpxDxl.js.map +1 -0
- package/dist/cli-session.d.ts +26 -1
- package/dist/cli.d.ts +20 -2
- package/dist/cli.js +1 -1
- package/dist/code-plan-templates.d.ts +21 -0
- package/dist/config.d.ts +51 -0
- package/dist/constraint-check.d.ts +35 -0
- package/dist/contradiction-checker.d.ts +7 -0
- package/dist/decomposed-answer.d.ts +13 -0
- package/dist/decomposition-classifier.d.ts +2 -0
- package/dist/doctor-checks.d.ts +3 -0
- package/dist/episodic-digest.d.ts +89 -0
- package/dist/fact-extraction.d.ts +39 -0
- package/dist/file-tools-mcp-server.mjs +138 -12
- package/dist/file-tools.d.ts +4 -0
- package/dist/first-run.d.ts +3 -2
- package/dist/goal-graph-flag.d.ts +44 -0
- package/dist/goal-graph-reconcile.d.ts +55 -0
- package/dist/goal-graph-service.d.ts +48 -0
- package/dist/goal-graph-store.d.ts +485 -0
- package/dist/goal-graph-suggest-flag.d.ts +34 -0
- package/dist/goal-identity-matcher.d.ts +21 -0
- package/dist/goal-thread-identity.d.ts +32 -0
- package/dist/goal-thread-scheduler.d.ts +78 -0
- package/dist/grounding-check.d.ts +33 -0
- package/dist/harness-bridge.d.ts +75 -2
- package/dist/harness-token-budget.d.ts +9 -0
- package/dist/index.d.ts +30 -1
- package/dist/index.js +166 -80
- package/dist/index.js.map +1 -1
- package/dist/layer-policy-flag.d.ts +13 -0
- package/dist/layer-policy-wiring.d.ts +77 -0
- package/dist/layer-settings.d.ts +49 -0
- package/dist/layer-telemetry.d.ts +2 -0
- package/dist/lexical/lexical-mode.d.ts +29 -0
- package/dist/live-steering-channel.d.ts +31 -0
- package/dist/memory-consolidation.d.ts +80 -0
- package/dist/memory-governance.d.ts +30 -0
- package/dist/memory-reviewer.d.ts +114 -0
- package/dist/memory-service.d.ts +348 -9
- package/dist/model-json.d.ts +17 -0
- package/dist/next-step-context.d.ts +51 -0
- package/dist/next-step-proposer.d.ts +53 -0
- package/dist/plan-approval-service.d.ts +1 -1
- package/dist/plan-drafting-service.d.ts +1 -1
- package/dist/plan-graph-flag.d.ts +20 -0
- package/dist/plan-question.d.ts +60 -0
- package/dist/plan-service.d.ts +6 -2
- package/dist/plan-step-prompt.d.ts +15 -0
- package/dist/plan-store.d.ts +7 -1
- package/dist/plan-viz/normalize.d.ts +14 -0
- package/dist/plan-viz/plan-detail-lines.d.ts +3 -0
- package/dist/plan-viz/plan-layout.d.ts +48 -0
- package/dist/plan-viz/plan-nav.d.ts +29 -0
- package/dist/plan-viz/plan-raster.d.ts +36 -0
- package/dist/plan-viz/plan-routes.d.ts +6 -0
- package/dist/plan-viz/plan-snapshot.d.ts +73 -0
- package/dist/plan-viz/plan-viewport.d.ts +29 -0
- package/dist/plan-viz/plan-width.d.ts +15 -0
- package/dist/plan-viz/testkit/display-width.d.ts +12 -0
- package/dist/plan-viz/testkit/generators.d.ts +61 -0
- package/dist/plan-viz/testkit/grid-oracles.d.ts +38 -0
- package/dist/plan-viz/testkit/nav-oracles.d.ts +79 -0
- package/dist/plan-viz/testkit/types.d.ts +8 -0
- package/dist/plan-viz/types.d.ts +34 -0
- package/dist/provider-setup-LFsaTkpf.js +16606 -0
- package/dist/provider-setup-LFsaTkpf.js.map +1 -0
- package/dist/provider-setup.d.ts +51 -0
- package/dist/recall-tool.d.ts +43 -0
- package/dist/recovery-note.d.ts +22 -0
- package/dist/response-service.d.ts +28 -2
- package/dist/review-checker.d.ts +10 -4
- package/dist/reviewer-revision.d.ts +23 -0
- package/dist/risk-classifier.d.ts +7 -0
- package/dist/scope-urgency-classifier.d.ts +29 -0
- package/dist/scripted-llm-client.d.ts +26 -1
- package/dist/semantic-compaction.d.ts +15 -0
- package/dist/semantic-hypotheses.d.ts +40 -0
- package/dist/source-reliability.d.ts +71 -0
- package/dist/supervisor-flag.d.ts +20 -0
- package/dist/task-completion-check.d.ts +24 -0
- package/dist/tool-control-plane.d.ts +33 -1
- package/dist/tool-effect-class.d.ts +9 -0
- package/dist/transcript-compaction.d.ts +9 -0
- package/dist/{tui-app-CFfOP2DC.js → tui-app-BLR-PRFp.js} +321 -7
- package/dist/tui-app-BLR-PRFp.js.map +1 -0
- package/dist/tui-app.d.ts +38 -0
- package/dist/turn-intent-classifier.d.ts +75 -16
- package/dist/turn-interpreter.d.ts +25 -3
- package/dist/version.d.ts +1 -1
- package/package.json +7 -7
- package/dist/bin-Btzhiyzi.js +0 -2108
- package/dist/bin-Btzhiyzi.js.map +0 -1
- package/dist/cli-session-DnSc6Hhx.js +0 -8343
- package/dist/cli-session-DnSc6Hhx.js.map +0 -1
- package/dist/tui-app-CFfOP2DC.js.map +0 -1
|
@@ -0,0 +1,485 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { MemoryAdapter } from '@buildaharness/runtime';
|
|
3
|
+
import { PlanFsPersistence, PlanRecord } from './plan-store.js';
|
|
4
|
+
export declare const GoalThreadStatusSchema: z.ZodEnum<["READY", "ACTIVE", "BLOCKED", "PAUSED", "DONE", "ABANDONED"]>;
|
|
5
|
+
export type GoalThreadStatus = z.infer<typeof GoalThreadStatusSchema>;
|
|
6
|
+
/**
|
|
7
|
+
* R3's two reasons for multiple root nodes, handled oppositely: `alternative` roots are competing
|
|
8
|
+
* guesses at one intent (resolving one abandons the others), `concurrent` roots are genuinely
|
|
9
|
+
* separate goals that coexist. Absent for a thread with no siblings needing disambiguation.
|
|
10
|
+
*/
|
|
11
|
+
export declare const SiblingRelationSchema: z.ZodEnum<["alternative", "concurrent"]>;
|
|
12
|
+
export type SiblingRelation = z.infer<typeof SiblingRelationSchema>;
|
|
13
|
+
declare const GoalTaskRecordSchema: z.ZodObject<{
|
|
14
|
+
id: z.ZodString;
|
|
15
|
+
description: z.ZodString;
|
|
16
|
+
depends_on: z.ZodArray<z.ZodString, "many">;
|
|
17
|
+
status: z.ZodEnum<["PENDING", "RUNNING", "COMPLETE", "FAILED", "BLOCKED", "HUMAN_REQUIRED"]>;
|
|
18
|
+
riskLevel: z.ZodOptional<z.ZodEnum<["LOW", "MEDIUM", "HIGH"]>>;
|
|
19
|
+
cancelled: z.ZodOptional<z.ZodBoolean>;
|
|
20
|
+
}, "strip", z.ZodTypeAny, {
|
|
21
|
+
id: string;
|
|
22
|
+
status: "BLOCKED" | "HUMAN_REQUIRED" | "PENDING" | "RUNNING" | "COMPLETE" | "FAILED";
|
|
23
|
+
description: string;
|
|
24
|
+
depends_on: string[];
|
|
25
|
+
riskLevel?: "HIGH" | "MEDIUM" | "LOW" | undefined;
|
|
26
|
+
cancelled?: boolean | undefined;
|
|
27
|
+
}, {
|
|
28
|
+
id: string;
|
|
29
|
+
status: "BLOCKED" | "HUMAN_REQUIRED" | "PENDING" | "RUNNING" | "COMPLETE" | "FAILED";
|
|
30
|
+
description: string;
|
|
31
|
+
depends_on: string[];
|
|
32
|
+
riskLevel?: "HIGH" | "MEDIUM" | "LOW" | undefined;
|
|
33
|
+
cancelled?: boolean | undefined;
|
|
34
|
+
}>;
|
|
35
|
+
export type GoalTaskRecord = z.infer<typeof GoalTaskRecordSchema>;
|
|
36
|
+
/**
|
|
37
|
+
* A persisted next-step suggestion (R7) — what next-step-proposer.ts's `proposeNextSteps()` yields
|
|
38
|
+
* for a thread that just reached DONE, minus `goalThreadId` (it lives on the thread that owns it).
|
|
39
|
+
* Advisory only: a suggestion is never a task on the thread and is never executed; the user acts on
|
|
40
|
+
* it, if at all, by simply asking. `promotion` records the confidence policy that admitted it
|
|
41
|
+
* (`auto` = high confidence, `pending_confirm` = medium); `session_only` (low confidence)
|
|
42
|
+
* suggestions are never persisted, so they don't appear here.
|
|
43
|
+
*/
|
|
44
|
+
export declare const ThreadSuggestionSchema: z.ZodObject<{
|
|
45
|
+
id: z.ZodString;
|
|
46
|
+
description: z.ZodString;
|
|
47
|
+
rationale: z.ZodString;
|
|
48
|
+
confidence: z.ZodEnum<["high", "medium", "low"]>;
|
|
49
|
+
promotion: z.ZodEnum<["auto", "pending_confirm", "session_only"]>;
|
|
50
|
+
createdAt: z.ZodString;
|
|
51
|
+
}, "strip", z.ZodTypeAny, {
|
|
52
|
+
rationale: string;
|
|
53
|
+
id: string;
|
|
54
|
+
confidence: "high" | "medium" | "low";
|
|
55
|
+
description: string;
|
|
56
|
+
createdAt: string;
|
|
57
|
+
promotion: "auto" | "pending_confirm" | "session_only";
|
|
58
|
+
}, {
|
|
59
|
+
rationale: string;
|
|
60
|
+
id: string;
|
|
61
|
+
confidence: "high" | "medium" | "low";
|
|
62
|
+
description: string;
|
|
63
|
+
createdAt: string;
|
|
64
|
+
promotion: "auto" | "pending_confirm" | "session_only";
|
|
65
|
+
}>;
|
|
66
|
+
export type ThreadSuggestion = z.infer<typeof ThreadSuggestionSchema>;
|
|
67
|
+
/**
|
|
68
|
+
* One node in the persisted goal DAG (R2). Absorbs PlanRecord's exact shape (Q1) — templateName
|
|
69
|
+
* through updatedAt below are unchanged in meaning from PlanRecord — plus the fields that make a
|
|
70
|
+
* thread schedulable: a stable `id` (PlanRecord had none, being a singleton), a scheduler-facing
|
|
71
|
+
* `status` distinct from `mode` (which is about this thread's own Tier-2 drafting/approval
|
|
72
|
+
* lifecycle, not whether the Scheduler may currently give it focus — see INV-40), and R3's sibling
|
|
73
|
+
* relation for when this thread is one of several roots.
|
|
74
|
+
*/
|
|
75
|
+
export declare const GoalThreadSchema: z.ZodObject<{
|
|
76
|
+
id: z.ZodString;
|
|
77
|
+
status: z.ZodEnum<["READY", "ACTIVE", "BLOCKED", "PAUSED", "DONE", "ABANDONED"]>;
|
|
78
|
+
relationToSiblings: z.ZodOptional<z.ZodEnum<["alternative", "concurrent"]>>;
|
|
79
|
+
/** Sibling GoalThread ids this one is grouped with as competing/concurrent roots (R3). */
|
|
80
|
+
siblingIds: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
81
|
+
/** templateName..updatedAt: absorbed from PlanRecord unchanged (Q1). */
|
|
82
|
+
templateName: z.ZodNullable<z.ZodString>;
|
|
83
|
+
successCriteria: z.ZodString;
|
|
84
|
+
rationale: z.ZodString;
|
|
85
|
+
tasks: z.ZodArray<z.ZodObject<{
|
|
86
|
+
id: z.ZodString;
|
|
87
|
+
description: z.ZodString;
|
|
88
|
+
depends_on: z.ZodArray<z.ZodString, "many">;
|
|
89
|
+
status: z.ZodEnum<["PENDING", "RUNNING", "COMPLETE", "FAILED", "BLOCKED", "HUMAN_REQUIRED"]>;
|
|
90
|
+
riskLevel: z.ZodOptional<z.ZodEnum<["LOW", "MEDIUM", "HIGH"]>>;
|
|
91
|
+
cancelled: z.ZodOptional<z.ZodBoolean>;
|
|
92
|
+
}, "strip", z.ZodTypeAny, {
|
|
93
|
+
id: string;
|
|
94
|
+
status: "BLOCKED" | "HUMAN_REQUIRED" | "PENDING" | "RUNNING" | "COMPLETE" | "FAILED";
|
|
95
|
+
description: string;
|
|
96
|
+
depends_on: string[];
|
|
97
|
+
riskLevel?: "HIGH" | "MEDIUM" | "LOW" | undefined;
|
|
98
|
+
cancelled?: boolean | undefined;
|
|
99
|
+
}, {
|
|
100
|
+
id: string;
|
|
101
|
+
status: "BLOCKED" | "HUMAN_REQUIRED" | "PENDING" | "RUNNING" | "COMPLETE" | "FAILED";
|
|
102
|
+
description: string;
|
|
103
|
+
depends_on: string[];
|
|
104
|
+
riskLevel?: "HIGH" | "MEDIUM" | "LOW" | undefined;
|
|
105
|
+
cancelled?: boolean | undefined;
|
|
106
|
+
}>, "many">;
|
|
107
|
+
mode: z.ZodEnum<["drafting", "awaiting_approval", "active", "done", "abandoned"]>;
|
|
108
|
+
reviewNotes: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
109
|
+
verifiedAt: z.ZodOptional<z.ZodString>;
|
|
110
|
+
executingOnPlan: z.ZodBoolean;
|
|
111
|
+
/** Advisory next steps proposed when this thread reached DONE — see ThreadSuggestionSchema. */
|
|
112
|
+
suggestions: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
113
|
+
id: z.ZodString;
|
|
114
|
+
description: z.ZodString;
|
|
115
|
+
rationale: z.ZodString;
|
|
116
|
+
confidence: z.ZodEnum<["high", "medium", "low"]>;
|
|
117
|
+
promotion: z.ZodEnum<["auto", "pending_confirm", "session_only"]>;
|
|
118
|
+
createdAt: z.ZodString;
|
|
119
|
+
}, "strip", z.ZodTypeAny, {
|
|
120
|
+
rationale: string;
|
|
121
|
+
id: string;
|
|
122
|
+
confidence: "high" | "medium" | "low";
|
|
123
|
+
description: string;
|
|
124
|
+
createdAt: string;
|
|
125
|
+
promotion: "auto" | "pending_confirm" | "session_only";
|
|
126
|
+
}, {
|
|
127
|
+
rationale: string;
|
|
128
|
+
id: string;
|
|
129
|
+
confidence: "high" | "medium" | "low";
|
|
130
|
+
description: string;
|
|
131
|
+
createdAt: string;
|
|
132
|
+
promotion: "auto" | "pending_confirm" | "session_only";
|
|
133
|
+
}>, "many">>;
|
|
134
|
+
trustApprovedSteps: z.ZodOptional<z.ZodBoolean>;
|
|
135
|
+
planApprovalId: z.ZodOptional<z.ZodString>;
|
|
136
|
+
createdAt: z.ZodString;
|
|
137
|
+
updatedAt: z.ZodString;
|
|
138
|
+
}, "strip", z.ZodTypeAny, {
|
|
139
|
+
rationale: string;
|
|
140
|
+
id: string;
|
|
141
|
+
status: "BLOCKED" | "READY" | "ACTIVE" | "PAUSED" | "DONE" | "ABANDONED";
|
|
142
|
+
tasks: {
|
|
143
|
+
id: string;
|
|
144
|
+
status: "BLOCKED" | "HUMAN_REQUIRED" | "PENDING" | "RUNNING" | "COMPLETE" | "FAILED";
|
|
145
|
+
description: string;
|
|
146
|
+
depends_on: string[];
|
|
147
|
+
riskLevel?: "HIGH" | "MEDIUM" | "LOW" | undefined;
|
|
148
|
+
cancelled?: boolean | undefined;
|
|
149
|
+
}[];
|
|
150
|
+
successCriteria: string;
|
|
151
|
+
mode: "active" | "done" | "drafting" | "awaiting_approval" | "abandoned";
|
|
152
|
+
createdAt: string;
|
|
153
|
+
templateName: string | null;
|
|
154
|
+
executingOnPlan: boolean;
|
|
155
|
+
updatedAt: string;
|
|
156
|
+
relationToSiblings?: "alternative" | "concurrent" | undefined;
|
|
157
|
+
siblingIds?: string[] | undefined;
|
|
158
|
+
reviewNotes?: string[] | undefined;
|
|
159
|
+
verifiedAt?: string | undefined;
|
|
160
|
+
suggestions?: {
|
|
161
|
+
rationale: string;
|
|
162
|
+
id: string;
|
|
163
|
+
confidence: "high" | "medium" | "low";
|
|
164
|
+
description: string;
|
|
165
|
+
createdAt: string;
|
|
166
|
+
promotion: "auto" | "pending_confirm" | "session_only";
|
|
167
|
+
}[] | undefined;
|
|
168
|
+
trustApprovedSteps?: boolean | undefined;
|
|
169
|
+
planApprovalId?: string | undefined;
|
|
170
|
+
}, {
|
|
171
|
+
rationale: string;
|
|
172
|
+
id: string;
|
|
173
|
+
status: "BLOCKED" | "READY" | "ACTIVE" | "PAUSED" | "DONE" | "ABANDONED";
|
|
174
|
+
tasks: {
|
|
175
|
+
id: string;
|
|
176
|
+
status: "BLOCKED" | "HUMAN_REQUIRED" | "PENDING" | "RUNNING" | "COMPLETE" | "FAILED";
|
|
177
|
+
description: string;
|
|
178
|
+
depends_on: string[];
|
|
179
|
+
riskLevel?: "HIGH" | "MEDIUM" | "LOW" | undefined;
|
|
180
|
+
cancelled?: boolean | undefined;
|
|
181
|
+
}[];
|
|
182
|
+
successCriteria: string;
|
|
183
|
+
mode: "active" | "done" | "drafting" | "awaiting_approval" | "abandoned";
|
|
184
|
+
createdAt: string;
|
|
185
|
+
templateName: string | null;
|
|
186
|
+
executingOnPlan: boolean;
|
|
187
|
+
updatedAt: string;
|
|
188
|
+
relationToSiblings?: "alternative" | "concurrent" | undefined;
|
|
189
|
+
siblingIds?: string[] | undefined;
|
|
190
|
+
reviewNotes?: string[] | undefined;
|
|
191
|
+
verifiedAt?: string | undefined;
|
|
192
|
+
suggestions?: {
|
|
193
|
+
rationale: string;
|
|
194
|
+
id: string;
|
|
195
|
+
confidence: "high" | "medium" | "low";
|
|
196
|
+
description: string;
|
|
197
|
+
createdAt: string;
|
|
198
|
+
promotion: "auto" | "pending_confirm" | "session_only";
|
|
199
|
+
}[] | undefined;
|
|
200
|
+
trustApprovedSteps?: boolean | undefined;
|
|
201
|
+
planApprovalId?: string | undefined;
|
|
202
|
+
}>;
|
|
203
|
+
export type GoalThread = z.infer<typeof GoalThreadSchema>;
|
|
204
|
+
/**
|
|
205
|
+
* The persisted DAG itself (R2): `threads` is the full set of goal threads known this session,
|
|
206
|
+
* `activeThreadId` is the O(1) current-focus pointer every downstream mechanism (classifier,
|
|
207
|
+
* Scheduler, next-step proposer, Tier-2 scoping) needs answerable without a graph traversal —
|
|
208
|
+
* see the "current-focus / task→goal linkage primitive" gap this plan's design brief calls out.
|
|
209
|
+
* INV-38/39 (at most one ACTIVE thread, Scheduler is the sole writer of this pointer) are enforced
|
|
210
|
+
* starting Phase 5, not here — this phase only defines the shape.
|
|
211
|
+
*/
|
|
212
|
+
export declare const GoalGraphRecordSchema: z.ZodObject<{
|
|
213
|
+
threads: z.ZodArray<z.ZodObject<{
|
|
214
|
+
id: z.ZodString;
|
|
215
|
+
status: z.ZodEnum<["READY", "ACTIVE", "BLOCKED", "PAUSED", "DONE", "ABANDONED"]>;
|
|
216
|
+
relationToSiblings: z.ZodOptional<z.ZodEnum<["alternative", "concurrent"]>>;
|
|
217
|
+
/** Sibling GoalThread ids this one is grouped with as competing/concurrent roots (R3). */
|
|
218
|
+
siblingIds: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
219
|
+
/** templateName..updatedAt: absorbed from PlanRecord unchanged (Q1). */
|
|
220
|
+
templateName: z.ZodNullable<z.ZodString>;
|
|
221
|
+
successCriteria: z.ZodString;
|
|
222
|
+
rationale: z.ZodString;
|
|
223
|
+
tasks: z.ZodArray<z.ZodObject<{
|
|
224
|
+
id: z.ZodString;
|
|
225
|
+
description: z.ZodString;
|
|
226
|
+
depends_on: z.ZodArray<z.ZodString, "many">;
|
|
227
|
+
status: z.ZodEnum<["PENDING", "RUNNING", "COMPLETE", "FAILED", "BLOCKED", "HUMAN_REQUIRED"]>;
|
|
228
|
+
riskLevel: z.ZodOptional<z.ZodEnum<["LOW", "MEDIUM", "HIGH"]>>;
|
|
229
|
+
cancelled: z.ZodOptional<z.ZodBoolean>;
|
|
230
|
+
}, "strip", z.ZodTypeAny, {
|
|
231
|
+
id: string;
|
|
232
|
+
status: "BLOCKED" | "HUMAN_REQUIRED" | "PENDING" | "RUNNING" | "COMPLETE" | "FAILED";
|
|
233
|
+
description: string;
|
|
234
|
+
depends_on: string[];
|
|
235
|
+
riskLevel?: "HIGH" | "MEDIUM" | "LOW" | undefined;
|
|
236
|
+
cancelled?: boolean | undefined;
|
|
237
|
+
}, {
|
|
238
|
+
id: string;
|
|
239
|
+
status: "BLOCKED" | "HUMAN_REQUIRED" | "PENDING" | "RUNNING" | "COMPLETE" | "FAILED";
|
|
240
|
+
description: string;
|
|
241
|
+
depends_on: string[];
|
|
242
|
+
riskLevel?: "HIGH" | "MEDIUM" | "LOW" | undefined;
|
|
243
|
+
cancelled?: boolean | undefined;
|
|
244
|
+
}>, "many">;
|
|
245
|
+
mode: z.ZodEnum<["drafting", "awaiting_approval", "active", "done", "abandoned"]>;
|
|
246
|
+
reviewNotes: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
247
|
+
verifiedAt: z.ZodOptional<z.ZodString>;
|
|
248
|
+
executingOnPlan: z.ZodBoolean;
|
|
249
|
+
/** Advisory next steps proposed when this thread reached DONE — see ThreadSuggestionSchema. */
|
|
250
|
+
suggestions: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
251
|
+
id: z.ZodString;
|
|
252
|
+
description: z.ZodString;
|
|
253
|
+
rationale: z.ZodString;
|
|
254
|
+
confidence: z.ZodEnum<["high", "medium", "low"]>;
|
|
255
|
+
promotion: z.ZodEnum<["auto", "pending_confirm", "session_only"]>;
|
|
256
|
+
createdAt: z.ZodString;
|
|
257
|
+
}, "strip", z.ZodTypeAny, {
|
|
258
|
+
rationale: string;
|
|
259
|
+
id: string;
|
|
260
|
+
confidence: "high" | "medium" | "low";
|
|
261
|
+
description: string;
|
|
262
|
+
createdAt: string;
|
|
263
|
+
promotion: "auto" | "pending_confirm" | "session_only";
|
|
264
|
+
}, {
|
|
265
|
+
rationale: string;
|
|
266
|
+
id: string;
|
|
267
|
+
confidence: "high" | "medium" | "low";
|
|
268
|
+
description: string;
|
|
269
|
+
createdAt: string;
|
|
270
|
+
promotion: "auto" | "pending_confirm" | "session_only";
|
|
271
|
+
}>, "many">>;
|
|
272
|
+
trustApprovedSteps: z.ZodOptional<z.ZodBoolean>;
|
|
273
|
+
planApprovalId: z.ZodOptional<z.ZodString>;
|
|
274
|
+
createdAt: z.ZodString;
|
|
275
|
+
updatedAt: z.ZodString;
|
|
276
|
+
}, "strip", z.ZodTypeAny, {
|
|
277
|
+
rationale: string;
|
|
278
|
+
id: string;
|
|
279
|
+
status: "BLOCKED" | "READY" | "ACTIVE" | "PAUSED" | "DONE" | "ABANDONED";
|
|
280
|
+
tasks: {
|
|
281
|
+
id: string;
|
|
282
|
+
status: "BLOCKED" | "HUMAN_REQUIRED" | "PENDING" | "RUNNING" | "COMPLETE" | "FAILED";
|
|
283
|
+
description: string;
|
|
284
|
+
depends_on: string[];
|
|
285
|
+
riskLevel?: "HIGH" | "MEDIUM" | "LOW" | undefined;
|
|
286
|
+
cancelled?: boolean | undefined;
|
|
287
|
+
}[];
|
|
288
|
+
successCriteria: string;
|
|
289
|
+
mode: "active" | "done" | "drafting" | "awaiting_approval" | "abandoned";
|
|
290
|
+
createdAt: string;
|
|
291
|
+
templateName: string | null;
|
|
292
|
+
executingOnPlan: boolean;
|
|
293
|
+
updatedAt: string;
|
|
294
|
+
relationToSiblings?: "alternative" | "concurrent" | undefined;
|
|
295
|
+
siblingIds?: string[] | undefined;
|
|
296
|
+
reviewNotes?: string[] | undefined;
|
|
297
|
+
verifiedAt?: string | undefined;
|
|
298
|
+
suggestions?: {
|
|
299
|
+
rationale: string;
|
|
300
|
+
id: string;
|
|
301
|
+
confidence: "high" | "medium" | "low";
|
|
302
|
+
description: string;
|
|
303
|
+
createdAt: string;
|
|
304
|
+
promotion: "auto" | "pending_confirm" | "session_only";
|
|
305
|
+
}[] | undefined;
|
|
306
|
+
trustApprovedSteps?: boolean | undefined;
|
|
307
|
+
planApprovalId?: string | undefined;
|
|
308
|
+
}, {
|
|
309
|
+
rationale: string;
|
|
310
|
+
id: string;
|
|
311
|
+
status: "BLOCKED" | "READY" | "ACTIVE" | "PAUSED" | "DONE" | "ABANDONED";
|
|
312
|
+
tasks: {
|
|
313
|
+
id: string;
|
|
314
|
+
status: "BLOCKED" | "HUMAN_REQUIRED" | "PENDING" | "RUNNING" | "COMPLETE" | "FAILED";
|
|
315
|
+
description: string;
|
|
316
|
+
depends_on: string[];
|
|
317
|
+
riskLevel?: "HIGH" | "MEDIUM" | "LOW" | undefined;
|
|
318
|
+
cancelled?: boolean | undefined;
|
|
319
|
+
}[];
|
|
320
|
+
successCriteria: string;
|
|
321
|
+
mode: "active" | "done" | "drafting" | "awaiting_approval" | "abandoned";
|
|
322
|
+
createdAt: string;
|
|
323
|
+
templateName: string | null;
|
|
324
|
+
executingOnPlan: boolean;
|
|
325
|
+
updatedAt: string;
|
|
326
|
+
relationToSiblings?: "alternative" | "concurrent" | undefined;
|
|
327
|
+
siblingIds?: string[] | undefined;
|
|
328
|
+
reviewNotes?: string[] | undefined;
|
|
329
|
+
verifiedAt?: string | undefined;
|
|
330
|
+
suggestions?: {
|
|
331
|
+
rationale: string;
|
|
332
|
+
id: string;
|
|
333
|
+
confidence: "high" | "medium" | "low";
|
|
334
|
+
description: string;
|
|
335
|
+
createdAt: string;
|
|
336
|
+
promotion: "auto" | "pending_confirm" | "session_only";
|
|
337
|
+
}[] | undefined;
|
|
338
|
+
trustApprovedSteps?: boolean | undefined;
|
|
339
|
+
planApprovalId?: string | undefined;
|
|
340
|
+
}>, "many">;
|
|
341
|
+
activeThreadId: z.ZodNullable<z.ZodString>;
|
|
342
|
+
createdAt: z.ZodString;
|
|
343
|
+
updatedAt: z.ZodString;
|
|
344
|
+
}, "strip", z.ZodTypeAny, {
|
|
345
|
+
createdAt: string;
|
|
346
|
+
updatedAt: string;
|
|
347
|
+
threads: {
|
|
348
|
+
rationale: string;
|
|
349
|
+
id: string;
|
|
350
|
+
status: "BLOCKED" | "READY" | "ACTIVE" | "PAUSED" | "DONE" | "ABANDONED";
|
|
351
|
+
tasks: {
|
|
352
|
+
id: string;
|
|
353
|
+
status: "BLOCKED" | "HUMAN_REQUIRED" | "PENDING" | "RUNNING" | "COMPLETE" | "FAILED";
|
|
354
|
+
description: string;
|
|
355
|
+
depends_on: string[];
|
|
356
|
+
riskLevel?: "HIGH" | "MEDIUM" | "LOW" | undefined;
|
|
357
|
+
cancelled?: boolean | undefined;
|
|
358
|
+
}[];
|
|
359
|
+
successCriteria: string;
|
|
360
|
+
mode: "active" | "done" | "drafting" | "awaiting_approval" | "abandoned";
|
|
361
|
+
createdAt: string;
|
|
362
|
+
templateName: string | null;
|
|
363
|
+
executingOnPlan: boolean;
|
|
364
|
+
updatedAt: string;
|
|
365
|
+
relationToSiblings?: "alternative" | "concurrent" | undefined;
|
|
366
|
+
siblingIds?: string[] | undefined;
|
|
367
|
+
reviewNotes?: string[] | undefined;
|
|
368
|
+
verifiedAt?: string | undefined;
|
|
369
|
+
suggestions?: {
|
|
370
|
+
rationale: string;
|
|
371
|
+
id: string;
|
|
372
|
+
confidence: "high" | "medium" | "low";
|
|
373
|
+
description: string;
|
|
374
|
+
createdAt: string;
|
|
375
|
+
promotion: "auto" | "pending_confirm" | "session_only";
|
|
376
|
+
}[] | undefined;
|
|
377
|
+
trustApprovedSteps?: boolean | undefined;
|
|
378
|
+
planApprovalId?: string | undefined;
|
|
379
|
+
}[];
|
|
380
|
+
activeThreadId: string | null;
|
|
381
|
+
}, {
|
|
382
|
+
createdAt: string;
|
|
383
|
+
updatedAt: string;
|
|
384
|
+
threads: {
|
|
385
|
+
rationale: string;
|
|
386
|
+
id: string;
|
|
387
|
+
status: "BLOCKED" | "READY" | "ACTIVE" | "PAUSED" | "DONE" | "ABANDONED";
|
|
388
|
+
tasks: {
|
|
389
|
+
id: string;
|
|
390
|
+
status: "BLOCKED" | "HUMAN_REQUIRED" | "PENDING" | "RUNNING" | "COMPLETE" | "FAILED";
|
|
391
|
+
description: string;
|
|
392
|
+
depends_on: string[];
|
|
393
|
+
riskLevel?: "HIGH" | "MEDIUM" | "LOW" | undefined;
|
|
394
|
+
cancelled?: boolean | undefined;
|
|
395
|
+
}[];
|
|
396
|
+
successCriteria: string;
|
|
397
|
+
mode: "active" | "done" | "drafting" | "awaiting_approval" | "abandoned";
|
|
398
|
+
createdAt: string;
|
|
399
|
+
templateName: string | null;
|
|
400
|
+
executingOnPlan: boolean;
|
|
401
|
+
updatedAt: string;
|
|
402
|
+
relationToSiblings?: "alternative" | "concurrent" | undefined;
|
|
403
|
+
siblingIds?: string[] | undefined;
|
|
404
|
+
reviewNotes?: string[] | undefined;
|
|
405
|
+
verifiedAt?: string | undefined;
|
|
406
|
+
suggestions?: {
|
|
407
|
+
rationale: string;
|
|
408
|
+
id: string;
|
|
409
|
+
confidence: "high" | "medium" | "low";
|
|
410
|
+
description: string;
|
|
411
|
+
createdAt: string;
|
|
412
|
+
promotion: "auto" | "pending_confirm" | "session_only";
|
|
413
|
+
}[] | undefined;
|
|
414
|
+
trustApprovedSteps?: boolean | undefined;
|
|
415
|
+
planApprovalId?: string | undefined;
|
|
416
|
+
}[];
|
|
417
|
+
activeThreadId: string | null;
|
|
418
|
+
}>;
|
|
419
|
+
export type GoalGraphRecord = z.infer<typeof GoalGraphRecordSchema>;
|
|
420
|
+
/** Same `{backend, workspaceRoot}` pair as PlanFsPersistence — a goal graph and its session's plan file live in the same workspace. */
|
|
421
|
+
export type GoalGraphFsPersistence = PlanFsPersistence;
|
|
422
|
+
/**
|
|
423
|
+
* Wraps an existing `PlanRecord` into the single `GoalThread` it becomes under Q1's "absorb, don't
|
|
424
|
+
* duplicate" resolution — nothing in `plan`'s own fields is dropped.
|
|
425
|
+
*/
|
|
426
|
+
export declare function createGoalThreadFromPlanRecord(plan: PlanRecord, id?: string): GoalThread;
|
|
427
|
+
/** A fresh, empty goal graph — no threads, nothing active. */
|
|
428
|
+
export declare function createEmptyGoalGraphRecord(): GoalGraphRecord;
|
|
429
|
+
/** Wraps a single pre-existing `PlanRecord` into a one-thread `GoalGraphRecord` — the migration path's output shape. */
|
|
430
|
+
export declare function createGoalGraphRecordFromPlanRecord(plan: PlanRecord): GoalGraphRecord;
|
|
431
|
+
/**
|
|
432
|
+
* R2's O(1) locatability primitive, live as of Phase 4: the currently-focused thread, found by a
|
|
433
|
+
* direct field lookup (`activeThreadId`), never a graph traversal. Defensive about a transient
|
|
434
|
+
* inconsistency Phase 4 can produce (see goal-graph-reconcile.ts): a NEW_GOAL/CANCEL_CURRENT
|
|
435
|
+
* steering message can pause/abandon the thread `activeThreadId` still points at, ahead of Phase
|
|
436
|
+
* 5's Scheduler ever reassigning that pointer (INV-39 — only the Scheduler writes it) — so this
|
|
437
|
+
* only returns a thread whose own `status` is still genuinely `ACTIVE`, not just pointed-at.
|
|
438
|
+
*/
|
|
439
|
+
export declare function getActiveThread(record: GoalGraphRecord): GoalThread | null;
|
|
440
|
+
/** R2's task→goal parent-link query — every task belonging to `goalId`, a direct field filter, never a traversal. */
|
|
441
|
+
export declare function tasksForGoal(record: GoalGraphRecord, goalId: string): GoalTaskRecord[];
|
|
442
|
+
/**
|
|
443
|
+
* Every thread the Scheduler could hand focus to right now (Phase 5): READY, and not mid-Tier-2
|
|
444
|
+
* drafting or awaiting approval (INV-40). A drafting thread's `status` is READY (see
|
|
445
|
+
* createGoalThreadFromPlanRecord / mintConcurrentReadyThread), so the exclusion has to look at
|
|
446
|
+
* `mode`, not just `status` — until 2026-09-23 this filtered on status alone, which quietly made
|
|
447
|
+
* INV-40 false: a thread minted by a NEW_GOAL steering message (mode 'drafting') was eligible for
|
|
448
|
+
* focus. The identity matcher (goal-thread-identity.ts) is what adopts such a thread, by matching
|
|
449
|
+
* a real turn to it and promoting its mode to 'active'.
|
|
450
|
+
*/
|
|
451
|
+
export declare function readyThreads(record: GoalGraphRecord): GoalThread[];
|
|
452
|
+
/**
|
|
453
|
+
* R4's NEW_GOAL branch (both IMMEDIATE and DEFERRED collapse to this in Phase 4 — see
|
|
454
|
+
* check-caller-updates.ts's cancel_current sibling doc comment and the plan's resolved
|
|
455
|
+
* "ACTIVE-pointer write authority" decision: Tier-1 never writes `activeThreadId` itself, it only
|
|
456
|
+
* pauses the old thread and mints the new one READY; Phase 5's Scheduler decides what becomes
|
|
457
|
+
* ACTIVE next). `pauseThreadId`, when given and currently ACTIVE, transitions to PAUSED and is
|
|
458
|
+
* linked to the new thread as a `concurrent` sibling (R3) — never `alternative`, since a NEW_GOAL
|
|
459
|
+
* is a genuinely separate objective, not a competing guess at the same one.
|
|
460
|
+
*/
|
|
461
|
+
export declare function mintConcurrentReadyThread(record: GoalGraphRecord, description: string, pauseThreadId?: string | null): GoalGraphRecord;
|
|
462
|
+
/** R4's CANCEL_CURRENT branch — marks a thread ABANDONED. Kept for audit trail, never removed from `threads`. */
|
|
463
|
+
export declare function abandonThread(record: GoalGraphRecord, threadId: string): GoalGraphRecord;
|
|
464
|
+
export declare function saveGoalGraphRecord(memory: MemoryAdapter, sessionId: string, record: GoalGraphRecord, fsPersistence?: GoalGraphFsPersistence): Promise<void>;
|
|
465
|
+
/**
|
|
466
|
+
* Loads `sessionId`'s goal graph, migrating a pre-existing `PlanRecord` in place the first time
|
|
467
|
+
* this is called for a session that predates this mechanism (P5-equivalent non-destructive
|
|
468
|
+
* discipline — same as `migrateFact`/`migratePlanRecord`: the old record's data is never silently
|
|
469
|
+
* dropped, just re-shaped and persisted once under the new key). Every call after that first one
|
|
470
|
+
* finds the migrated `GoalGraphRecord` directly and never re-touches the legacy `PlanRecord`.
|
|
471
|
+
*
|
|
472
|
+
* When `fsPersistence` is configured and its goal-graph JSON file exists, that file wins over the
|
|
473
|
+
* Dexie/State-tier record, mirroring `loadPlanRecord`'s own fs-file-wins-then-reconcile behavior
|
|
474
|
+
* (INV-33's discipline, applied here too: the result is written back into `memory` so the two
|
|
475
|
+
* never stay silently split).
|
|
476
|
+
*/
|
|
477
|
+
export declare function loadGoalGraphRecord(memory: MemoryAdapter, sessionId: string, fsPersistence?: GoalGraphFsPersistence): Promise<GoalGraphRecord | null>;
|
|
478
|
+
/**
|
|
479
|
+
* Appends advisory `suggestions` to `threadId`, skipping any whose description (case-insensitive,
|
|
480
|
+
* trimmed) the thread already carries — proposing again for the same DONE thread must not stack
|
|
481
|
+
* duplicates. `session_only` suggestions are dropped here (low confidence is advisory for the turn
|
|
482
|
+
* that produced it, never persisted). A `threadId` not present in `record.threads` is a no-op.
|
|
483
|
+
*/
|
|
484
|
+
export declare function addThreadSuggestions(record: GoalGraphRecord, threadId: string, suggestions: ThreadSuggestion[]): GoalGraphRecord;
|
|
485
|
+
export {};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure logic backing the hierarchical-goal-tree mechanism's Tier 1.5 gate — the next-step
|
|
3
|
+
* proposer (Phase 6, `next-step-proposer.ts`) — see
|
|
4
|
+
* plans/hierarchical_goal_tree_and_steering_plan.html. Split out into its own file/flag rather
|
|
5
|
+
* than folded into `goal-graph-flag.ts`, matching this codebase's one-flag-per-file convention
|
|
6
|
+
* (`one-loop-flag.ts`/`ask-mode-flag.ts`/`plan-mode-flag.ts`/`goal-graph-flag.ts`) and the plan's
|
|
7
|
+
* own "Rollout discipline" resolution (2026-09-22): gated independently of `goalGraphMode` since a
|
|
8
|
+
* regression in the next-step proposer shouldn't block Tier 0/1 (the steering channel, classifier,
|
|
9
|
+
* persistent `GoalGraphRecord`).
|
|
10
|
+
*
|
|
11
|
+
* As of Phase 8, threaded through `AssistantConfig` exactly like `goal-graph-flag.ts`:
|
|
12
|
+
* `goalGraphSuggestMode` is a real config field with `/config set` support, a
|
|
13
|
+
* `VITE_ASSISTANT_GOAL_GRAPH_SUGGEST` build-time line in chat-ui's browser-config.ts, and
|
|
14
|
+
* flag-chain resolution tests (cli-config.test.ts, browser-config.test.ts) — resolved via
|
|
15
|
+
* `normalizeGoalGraphSuggestMode` below, mirroring `normalizeGoalGraphMode` exactly. No production
|
|
16
|
+
* call site reads `config.goalGraphSuggestMode` yet (`next-step-proposer.ts`'s
|
|
17
|
+
* `proposeNextSteps()` still takes its `suggestMode` argument directly from whichever caller wires
|
|
18
|
+
* it in, and no caller does that yet — see that file's own notes), so this remains inert beyond
|
|
19
|
+
* the config seam itself.
|
|
20
|
+
*
|
|
21
|
+
* Default OFF ('disabled'): `next-step-proposer.ts`'s `proposeNextSteps()` returns `[]` without
|
|
22
|
+
* making any LLM call, so a flag-off session sees zero behavior change (INV-43).
|
|
23
|
+
*/
|
|
24
|
+
export type GoalGraphSuggestMode = 'enabled' | 'disabled';
|
|
25
|
+
export declare const DEFAULT_GOAL_GRAPH_SUGGEST_MODE: GoalGraphSuggestMode;
|
|
26
|
+
/** See isGoalGraphEnabled (goal-graph-flag.ts) — same undefined-means-package-default rule. */
|
|
27
|
+
export declare function isGoalGraphSuggestEnabled(mode: GoalGraphSuggestMode | undefined): boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Same signature/typo-tolerance-with-a-warning convention as `normalizeGoalGraphMode`: an unset or
|
|
30
|
+
* empty value falls back to the default silently, an unrecognized non-empty value falls back with
|
|
31
|
+
* a startup warning naming `varName`.
|
|
32
|
+
*/
|
|
33
|
+
export declare function normalizeGoalGraphSuggestMode(raw: string | undefined, varName?: string): GoalGraphSuggestMode;
|
|
34
|
+
export declare function resolveGoalGraphSuggestMode(env: NodeJS.ProcessEnv): GoalGraphSuggestMode;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { ILLMClient, TokenUsage } from '@buildaharness/runtime';
|
|
2
|
+
export interface GoalCandidate {
|
|
3
|
+
id: string;
|
|
4
|
+
/** A short description of the goal's intent — e.g. a GoalThread's successCriteria/rationale — used as the identity anchor for matching, not its full task list. */
|
|
5
|
+
description: string;
|
|
6
|
+
}
|
|
7
|
+
export interface GoalIdentityMatchResult {
|
|
8
|
+
/** The existing candidate this message's intent matches, or null when nothing matches — including on ambiguity, see `ambiguous`. Always one of `candidates`' ids, never a dangling/unrecognized one. */
|
|
9
|
+
matchedGoalId: string | null;
|
|
10
|
+
/** True when more than one candidate plausibly matches and the model couldn't confidently pick a single one. matchedGoalId is always null in this case — never guess a specific attachment, same fail-safe direction as no-match at all. */
|
|
11
|
+
ambiguous: boolean;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* One bounded LLM call per incoming steering message, only when there's at least one existing
|
|
15
|
+
* goal thread to match against. Falls back to "no match, treat as new" — the same fail-safe
|
|
16
|
+
* direction as an unrecognized/dangling id or genuine ambiguity — on any parse failure or LLM
|
|
17
|
+
* error, matching this codebase's other LLM-backed classifiers (classifyTurnIntent,
|
|
18
|
+
* checkForContradictions): a missed match costs nothing worse than spinning up an extra
|
|
19
|
+
* `concurrent` goal root, never a wrong attachment to the wrong thread.
|
|
20
|
+
*/
|
|
21
|
+
export declare function matchGoalIdentity(message: string, candidates: GoalCandidate[], llmClient: ILLMClient, model?: string, onUsage?: (usage: TokenUsage) => void): Promise<GoalIdentityMatchResult>;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { ILLMClient, MemoryAdapter, TokenUsage } from '@buildaharness/runtime';
|
|
2
|
+
import { GoalGraphFsPersistence } from './goal-graph-store.js';
|
|
3
|
+
/**
|
|
4
|
+
* Cross-turn goal identity, wired into the turn (plans/hierarchical_goal_tree_and_steering_plan.html
|
|
5
|
+
* Phase 2's matcher, unused until now): decides which goal thread a full turn belongs to, so a
|
|
6
|
+
* message that continues an earlier goal gets that goal's thread back in focus (with its paused
|
|
7
|
+
* evidence intact) and a message about something new starts its own thread. This is what makes
|
|
8
|
+
* the graph fill in for ordinary conversation; before it, threads only came from a session plan or
|
|
9
|
+
* a NEW_GOAL steering message.
|
|
10
|
+
*
|
|
11
|
+
* - candidates: every thread that is not finished (READY / ACTIVE / PAUSED / BLOCKED — including a
|
|
12
|
+
* placeholder a NEW_GOAL steering message minted, which is how that deferred ask finds its
|
|
13
|
+
* thread again when it runs as its own turn). DONE and ABANDONED goals are not reopened.
|
|
14
|
+
* - matched → `focusThread` (the Scheduler's single write path, INV-39); a BLOCKED match keeps
|
|
15
|
+
* its status but is still the thread this turn's evidence lands on.
|
|
16
|
+
* - no match or ambiguous → `startThread`. Ambiguity is never guessed into an attachment
|
|
17
|
+
* (same fail-safe as the matcher: a missed match costs an extra thread, a wrong one costs work
|
|
18
|
+
* landing on the wrong goal).
|
|
19
|
+
* - no candidates → `startThread` with no LLM call at all.
|
|
20
|
+
*
|
|
21
|
+
* Best-effort by construction: any failure (memory, matcher) resolves to "no thread" for this turn,
|
|
22
|
+
* exactly as if the goal graph were off. Returns the thread id this turn's evidence should land on.
|
|
23
|
+
*/
|
|
24
|
+
export declare function resolveTurnGoalThread(params: {
|
|
25
|
+
userMessage: string;
|
|
26
|
+
sessionId: string;
|
|
27
|
+
memory: MemoryAdapter;
|
|
28
|
+
llmClient: ILLMClient;
|
|
29
|
+
model?: string;
|
|
30
|
+
onUsage?: (usage: TokenUsage) => void;
|
|
31
|
+
fsPersistence?: GoalGraphFsPersistence;
|
|
32
|
+
}): Promise<string | undefined>;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { GoalGraphRecord, GoalThread } from './goal-graph-store.js';
|
|
2
|
+
/**
|
|
3
|
+
* Phase 5 of plans/hierarchical_goal_tree_and_steering_plan.html — the Scheduler: the sole writer
|
|
4
|
+
* of `GoalGraphRecord.activeThreadId` (INV-39), enforcing single-focus v1 (INV-38 — at most one
|
|
5
|
+
* `ACTIVE` thread at a time) and READY-only selection that excludes anything mid-Tier-2-drafting
|
|
6
|
+
* (INV-40, via `readyThreads()`'s own `status`+`mode` filter).
|
|
7
|
+
*
|
|
8
|
+
* Per the plan's resolved "ACTIVE-pointer write authority" decision, IMMEDIATE and DEFERRED
|
|
9
|
+
* steering both call this *same* selection function with the *same* exclusion rules — the only
|
|
10
|
+
* difference is *when* a caller invokes it: `goal-graph-reconcile.ts`'s NEW_GOAL branch calls it
|
|
11
|
+
* synchronously, this same iteration, for IMMEDIATE; DEFERRED leaves it for the next natural pass
|
|
12
|
+
* (today, `assistant.ts`'s own per-turn call at turn-dispatch, gated on `options.steeringChannel`
|
|
13
|
+
* being present — the natural turn-scoped analog of "off a control_state BLOCKED trigger", since
|
|
14
|
+
* TaskGraph loading/swapping is itself a turn-scoped operation, not a mid-iteration one).
|
|
15
|
+
*/
|
|
16
|
+
export interface SchedulerSelectionResult {
|
|
17
|
+
record: GoalGraphRecord;
|
|
18
|
+
activeThreadId: string | null;
|
|
19
|
+
switched: boolean;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* The Scheduler's one selection pass. If a thread is already genuinely `ACTIVE`
|
|
23
|
+
* (`getActiveThread` — defensively re-checks `status`, not just the pointer), it keeps focus:
|
|
24
|
+
* v1 is cooperative, not preemptive by default (Q6) — a still-workable ACTIVE thread is never
|
|
25
|
+
* bumped just because other READY threads exist. Only when there is *no* valid ACTIVE thread
|
|
26
|
+
* (null pointer, or the pointed-at thread's own status has moved on — PAUSED/BLOCKED/DONE/
|
|
27
|
+
* ABANDONED, e.g. after a NEW_GOAL/CANCEL_CURRENT steering event paused or abandoned it) does it
|
|
28
|
+
* pick the next eligible candidate, FIFO by `createdAt`. No eligible candidate leaves the pointer
|
|
29
|
+
* exactly as it was — never invents a switch out of thin air.
|
|
30
|
+
*/
|
|
31
|
+
export declare function selectActiveThread(record: GoalGraphRecord): SchedulerSelectionResult;
|
|
32
|
+
/**
|
|
33
|
+
* IMMEDIATE steering's synchronous hook (see the header comment): forces `threadId` to become
|
|
34
|
+
* `ACTIVE` right now if — and only if — it's actually eligible (`READY`, not mid-drafting) per the
|
|
35
|
+
* exact same rules `selectActiveThread` itself enforces. An ineligible or unknown `threadId` (e.g.
|
|
36
|
+
* the just-minted thread is still `mode: 'drafting'`, per `mintConcurrentReadyThread` — real,
|
|
37
|
+
* common case: Tier-2 hasn't decomposed it into runnable tasks yet) falls back to the ordinary
|
|
38
|
+
* `selectActiveThread` pass rather than force-activating something not actually runnable —
|
|
39
|
+
* "same selection function, same exclusion rules either way" holds even for the forced path.
|
|
40
|
+
*/
|
|
41
|
+
export declare function forceActivateThread(record: GoalGraphRecord, threadId: string): SchedulerSelectionResult;
|
|
42
|
+
/**
|
|
43
|
+
* Gives `threadId` focus for the turn that is about to run on it — the identity matcher's "this
|
|
44
|
+
* message continues that goal" outcome. Unlike `forceActivateThread` (which only ever activates a
|
|
45
|
+
* thread the Scheduler already considers eligible), this is the deliberate, user-driven switch:
|
|
46
|
+
* the message itself is the evidence, so a READY, PAUSED or still-drafting thread is promoted
|
|
47
|
+
* (a drafting thread — e.g. one a NEW_GOAL steering message minted — becomes `mode: 'active'`,
|
|
48
|
+
* because a real turn is now executing it) and whatever else was ACTIVE is paused with its
|
|
49
|
+
* evidence intact (INV-42). Still the Scheduler's single write path to the ACTIVE pointer (INV-39).
|
|
50
|
+
* A BLOCKED, DONE, ABANDONED or already-ACTIVE thread is left exactly as it is (`switched: false`):
|
|
51
|
+
* blocked work isn't silently unblocked by a mention, and finished work isn't reopened.
|
|
52
|
+
*/
|
|
53
|
+
export declare function focusThread(record: GoalGraphRecord, threadId: string): SchedulerSelectionResult;
|
|
54
|
+
/**
|
|
55
|
+
* Starts a brand-new goal thread that takes focus immediately — the identity matcher's "this is a
|
|
56
|
+
* new goal" outcome (no existing thread matches, or it was ambiguous). The description is the
|
|
57
|
+
* message itself, kept to one short line. Any thread that was ACTIVE is paused and linked as a
|
|
58
|
+
* `concurrent` sibling (R3), never discarded (INV-42). `tasks` starts empty and is adopted from the
|
|
59
|
+
* harness's task graph once the turn runs (see syncThreadFromTaskGraph).
|
|
60
|
+
*/
|
|
61
|
+
export declare function startThread(record: GoalGraphRecord, description: string): SchedulerSelectionResult;
|
|
62
|
+
/**
|
|
63
|
+
* INV-42 (Q3's resolution — "PAUSED preserves partial state/evidence — never silently discarded
|
|
64
|
+
* on preemption"): the per-thread analog of `plan-store.ts`'s `updatePlanFromRun`, mapping the
|
|
65
|
+
* harness's resulting task statuses back onto `threadId`'s own `tasks` list. Deliberately looked
|
|
66
|
+
* up **by id**, not via `getActiveThread` — the whole point is this still works for a thread the
|
|
67
|
+
* Scheduler has since moved to `PAUSED` (an in-flight tool call that was already running when a
|
|
68
|
+
* steering message preempted its thread runs to completion per Q3's "let it finish" default, and
|
|
69
|
+
* its result must still land on the now-PAUSED thread, not be silently dropped). A `threadId` not
|
|
70
|
+
* present in `record.threads` is a no-op — defensive, never throws on a stale id.
|
|
71
|
+
*/
|
|
72
|
+
export declare function syncThreadFromTaskGraph(record: GoalGraphRecord, threadId: string, taskGraphTasks: {
|
|
73
|
+
id: string;
|
|
74
|
+
status: GoalThread['tasks'][number]['status'];
|
|
75
|
+
description?: string;
|
|
76
|
+
depends_on?: string[];
|
|
77
|
+
risk_level?: 'LOW' | 'MEDIUM' | 'HIGH';
|
|
78
|
+
}[]): GoalGraphRecord;
|