@buildaharness/aielia 0.3.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.
- package/README.md +832 -0
- package/dist/action-approval-service.d.ts +52 -0
- package/dist/action-snapshot.d.ts +173 -0
- package/dist/action-tools.d.ts +38 -0
- package/dist/agent-loop.d.ts +372 -0
- package/dist/answer-claim.d.ts +51 -0
- package/dist/ask-clarification-service.d.ts +70 -0
- package/dist/ask-mode-flag.d.ts +25 -0
- package/dist/ask-response-format.d.ts +8 -0
- package/dist/assistant-session.d.ts +267 -0
- package/dist/assistant-source.d.ts +14 -0
- package/dist/assistant-types.d.ts +158 -0
- package/dist/assistant.d.ts +419 -0
- package/dist/batch-list-detector.d.ts +15 -0
- package/dist/batch-research-fixtures.d.ts +50 -0
- package/dist/benchmark-injected-failure.d.ts +27 -0
- package/dist/claude-cli-llm-client.d.ts +139 -0
- package/dist/claude-cli-prompt.d.ts +86 -0
- package/dist/cli-config.d.ts +27 -0
- package/dist/cli-session-D0uLdT2A.js +7863 -0
- package/dist/cli-session-D0uLdT2A.js.map +1 -0
- package/dist/cli-session.d.ts +63 -0
- package/dist/cli.d.ts +65 -0
- package/dist/cli.js +1693 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +175 -0
- package/dist/contradiction-checker.d.ts +27 -0
- package/dist/debug-log.d.ts +16 -0
- package/dist/decomposition-classifier.d.ts +38 -0
- package/dist/doctor-checks.d.ts +8 -0
- package/dist/email-smtp.d.ts +19 -0
- package/dist/email.d.ts +60 -0
- package/dist/error-classifier.d.ts +13 -0
- package/dist/execution-mode.d.ts +85 -0
- package/dist/fact-extraction.d.ts +143 -0
- package/dist/failure-mode-matcher.d.ts +32 -0
- package/dist/file-tools-mcp-server.mjs +1027 -0
- package/dist/file-tools.d.ts +179 -0
- package/dist/first-run.d.ts +22 -0
- package/dist/harness-bridge.d.ts +103 -0
- package/dist/index.d.ts +58 -0
- package/dist/index.js +212 -0
- package/dist/index.js.map +1 -0
- package/dist/ink-test-render.d.ts +24 -0
- package/dist/lexical/patterns/batch-list-markers.json +8 -0
- package/dist/lexical/patterns/batch-list-markers.json.d.ts +11 -0
- package/dist/lexical/patterns/coding-fact-markers.json +8 -0
- package/dist/lexical/patterns/coding-fact-markers.json.d.ts +11 -0
- package/dist/lexical/patterns/enumeration-markers.json +20 -0
- package/dist/lexical/patterns/enumeration-markers.json.d.ts +23 -0
- package/dist/lexical/patterns/fact-markers.json +16 -0
- package/dist/lexical/patterns/fact-markers.json.d.ts +19 -0
- package/dist/lexical/patterns/injection-patterns.json +20 -0
- package/dist/lexical/patterns/injection-patterns.json.d.ts +23 -0
- package/dist/lexical/patterns/plan-mode-markers.json +10 -0
- package/dist/lexical/patterns/plan-mode-markers.json.d.ts +13 -0
- package/dist/lexical/patterns/risk-patterns.json +122 -0
- package/dist/lexical/patterns/risk-patterns.json.d.ts +125 -0
- package/dist/lexical/patterns/task-cancel-markers.json +22 -0
- package/dist/lexical/patterns/task-cancel-markers.json.d.ts +25 -0
- package/dist/lexical/patterns/template-keywords.json +20 -0
- package/dist/lexical/patterns/template-keywords.json.d.ts +23 -0
- package/dist/lexical/patterns/tool-yield-markers.json +22 -0
- package/dist/lexical/patterns/tool-yield-markers.json.d.ts +25 -0
- package/dist/lexical/patterns.d.ts +64 -0
- package/dist/memory-service.d.ts +219 -0
- package/dist/model-pricing.d.ts +19 -0
- package/dist/network-containment.d.ts +21 -0
- package/dist/node-config-store.d.ts +29 -0
- package/dist/node-display-names.d.ts +26 -0
- package/dist/node-fs-backend.d.ts +8 -0
- package/dist/non-interactive-mode.d.ts +22 -0
- package/dist/one-loop-flag.d.ts +38 -0
- package/dist/plan-approval-service.d.ts +62 -0
- package/dist/plan-builder.d.ts +32 -0
- package/dist/plan-drafting-service.d.ts +87 -0
- package/dist/plan-drafting.d.ts +58 -0
- package/dist/plan-mode-flag.d.ts +34 -0
- package/dist/plan-service.d.ts +61 -0
- package/dist/plan-sketch-service.d.ts +24 -0
- package/dist/plan-sketch.d.ts +20 -0
- package/dist/plan-store.d.ts +232 -0
- package/dist/plan-templates/data/content_creation.json.d.ts +75 -0
- package/dist/plan-templates/data/decision_making.json.d.ts +66 -0
- package/dist/plan-templates/data/problem_solving.json.d.ts +75 -0
- package/dist/plan-templates/data/process_improvement.json.d.ts +57 -0
- package/dist/plan-templates/data/project_planning.json.d.ts +66 -0
- package/dist/plan-templates/data/research_analysis.json.d.ts +66 -0
- package/dist/plan-templates/data/trip_planning.json.d.ts +66 -0
- package/dist/plan-templates/index.d.ts +33 -0
- package/dist/plan-verification.d.ts +31 -0
- package/dist/reminder-tools.d.ts +13 -0
- package/dist/response-service.d.ts +73 -0
- package/dist/review-checker.d.ts +22 -0
- package/dist/risk-classifier.d.ts +7 -0
- package/dist/scripted-llm-client.d.ts +37 -0
- package/dist/semantic-criterion-coverage.d.ts +30 -0
- package/dist/shell-executor.d.ts +14 -0
- package/dist/shell-tools.d.ts +84 -0
- package/dist/spend-cap.d.ts +41 -0
- package/dist/spike.d.ts +1 -0
- package/dist/spike.js +18 -0
- package/dist/spike.js.map +1 -0
- package/dist/supervisor-decider.d.ts +3 -0
- package/dist/system-prompt.d.ts +8 -0
- package/dist/task-mapping.d.ts +42 -0
- package/dist/tool-control-plane.d.ts +67 -0
- package/dist/tool-policy.d.ts +45 -0
- package/dist/tool-step.d.ts +23 -0
- package/dist/tool-yield-classifier.d.ts +7 -0
- package/dist/trace-events.d.ts +126 -0
- package/dist/transcript-compaction.d.ts +13 -0
- package/dist/trust-tagging.d.ts +38 -0
- package/dist/tui-app-DxLPSGh2.js +481 -0
- package/dist/tui-app-DxLPSGh2.js.map +1 -0
- package/dist/tui-app.d.ts +125 -0
- package/dist/tui-input.d.ts +51 -0
- package/dist/tui-mode-flag.d.ts +36 -0
- package/dist/tui-output-capture.d.ts +30 -0
- package/dist/tui-spike.d.ts +1 -0
- package/dist/turn-intent-classifier.d.ts +96 -0
- package/dist/turn-interpreter.d.ts +71 -0
- package/dist/turn-policy.d.ts +45 -0
- package/dist/web-fetch-core.d.ts +65 -0
- package/dist/web-search-provider.d.ts +12 -0
- package/dist/web-tools.d.ts +26 -0
- package/package.json +69 -0
|
@@ -0,0 +1,419 @@
|
|
|
1
|
+
import { ExperienceStore, CheckpointStore, AskResponse } from '@buildaharness/harness';
|
|
2
|
+
import { MemoryAdapter, ILLMClient, ChatMessage, ReminderStore } from '@buildaharness/runtime';
|
|
3
|
+
import { FileToolsContext } from './file-tools.js';
|
|
4
|
+
import { UndoLogEntry } from './action-snapshot.js';
|
|
5
|
+
import { WebToolsContext } from './web-tools.js';
|
|
6
|
+
import { ShellToolsContext } from './shell-tools.js';
|
|
7
|
+
import { ActionToolsContext } from './action-tools.js';
|
|
8
|
+
import { SpendCapConfig, SpendState } from './spend-cap.js';
|
|
9
|
+
import { TraceEvent } from './trace-events.js';
|
|
10
|
+
import { AssistantToolStep } from './tool-step.js';
|
|
11
|
+
import { MemorySummary, MemoryExport } from './memory-service.js';
|
|
12
|
+
import { UserFact } from './fact-extraction.js';
|
|
13
|
+
import { TranscriptSearchHit } from './assistant-session.js';
|
|
14
|
+
import { PlanDecision, PlanApprovalEdits } from './plan-approval-service.js';
|
|
15
|
+
import { PlanRecord } from './plan-store.js';
|
|
16
|
+
import { OneLoopMode } from './one-loop-flag.js';
|
|
17
|
+
import { AskMode } from './ask-mode-flag.js';
|
|
18
|
+
import { PlanRolloutMode } from './plan-mode-flag.js';
|
|
19
|
+
import { DebugLogEntry } from './debug-log.js';
|
|
20
|
+
import { AssistantTurnResult, AssistantProgress } from './assistant-types.js';
|
|
21
|
+
export type { MemorySummary, MemoryExport, PendingFact } from './memory-service.js';
|
|
22
|
+
export type { FactCategory } from './turn-intent-classifier.js';
|
|
23
|
+
export type { IndexedMessage, TranscriptSearchHit } from './assistant-session.js';
|
|
24
|
+
export type { BatchBudgetState } from './agent-loop.js';
|
|
25
|
+
export { trimmedAverage, nextItemBudget } from './agent-loop.js';
|
|
26
|
+
export type { AssistantSource } from './assistant-source.js';
|
|
27
|
+
export type { DebugLogEntry } from './debug-log.js';
|
|
28
|
+
export type { AssistantTrace, AssistantTurnResult, AssistantProgress, ProposerKind } from './assistant-types.js';
|
|
29
|
+
export type { PlanDecision, PlanApprovalEdits } from './plan-approval-service.js';
|
|
30
|
+
export type { PlanMode } from './plan-store.js';
|
|
31
|
+
/** Result of `/memory confirm`/`/memory reject` (single index or bulk category) — see PersonalAssistant.confirmPendingFact/rejectPendingFact. */
|
|
32
|
+
export type MemoryPendingOutcome = {
|
|
33
|
+
ok: true;
|
|
34
|
+
facts: UserFact[];
|
|
35
|
+
conflictNotices: string[];
|
|
36
|
+
} | {
|
|
37
|
+
ok: false;
|
|
38
|
+
error: string;
|
|
39
|
+
};
|
|
40
|
+
export interface TurnOptions {
|
|
41
|
+
sessionId?: string;
|
|
42
|
+
approved?: boolean;
|
|
43
|
+
pendingActionId?: string;
|
|
44
|
+
/**
|
|
45
|
+
* Q2 of plans/ask_question_and_plan_mode_plan.html — resolves a staged `needs_clarification`
|
|
46
|
+
* result (see AssistantTurnResult.pendingClarificationId) with the user's answer. Mirrors
|
|
47
|
+
* `pendingActionId`/`approved`'s own "resolved by ID, never re-derived" shape:
|
|
48
|
+
* `clarificationAnswer` must answer exactly the questions that were staged, validated
|
|
49
|
+
* server-side (INV-28) regardless of what the client already checked.
|
|
50
|
+
*/
|
|
51
|
+
pendingClarificationId?: string;
|
|
52
|
+
clarificationAnswer?: AskResponse;
|
|
53
|
+
/**
|
|
54
|
+
* P2 of plans/ask_question_and_plan_mode_plan.html — resolves a staged `needs_plan_approval`
|
|
55
|
+
* result (see AssistantTurnResult.planApprovalId) with the user's decision. Mirrors
|
|
56
|
+
* `pendingActionId`/`approved`'s "resolved by ID, never re-derived" shape: what gets
|
|
57
|
+
* approved/declined is exactly the plan that was staged, never re-drafted.
|
|
58
|
+
*/
|
|
59
|
+
planApprovalId?: string;
|
|
60
|
+
/** `'approve'`/`'approve_with_edits'`/`'decline'` — required to resolve `planApprovalId`; omitting it leaves the plan `awaiting_approval` (fail closed), same as an unanswered clarification. */
|
|
61
|
+
planDecision?: PlanDecision;
|
|
62
|
+
/** Only meaningful with `planDecision: 'approve_with_edits'` — cancels/edits applied before the plan is activated. */
|
|
63
|
+
planEdits?: PlanApprovalEdits;
|
|
64
|
+
/**
|
|
65
|
+
* Per-session override — tier 2 of Q1's three-tier INV-29 resolution. `'disabled'` forces
|
|
66
|
+
* plain free-text-fallback escalations for this turn even when the global `askMode` config is
|
|
67
|
+
* `'enabled'`. Absent/`'enabled'` defers to the global flag. Never widens the global flag: an
|
|
68
|
+
* override can only turn structured questions off relative to it, never on when the global
|
|
69
|
+
* flag is off.
|
|
70
|
+
*/
|
|
71
|
+
askMode?: AskMode;
|
|
72
|
+
onProgress?: (progress: AssistantProgress) => void;
|
|
73
|
+
/**
|
|
74
|
+
* Called with each token as the model's reply streams in. On the plain chat
|
|
75
|
+
* path (no tool loop active) this is the turn's one real LLM call, read via
|
|
76
|
+
* callChat. On the tool-loop path (fileTools/webTools configured), every
|
|
77
|
+
* tool-bearing round trip stays non-streaming — callChatStructured isn't a
|
|
78
|
+
* streaming call for either backend — but once the model stops calling tools,
|
|
79
|
+
* one extra callChat request re-asks for that same final answer as a real
|
|
80
|
+
* streamed completion, *only when `onToken` is supplied* (so a caller who
|
|
81
|
+
* doesn't listen never pays for it). ClaudeCliLLMClient's callChat isn't real
|
|
82
|
+
* per-token streaming either way (it yields the whole reply as one chunk) —
|
|
83
|
+
* this only reads token-by-token on the proxy backend.
|
|
84
|
+
*/
|
|
85
|
+
onToken?: (token: string) => void;
|
|
86
|
+
/**
|
|
87
|
+
* Called once per tool call as it happens, with a human-readable summary — the "what
|
|
88
|
+
* step is the assistant on right now" signal, distinct from onTrace's name/status-only
|
|
89
|
+
* telemetry. Fires for every backend: the proxy backend's tool loop reports each call it
|
|
90
|
+
* dispatches directly; the claude-cli backend reports calls its own agentic loop makes
|
|
91
|
+
* autonomously inside a single subprocess call, via ChatOptions.onToolStep (see
|
|
92
|
+
* ClaudeCliLLMClient).
|
|
93
|
+
*/
|
|
94
|
+
onToolStep?: (step: AssistantToolStep) => void;
|
|
95
|
+
/**
|
|
96
|
+
* **Eval harness only** (`packages/aielia/eval/`). Wraps the one-loop
|
|
97
|
+
* proposer so its first `failIterations` harness iterations report a failed execution
|
|
98
|
+
* and `seedFailures` recurring same-class records are seeded into the run's
|
|
99
|
+
* `failureDiagnostics` — enough to trip `cannotMakeProgress()` on iteration 1 and
|
|
100
|
+
* exercise the Trajectory Supervisor's stall edge inside a single benchmark turn. Never
|
|
101
|
+
* set by a real caller; ignored unless the one-loop proposer path is active.
|
|
102
|
+
*/
|
|
103
|
+
__benchmarkInjectedFailure?: {
|
|
104
|
+
failIterations: number;
|
|
105
|
+
seedFailures: number;
|
|
106
|
+
onInjected?: () => void;
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
export interface PersonalAssistantOptions {
|
|
110
|
+
llmClient: ILLMClient;
|
|
111
|
+
model?: string;
|
|
112
|
+
/**
|
|
113
|
+
* The already-resolved project label a project-scoped fact gets tagged with and filtered
|
|
114
|
+
* against — see UserFact.project's doc comment. Callers resolve `config.activeProject ??
|
|
115
|
+
* workspaceRoot` themselves (cli.ts's buildAssistant) before passing it in; PersonalAssistant
|
|
116
|
+
* doesn't know about workspaceRoot itself (it's a per-tool option, not assistant-wide — see
|
|
117
|
+
* fileTools/shellTools/actionTools). Undefined/empty leaves every fact unscoped, matching a
|
|
118
|
+
* fresh install with no workspace concept at all.
|
|
119
|
+
*/
|
|
120
|
+
activeProject?: string;
|
|
121
|
+
/** Conversation transcript storage — defaults to an in-process Map, swap for IndexedDBAdapter in the browser. */
|
|
122
|
+
memory?: MemoryAdapter;
|
|
123
|
+
/** Learning-layer store — persist and pass the same instance back in across sessions to retain strategy weights. */
|
|
124
|
+
experienceStore?: ExperienceStore;
|
|
125
|
+
/** Stores an in-flight harness run's checkpoint so a crash/reload mid-turn can resume instead of losing the turn. */
|
|
126
|
+
checkpointStore?: CheckpointStore;
|
|
127
|
+
/**
|
|
128
|
+
* Caps both the harness's plan-driven main loop (auto-raised there via
|
|
129
|
+
* `Math.max(maxSteps, initialTasks.length)` so a decomposed plan is never starved) and the
|
|
130
|
+
* ReAct-style tool loop's round-trips (AgentLoop.runToolLoop) — one shared per-turn step
|
|
131
|
+
* budget rather than two independently-tuned constants. Defaults to 15: high enough that a
|
|
132
|
+
* legitimate multi-query research task (e.g. "find primary schools near me", which can
|
|
133
|
+
* easily take 5+ real search round-trips) doesn't get cut off mid-work, while still bounding
|
|
134
|
+
* a stuck/looping model.
|
|
135
|
+
*/
|
|
136
|
+
maxSteps?: number;
|
|
137
|
+
/**
|
|
138
|
+
* When set, `turn()` gives the model real read_file/list_directory/write_file
|
|
139
|
+
* tools scoped to `workspaceRoot` instead of a single plain chat call. Absent
|
|
140
|
+
* by default — behavior is byte-for-byte unchanged from before this option existed.
|
|
141
|
+
* `write_file` never executes inline; it always stages a proposal and the turn
|
|
142
|
+
* returns `needs_approval` with a `pendingWriteId`.
|
|
143
|
+
*/
|
|
144
|
+
fileTools?: FileToolsContext;
|
|
145
|
+
/**
|
|
146
|
+
* When set, `turn()` also gives the model web_search/fetch_url tools, grounding replies in external content.
|
|
147
|
+
* Absent by default — behavior is unchanged when unset. Results from these two tools are wrapped in
|
|
148
|
+
* `<untrusted_external_content>` before they reach the model (see trust-tagging.ts) — unlike file tools,
|
|
149
|
+
* this is content the assistant does not vouch for.
|
|
150
|
+
*/
|
|
151
|
+
webTools?: WebToolsContext;
|
|
152
|
+
/**
|
|
153
|
+
* When set, `turn()` gives the model a real run_shell_command tool scoped to `workspaceRoot`.
|
|
154
|
+
* Every call is gated on approval, full stop — there is no "safe subset" the way `read_file` is
|
|
155
|
+
* safe within `write_file`'s tool group (a shell command has no structural split between "reads"
|
|
156
|
+
* and "mutates"). Once approved, the command's stdout+stderr is wrapped in
|
|
157
|
+
* `<untrusted_external_content>` (same trust boundary as web_search/fetch_url — see
|
|
158
|
+
* trust-tagging.ts) before it's saved into the transcript, since it can carry the same kind of
|
|
159
|
+
* injection-shaped content a fetched web page can. Independent of `fileTools`/`webTools` so a
|
|
160
|
+
* caller can enable file/web access without ever exposing shell.
|
|
161
|
+
*/
|
|
162
|
+
shellTools?: ShellToolsContext;
|
|
163
|
+
/**
|
|
164
|
+
* When set, `turn()` gives the model real "effect" tools — today `send_email` — scoped to
|
|
165
|
+
* `workspaceRoot` for staging. Every call is approval-gated exactly like `write_file` /
|
|
166
|
+
* `run_shell_command`: the model can only propose a message, never deliver one. On approval,
|
|
167
|
+
* `applyPendingAction` calls `sendEmail` (email.ts's Resend transport / email-smtp.ts's SMTP
|
|
168
|
+
* transport — wired in by a Node caller, never imported here). Independent of
|
|
169
|
+
* `fileTools`/`webTools`/`shellTools`. Absent by default — no `send_email` tool exists unless set.
|
|
170
|
+
*/
|
|
171
|
+
actionTools?: ActionToolsContext;
|
|
172
|
+
/** Stores reminders detected from "remind me"/"set a reminder"-shaped requests — defaults to an in-process store. See ReminderStore's `dueAt` doc: v1 stores raw text only, no time parsing, so `listDue()` won't return these yet. */
|
|
173
|
+
reminderStore?: ReminderStore;
|
|
174
|
+
/** Structured turn telemetry — turn/risk/triviality/harness-node/tool-call/escalation/error events. Purely additive instrumentation; no behavior change when unset. */
|
|
175
|
+
onTrace?: (event: TraceEvent) => void;
|
|
176
|
+
/**
|
|
177
|
+
* Full message/tool content for live debugging — deliberately separate from `onTrace`
|
|
178
|
+
* (which is name/status-only by design, safe to hand to an arbitrary sink; see its own doc
|
|
179
|
+
* comment) since this one carries the actual conversation. Off by default: nothing is
|
|
180
|
+
* logged anywhere unless a caller wires this in. See DebugLogEntry.
|
|
181
|
+
*/
|
|
182
|
+
onDebugLog?: (entry: DebugLogEntry) => void;
|
|
183
|
+
/**
|
|
184
|
+
* Equivalent of Claude Code's own --dangerously-skip-permissions (see AssistantConfig's doc
|
|
185
|
+
* comment in config.ts). When true, both the message-level risk gate and write_file/
|
|
186
|
+
* run_shell_command's per-call staging resolve as if the user had already said yes, instead
|
|
187
|
+
* of returning `needs_approval` — turn() auto-applies a staged action the same way a second
|
|
188
|
+
* turn() call with `approved: true` would. The underlying sandboxing (path validation, SSRF
|
|
189
|
+
* guard, shell env allowlist, output truncation, timeout) is never skipped — only the ask.
|
|
190
|
+
* Off by default.
|
|
191
|
+
*/
|
|
192
|
+
dangerouslySkipPermissions?: boolean;
|
|
193
|
+
/**
|
|
194
|
+
* Opt-in session spend/turn-count ceilings — see spend-cap.ts. Undefined by default, same as
|
|
195
|
+
* every other field here that changes behavior only when a caller sets it: no ceiling means
|
|
196
|
+
* exactly today's unbounded behavior. Checked once per turn, before any LLM call that turn
|
|
197
|
+
* would make (see turn()) — never mid-turn.
|
|
198
|
+
*/
|
|
199
|
+
spendCap?: SpendCapConfig;
|
|
200
|
+
/**
|
|
201
|
+
* R2 of plans/harness_d2_one_loop_rewire_plan.html — see one-loop-flag.ts's doc comment for the
|
|
202
|
+
* full rollout rationale. 'disabled' (the default, for the whole R2-R4 rollout window): today's
|
|
203
|
+
* behavior, byte-for-byte — HarnessBridge.run() always uses `() => draftReply` as its toolFn,
|
|
204
|
+
* regardless of whether a caller happens to supply a proposer. 'enabled' lets a supplied
|
|
205
|
+
* proposer (see HarnessRunParams.oneLoopProposer) actually be used. PersonalAssistant itself
|
|
206
|
+
* never touches process.env — only cli.ts (or an equivalent surface entry point) is expected to
|
|
207
|
+
* call resolveOneLoopMode(process.env) and pass the result here.
|
|
208
|
+
*/
|
|
209
|
+
oneLoopMode?: OneLoopMode;
|
|
210
|
+
/**
|
|
211
|
+
* Q2 of plans/ask_question_and_plan_mode_plan.html — global-flag control point (tier 1 of
|
|
212
|
+
* INV-29) for the ask-question mechanism. Undefined (the default) falls back to
|
|
213
|
+
* `DEFAULT_ASK_MODE` ('disabled') — today's behavior, byte-for-byte: every escalation stays on
|
|
214
|
+
* the plain `escalated`/`reply: null` path. Only cli.ts/chat-ui's App.tsx (or an equivalent
|
|
215
|
+
* surface entry point) is expected to resolve this from ASSISTANT_ASK_MODE/
|
|
216
|
+
* VITE_ASSISTANT_ASK_MODE and pass it down — PersonalAssistant itself never touches
|
|
217
|
+
* process.env, mirroring oneLoopMode's own convention.
|
|
218
|
+
*/
|
|
219
|
+
askMode?: AskMode;
|
|
220
|
+
/**
|
|
221
|
+
* P11 of plans/ask_question_and_plan_mode_plan.html — see plan-mode-flag.ts's doc comment for
|
|
222
|
+
* the full rollout rationale. 'legacy' (the default, for the whole rollout window): P3's
|
|
223
|
+
* judgment-based auto-trigger below never fires, so `turn()` never auto-enters plan mode's
|
|
224
|
+
* exclusive drafting+approval loop — today's behavior, byte-for-byte, for every real user turn.
|
|
225
|
+
* 'gated' lets that auto-trigger run. PersonalAssistant itself never touches process.env — only
|
|
226
|
+
* cli.ts/chat-ui's App.tsx (or an equivalent surface entry point) is expected to call
|
|
227
|
+
* resolvePlanMode(process.env)/normalizePlanMode(import.meta.env...) and pass the result here.
|
|
228
|
+
*/
|
|
229
|
+
planMode?: PlanRolloutMode;
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* A light, everyday-use wrapper around HarnessRuntime: one harness run per chat turn,
|
|
233
|
+
* one real LLM call per turn (skipped entirely while a HIGH-risk action awaits approval).
|
|
234
|
+
* Conversation history lives beside the harness run (in `memory`), not inside it — each
|
|
235
|
+
* turn's WorldModel/TaskGraph/etc. are scratch state for that single turn, same as the
|
|
236
|
+
* rest of the 11-layer runtime; only the transcript, the ExperienceStore, and (while a
|
|
237
|
+
* turn is actually in flight) a HarnessRunState checkpoint persist.
|
|
238
|
+
*
|
|
239
|
+
* Phase 4d of the architecture remediation plan split this class's internals into 8
|
|
240
|
+
* single-purpose collaborators (MemoryService, AssistantSession, AgentLoop,
|
|
241
|
+
* ActionApprovalService, PlanService, TurnInterpreter, HarnessBridge, ResponseService), each
|
|
242
|
+
* constructed once here and wired together. This class itself is now a thin facade + sequencer:
|
|
243
|
+
* its public constructor signature and every public method below are unchanged, so every
|
|
244
|
+
* existing caller (cli.ts, chat-ui's App.tsx, assistant.test.ts's ~89 `new PersonalAssistant(...)`
|
|
245
|
+
* call sites) keeps working with zero call-site changes.
|
|
246
|
+
*/
|
|
247
|
+
export declare class PersonalAssistant {
|
|
248
|
+
private readonly llmClient;
|
|
249
|
+
private model?;
|
|
250
|
+
private activeProject?;
|
|
251
|
+
private readonly memory;
|
|
252
|
+
private readonly webTools?;
|
|
253
|
+
private readonly onTrace?;
|
|
254
|
+
private readonly onDebugLog?;
|
|
255
|
+
private readonly dangerouslySkipPermissions;
|
|
256
|
+
/** Whenever any of fileTools/webTools/shellTools is configured, `turn()` routes through AgentLoop instead of a single plain chat call — computed once here since it never changes for the lifetime of an instance. */
|
|
257
|
+
private readonly toolLoopWillRun;
|
|
258
|
+
/** R3 of plans/harness_d2_one_loop_rewire_plan.html — mirrors the same flag HarnessBridge was given at construction, kept here too so runTurn can decide whether to defer the tool loop into a harness-driven proposer instead of precomputing draftReply. See PersonalAssistantOptions.oneLoopMode's doc comment. */
|
|
259
|
+
private readonly oneLoopMode;
|
|
260
|
+
/** Q2 — global-flag tier of the ask-question mechanism's three-tier INV-29 resolution. See PersonalAssistantOptions.askMode's doc comment. */
|
|
261
|
+
private readonly askMode;
|
|
262
|
+
/** P11 — gates whether P3's auto-trigger below can ever enter plan mode for real traffic. See PersonalAssistantOptions.planMode's doc comment. */
|
|
263
|
+
private readonly planMode;
|
|
264
|
+
/**
|
|
265
|
+
* Scratch slot for which proposer drove the most recent runTurn — read by `turn()` to stamp
|
|
266
|
+
* AssistantTurnResult.proposerKind, and emitted as a 'proposer_selected' trace event from
|
|
267
|
+
* runTurn itself. A single mutable field is safe because `turn()` is awaited end to end (turns
|
|
268
|
+
* never overlap within one instance). See AssistantTurnResult.proposerKind and
|
|
269
|
+
* plans/chat_ui_browser_e2e_plan.html phase B1.
|
|
270
|
+
*/
|
|
271
|
+
private lastProposerKind;
|
|
272
|
+
private readonly memoryService;
|
|
273
|
+
private readonly session;
|
|
274
|
+
private readonly agentLoop;
|
|
275
|
+
private readonly actionApproval;
|
|
276
|
+
private readonly planService;
|
|
277
|
+
private readonly planApproval;
|
|
278
|
+
private readonly planDrafting;
|
|
279
|
+
private readonly planSketch;
|
|
280
|
+
private readonly turnInterpreter;
|
|
281
|
+
private readonly harnessBridge;
|
|
282
|
+
private readonly responseService;
|
|
283
|
+
private readonly askClarification;
|
|
284
|
+
constructor(options: PersonalAssistantOptions);
|
|
285
|
+
/**
|
|
286
|
+
* Preferred entry point in a browser: defaults transcript, learning, and
|
|
287
|
+
* checkpoint storage to their IndexedDB/Dexie-backed implementations so all
|
|
288
|
+
* three survive a page reload, instead of the in-process defaults the plain
|
|
289
|
+
* constructor uses. Falls back to the same in-memory defaults as `new
|
|
290
|
+
* PersonalAssistant(...)` outside a browser (e.g. the CLI).
|
|
291
|
+
*/
|
|
292
|
+
static create(options: PersonalAssistantOptions): Promise<PersonalAssistant>;
|
|
293
|
+
/**
|
|
294
|
+
* Thin wrapper around runTurn(): emits turn_start/turn_end/error trace events
|
|
295
|
+
* around the actual logic, so every one of runTurn's return paths gets a
|
|
296
|
+
* matching turn_end without instrumenting each one individually.
|
|
297
|
+
*/
|
|
298
|
+
turn(userMessage: string, options?: TurnOptions): Promise<AssistantTurnResult>;
|
|
299
|
+
/** Persisted alongside transcript/facts/plan — survives a process restart, same as everything else keyed by sessionId, so the ceiling is genuinely cross-session, not just cross-turn within one process lifetime. */
|
|
300
|
+
getSpendState(sessionId: string): Promise<SpendState>;
|
|
301
|
+
/** The session's conversation transcript, oldest first — same array `turn()` reads/appends to. Used by `/export`. */
|
|
302
|
+
getTranscript(sessionId: string): Promise<ChatMessage[]>;
|
|
303
|
+
/**
|
|
304
|
+
* Records a message-level risk-gate decline as a resolved, paired exchange, once the caller
|
|
305
|
+
* (cli.ts) knows the final answer was "no". See AssistantSession.recordDeclinedRequest's doc
|
|
306
|
+
* comment for the full reasoning.
|
|
307
|
+
*/
|
|
308
|
+
recordDeclinedRequest(sessionId: string, userMessage: string, reason: string): Promise<void>;
|
|
309
|
+
/** Ends the current conversation — see AssistantSession.clearSession's doc comment for exactly what is and isn't cleared. */
|
|
310
|
+
clearSession(sessionId: string): Promise<void>;
|
|
311
|
+
/**
|
|
312
|
+
* P1 of plans/ask_question_and_plan_mode_plan.html — explicit entry point into plan mode's
|
|
313
|
+
* exclusive drafting state. No production caller yet: P3 will later set this automatically from
|
|
314
|
+
* a judgment-based trigger ahead of TurnInterpreter's classification. Until then this is reached
|
|
315
|
+
* only by a caller (a future `/plan` CLI command, or a test) that wants to exercise the drafting
|
|
316
|
+
* loop directly. Once active, every `turn()` call for this session routes to
|
|
317
|
+
* `PlanDraftingService` instead of the normal pipeline until the user says an explicit
|
|
318
|
+
* cancel/abort phrase.
|
|
319
|
+
*/
|
|
320
|
+
enterPlanMode(sessionId: string): Promise<{
|
|
321
|
+
active: boolean;
|
|
322
|
+
draftId: string;
|
|
323
|
+
}>;
|
|
324
|
+
/**
|
|
325
|
+
* P7 of plans/ask_question_and_plan_mode_plan.html — the raw current `PlanRecord` for this
|
|
326
|
+
* session, regardless of `mode`, so a caller (chat-ui's persistent banner, the CLI's `/plan
|
|
327
|
+
* show`) can display live drafting/awaiting-approval state independent of any single turn's
|
|
328
|
+
* own result (a `needs_plan_approval` result only carries a snapshot at the moment it's
|
|
329
|
+
* staged; a plain `status: 'ok'` drafting reply doesn't carry `rationale`/`reviewNotes` at
|
|
330
|
+
* all). Returns `null` when no plan record exists for this session yet.
|
|
331
|
+
*/
|
|
332
|
+
getPlanState(sessionId: string): Promise<PlanRecord | null>;
|
|
333
|
+
/**
|
|
334
|
+
* P9 of plans/ask_question_and_plan_mode_plan.html — the lightweight plan-sketch delegate: a
|
|
335
|
+
* cheaper "just go research and draft an approach" path than plan mode's durable task-graph
|
|
336
|
+
* machinery (P0-P8), explicitly invoked (a CLI `/plan sketch <request>` command, a chat-ui
|
|
337
|
+
* "Sketch a plan" action) rather than auto-triggered. Returns advice in the reply text — it
|
|
338
|
+
* never creates a `PlanRecord`, never sets `planMode.active` (`enterPlanMode` above), never
|
|
339
|
+
* stages anything for `PlanApprovalService`, and cannot execute a single task (INV-35). A real,
|
|
340
|
+
* cost-incurring LLM call, so it still goes through the same session spend-cap check/record as
|
|
341
|
+
* an ordinary `turn()` — just none of `turn()`'s classification/tool-loop/plan-mode machinery.
|
|
342
|
+
*/
|
|
343
|
+
sketchPlan(sessionId: string, request: string): Promise<AssistantTurnResult>;
|
|
344
|
+
/** Scoped recovery for a stuck harness checkpoint — see AssistantSession.clearCheckpoint's doc comment. */
|
|
345
|
+
clearCheckpoint(sessionId: string): Promise<{
|
|
346
|
+
cleared: boolean;
|
|
347
|
+
stepsUsed?: number;
|
|
348
|
+
currentNode?: string;
|
|
349
|
+
}>;
|
|
350
|
+
/** Read-only counterpart to clearCheckpoint — see AssistantSession.getCheckpointStatus's doc comment. */
|
|
351
|
+
getCheckpointStatus(sessionId: string): Promise<{
|
|
352
|
+
present: boolean;
|
|
353
|
+
stepsUsed?: number;
|
|
354
|
+
currentNode?: string;
|
|
355
|
+
failedResumeAttempts: number;
|
|
356
|
+
}>;
|
|
357
|
+
/** Removes the most recent exchange from conversation history — see AssistantSession.undoLastTurn's doc comment. */
|
|
358
|
+
undoLastTurn(sessionId: string): Promise<{
|
|
359
|
+
undone: boolean;
|
|
360
|
+
}>;
|
|
361
|
+
/** Real filesystem effects still on record as revertible, newest first — see AssistantSession.listUndoLogEntries's doc comment. */
|
|
362
|
+
listUndoLogEntries(): Promise<UndoLogEntry[]>;
|
|
363
|
+
/** Stages a revert of undo-log entry `id` as its own approval-gated pending action — see AssistantSession.stageUndoAction's doc comment. */
|
|
364
|
+
stageUndoAction(id: string): Promise<{
|
|
365
|
+
status: 'staged';
|
|
366
|
+
pendingActionId: string;
|
|
367
|
+
reason: string;
|
|
368
|
+
} | {
|
|
369
|
+
status: 'error';
|
|
370
|
+
message: string;
|
|
371
|
+
}>;
|
|
372
|
+
/** Read-only snapshot of what this session/assistant has learned — see MemoryService.getMemorySummary's doc comment. Used by `/memory`. */
|
|
373
|
+
getMemorySummary(sessionId: string): Promise<MemorySummary>;
|
|
374
|
+
/** Full, unbounded snapshot of everything learned so far — see MemoryService.exportMemory's doc comment. Used by `/memory export`. */
|
|
375
|
+
exportMemory(sessionId: string): Promise<MemoryExport>;
|
|
376
|
+
/**
|
|
377
|
+
* `/memory confirm <n|category>` — `selector` is either a 1-based index into `/memory`'s
|
|
378
|
+
* flat, display-order "Pending confirmation" listing, or one of FactCategory's names for a
|
|
379
|
+
* bulk confirm. Phase 3 of plans/personal_assistant_fact_extraction_llm_confidence_plan.html.
|
|
380
|
+
* `conflictNotices` (if any) are advisory only — every confirmed fact is promoted regardless,
|
|
381
|
+
* matching how every other contradiction check in this codebase never gates belief admission.
|
|
382
|
+
*/
|
|
383
|
+
confirmPendingFact(selector: string): Promise<MemoryPendingOutcome>;
|
|
384
|
+
/** `/memory reject <n|category>` — mirror of confirmPendingFact, see its doc comment for `selector`'s shape. */
|
|
385
|
+
rejectPendingFact(selector: string): Promise<MemoryPendingOutcome>;
|
|
386
|
+
/**
|
|
387
|
+
* `/memory forget <n>` — `n` is a 1-based index into `/memory`'s "Facts I know" listing (durable
|
|
388
|
+
* facts first, then session facts — the same order `getMemorySummary()` returns). Unlike
|
|
389
|
+
* confirm/reject, there's no category form: a durable/session fact carries no `category` field,
|
|
390
|
+
* only pending model-inferred guesses do. Hard-deletes rather than routing through
|
|
391
|
+
* REJECTED_FACTS_KEY — see MemoryService.forgetFact's doc comment.
|
|
392
|
+
*/
|
|
393
|
+
forgetFact(selector: string, sessionId: string): Promise<MemoryPendingOutcome>;
|
|
394
|
+
/** Ranked search over the per-message index — see AssistantSession.searchTranscript's doc comment. Used by `/search`. */
|
|
395
|
+
searchTranscript(query: string, topK?: number): Promise<TranscriptSearchHit[]>;
|
|
396
|
+
/** Changes the model used by every subsequent `turn()` call, mid-session — no reconstruction needed. Used by `/model`. Every collaborator constructed above reads this field through a getter closure, never a captured string, so this takes effect for all of them immediately. */
|
|
397
|
+
setModel(model: string | undefined): void;
|
|
398
|
+
/** The project label new project-scoped facts are tagged with and existing ones are filtered against this session — see UserFact.project's doc comment. Empty string when none is set (cli.ts's buildAssistant always resolves one from workspaceRoot, but a bare `new PersonalAssistant()` with no `activeProject` option should read as "no project concept" rather than `undefined`). */
|
|
399
|
+
getActiveProject(): string;
|
|
400
|
+
/** Mid-session override for `activeProject`, mirroring setModel — takes effect on the very next turn via the same getter-closure MemoryService already reads through. Used by `/project <name>` outside the CLI's own /config-set-and-reload path (e.g. a future non-CLI embedder). */
|
|
401
|
+
setActiveProject(project: string | undefined): void;
|
|
402
|
+
/**
|
|
403
|
+
* The sequencer: constructs no state of its own beyond what a single turn needs
|
|
404
|
+
* (transcript/facts/system prompt, the turn-scoped usage accumulator), and otherwise just
|
|
405
|
+
* calls each collaborator in the same order the pre-split code ran their logic inline, wiring
|
|
406
|
+
* each one's output into the next. See turn-interpreter.ts/agent-loop.ts/harness-bridge.ts/
|
|
407
|
+
* response-service.ts for where the real control-flow subtlety (the batch-research path, the
|
|
408
|
+
* plan-cancel bypass, the triviality fast path) actually lives now.
|
|
409
|
+
*/
|
|
410
|
+
private runTurn;
|
|
411
|
+
/**
|
|
412
|
+
* Shared by the flag-OFF flat/batch tool loop's own needs_approval/escalated ToolLoopResult and
|
|
413
|
+
* the flag-ON harness-driven proposer's equivalent OneLoopPause (R3 of
|
|
414
|
+
* plans/harness_d2_one_loop_rewire_plan.html, see runTurn's two call sites) — "the model wants
|
|
415
|
+
* to write/run/send something" or "the tool loop gave up" means the same thing to the caller
|
|
416
|
+
* regardless of which loop discovered it.
|
|
417
|
+
*/
|
|
418
|
+
private buildToolLoopPauseResult;
|
|
419
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface BatchListDetection {
|
|
2
|
+
/** Exact strings as they appeared in the list (marker/bullet stripped), in message order. */
|
|
3
|
+
items: string[];
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Zero-LLM-call gate for the one task shape this plan targets: an explicit, syntactically obvious
|
|
7
|
+
* list of ≥3 lookup targets (newline-separated names, markdown bullets, or a numbered list).
|
|
8
|
+
* Deliberately narrower than decomposition-classifier.ts's enumeration detection — no
|
|
9
|
+
* comma-enumeration, no sequencing-word detection, no word-count fallback. Those stay that file's
|
|
10
|
+
* problem; this one only fires on a shape unambiguous enough that a false positive should be
|
|
11
|
+
* essentially impossible. Fails closed (returns null) for anything else, including a list where
|
|
12
|
+
* most lines don't read as name-shaped (task instructions, not lookup targets) and a run below the
|
|
13
|
+
* 3-item floor.
|
|
14
|
+
*/
|
|
15
|
+
export declare function detectHomogeneousBatchList(message: string): BatchListDetection | null;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { LLMStructuredResponse } from '@buildaharness/runtime';
|
|
2
|
+
import { WebSearchResult } from './web-tools.js';
|
|
3
|
+
/**
|
|
4
|
+
* The real school-dates comparison this plan is built on (see
|
|
5
|
+
* plans/personal_assistant_dynamic_tool_budget_plan.html's Reference Transcripts tab), encoded as
|
|
6
|
+
* a reusable scripted-LLM-response fixture instead of duplicated inline in assistant.test.ts —
|
|
7
|
+
* so the integration replay test stays traceable back to the actual incident that motivated this
|
|
8
|
+
* plan, and any recalibration of thresholds later has the real shape to check against.
|
|
9
|
+
*
|
|
10
|
+
* `searchYields` lists one entry per web_search call this item's own per-item sub-loop makes, in
|
|
11
|
+
* order. An item whose last 3 entries are all `'dead_end'` (Halensee-Grundschule below) trips
|
|
12
|
+
* resolveBatchItem's item-scoped dead-end window (BATCH_DEAD_END_WINDOW = 3) — that item never
|
|
13
|
+
* reaches a final LLM call at all, so `finalAnswer` is omitted for it; every other item needs one.
|
|
14
|
+
*/
|
|
15
|
+
export interface BatchFixtureItem {
|
|
16
|
+
/** Exact list-item text, as it will appear (one per line) in the batch request message. */
|
|
17
|
+
item: string;
|
|
18
|
+
searchYields: ReadonlyArray<'productive' | 'dead_end'>;
|
|
19
|
+
/** The model's own final per-item answer, once every scripted search yield above has been
|
|
20
|
+
* consumed. Omitted only for an item whose sub-loop resolves via the dead-end window instead
|
|
21
|
+
* (see the doc comment above). */
|
|
22
|
+
finalAnswer?: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* The actual 7-school request from the comparison transcript, in the same order the user pasted
|
|
26
|
+
* them back. Grunewald-Grundschule (cheap — resolved without needing a single search) and
|
|
27
|
+
* Erich-Kästner-Grundschule (expensive — needed several searches before the Terminplan PDF turned
|
|
28
|
+
* up a confirmed date) are items[0]/items[1], so a 7-item batch's probe phase (probeCount = 2)
|
|
29
|
+
* naturally covers both the cheap and the expensive case. Halensee-Grundschule (the genuinely
|
|
30
|
+
* dead 404'd page) sits among the remaining items, proving the item-scoped dead-end window
|
|
31
|
+
* doesn't drag down the other, perfectly findable schools queued behind it.
|
|
32
|
+
*/
|
|
33
|
+
export declare const SCHOOL_DATES_BATCH_FIXTURE: readonly BatchFixtureItem[];
|
|
34
|
+
/** The batch request message a user would actually send — each item on its own line, matching
|
|
35
|
+
* detectHomogeneousBatchList's expected shape. */
|
|
36
|
+
export declare function fixtureUserMessage(items?: readonly BatchFixtureItem[]): string;
|
|
37
|
+
/**
|
|
38
|
+
* The ordered callChatStructured script every item's own sub-loop consumes, in the exact order
|
|
39
|
+
* runBatchToolLoop/resolveRemainingBatchItems resolve them (probe items first, in array order,
|
|
40
|
+
* then the rest in array order) — a ScriptedToolLLMClient (see assistant.test.ts) plays this back
|
|
41
|
+
* verbatim regardless of what the mocked web_search calls actually return.
|
|
42
|
+
*/
|
|
43
|
+
export declare function fixtureStructuredResponses(items?: readonly BatchFixtureItem[]): LLMStructuredResponse[];
|
|
44
|
+
/**
|
|
45
|
+
* A stateful web_search mock consuming `searchYields` in the same flattened order
|
|
46
|
+
* fixtureStructuredResponses schedules its tool calls in — 'dead_end' yields an empty result
|
|
47
|
+
* array (web-tools.ts's executor turns that into the literal "No results found."); 'productive'
|
|
48
|
+
* yields one real-looking result.
|
|
49
|
+
*/
|
|
50
|
+
export declare function fixtureWebSearch(items?: readonly BatchFixtureItem[]): () => Promise<WebSearchResult[]>;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { ToolExecutorContext } from '@buildaharness/harness';
|
|
2
|
+
export interface InjectedFailureOptions {
|
|
3
|
+
/** How many leading harness iterations report a failed execution. */
|
|
4
|
+
failIterations: number;
|
|
5
|
+
/** Recurring same-class `failure_history` records seeded on the first call. */
|
|
6
|
+
seedFailures: number;
|
|
7
|
+
/**
|
|
8
|
+
* How many times the *real* proposer may run after the failure phase (default 2).
|
|
9
|
+
* The first real call is the derailed attempt; a supervisor recovery (a re-queued
|
|
10
|
+
* leaf after GATHER_EVIDENCE / REDIRECT_STRATEGY, S8) gets a second, fresh call so
|
|
11
|
+
* newly gathered evidence in the WorldModel can actually change the answer. Beyond
|
|
12
|
+
* this the last real result is replayed so a thrashing run still converges without
|
|
13
|
+
* unbounded backend cost.
|
|
14
|
+
*/
|
|
15
|
+
maxRealCalls?: number;
|
|
16
|
+
/**
|
|
17
|
+
* Called exactly once, the first time the wrapper actually runs (i.e. the failure was really
|
|
18
|
+
* injected into this turn). The benchmark reads it back as `ArmTurnOutput.injectedFailureFired`
|
|
19
|
+
* so `recoveryRate` only counts tasks where the failure genuinely fired for this arm — not
|
|
20
|
+
* every task that merely *declares* an `injectedFailure` (see
|
|
21
|
+
* plans/feature_audit_fair_comparison_plan.html F2).
|
|
22
|
+
*/
|
|
23
|
+
onInjected?: () => void;
|
|
24
|
+
}
|
|
25
|
+
type Proposer = (toolCtx: ToolExecutorContext) => unknown | Promise<unknown>;
|
|
26
|
+
export declare function wrapProposerWithInjectedFailure(realProposer: Proposer, opts: InjectedFailureOptions): (toolCtx: ToolExecutorContext) => Promise<unknown>;
|
|
27
|
+
export {};
|