@buildaharness/aielia 0.3.4 → 0.3.6
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 +156 -35
- package/dist/PlanGraphPane.d.ts +19 -0
- package/dist/_memory-core-generated.d.ts +1764 -0
- package/dist/action-approval-service.d.ts +34 -2
- package/dist/action-record.d.ts +13 -0
- package/dist/activity-log.d.ts +4 -0
- package/dist/agent-loop.d.ts +106 -9
- 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 +32 -2
- package/dist/assistant-source.d.ts +7 -0
- package/dist/assistant-types.d.ts +20 -2
- package/dist/assistant.d.ts +160 -6
- package/dist/benchmark-injected-failure.d.ts +6 -0
- package/dist/bin-BYRl4xXM.js +4985 -0
- package/dist/bin-BYRl4xXM.js.map +1 -0
- package/dist/cli-config.d.ts +3 -0
- package/dist/cli-session.d.ts +19 -5
- package/dist/cli.d.ts +26 -2
- package/dist/cli.js +1 -1
- package/dist/code-plan-templates.d.ts +21 -0
- package/dist/config.d.ts +31 -0
- package/dist/constraint-check.d.ts +35 -0
- package/dist/contradiction-checker.d.ts +7 -0
- package/dist/debug-log.d.ts +10 -1
- 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/email.d.ts +5 -3
- package/dist/episodic-digest.d.ts +89 -0
- package/dist/fact-extraction.d.ts +39 -0
- package/dist/file-tools-mcp-server.mjs +288 -37
- package/dist/file-tools.d.ts +6 -0
- package/dist/first-run.d.ts +0 -2
- package/dist/git-exclude.d.ts +9 -0
- package/dist/goal-graph-store.d.ts +18 -18
- 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 +21 -2
- package/dist/index.js +166 -94
- package/dist/index.js.map +1 -1
- package/dist/ink-select-prompt.d.ts +2 -0
- package/dist/ink-test-render.d.ts +2 -0
- 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/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 +356 -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 +10 -2
- package/dist/plan-drafting-service.d.ts +3 -0
- 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 +12 -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-CPbB5y_V.js → provider-setup-CV3S_TAS.js} +10792 -5731
- package/dist/provider-setup-CV3S_TAS.js.map +1 -0
- package/dist/recall-tool.d.ts +43 -0
- package/dist/recovery-note.d.ts +22 -0
- package/dist/reply-audit.d.ts +67 -0
- package/dist/response-service.d.ts +11 -1
- 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/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/side-call-policy.d.ts +30 -0
- package/dist/source-reliability.d.ts +71 -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/tool-step.d.ts +6 -0
- package/dist/trace-events.d.ts +1 -1
- package/dist/transcript-compaction.d.ts +9 -0
- package/dist/trust-tagging.d.ts +2 -0
- package/dist/{tui-app-DeyZ4Pr9.js → tui-app-CJq6YaiP.js} +436 -21
- package/dist/tui-app-CJq6YaiP.js.map +1 -0
- package/dist/tui-app.d.ts +73 -0
- package/dist/turn-abort.d.ts +18 -0
- package/dist/turn-intent-classifier.d.ts +81 -14
- package/dist/turn-interpreter.d.ts +27 -3
- package/dist/version.d.ts +1 -1
- package/package.json +6 -6
- package/dist/bin-CdVTAe7j.js +0 -2209
- package/dist/bin-CdVTAe7j.js.map +0 -1
- package/dist/provider-setup-CPbB5y_V.js.map +0 -1
- package/dist/tui-app-DeyZ4Pr9.js.map +0 -1
package/dist/cli-config.d.ts
CHANGED
|
@@ -18,10 +18,13 @@ export declare function isConfigKey(key: string): key is keyof AssistantConfig;
|
|
|
18
18
|
* before this module existed (ASSISTANT_ENABLE_WEB/ASSISTANT_ENABLE_SHELL must be exactly "1").
|
|
19
19
|
*/
|
|
20
20
|
export declare function envOverridesFromProcessEnv(env: NodeJS.ProcessEnv): Partial<AssistantConfig>;
|
|
21
|
+
export declare function findInvalidNumericSettings(config: AssistantConfig): string[];
|
|
21
22
|
/** Thrown by parseConfigValue on a value that doesn't fit the target key's type — cli.ts reports .message and leaves the config unchanged. */
|
|
22
23
|
export declare class ConfigValueParseError extends Error {
|
|
23
24
|
}
|
|
24
25
|
/** Parses a raw `/config set <key> <value>` string into the type AssistantConfig[key] expects. */
|
|
25
26
|
export declare function parseConfigValue(key: keyof AssistantConfig, raw: string): unknown;
|
|
27
|
+
/** A URL with any user:password, and every query-string value, masked, so a credential embedded in proxyUrl is never printed. Text that is not a URL is returned unchanged. */
|
|
28
|
+
export declare function redactUrlCredentials(text: string): string;
|
|
26
29
|
/** Renders /config's full listing as a single multi-line string — cli.ts just console.logs the result. */
|
|
27
30
|
export declare function formatConfigListing(config: AssistantConfig, overriddenKeys: ReadonlySet<keyof AssistantConfig>): string;
|
package/dist/cli-session.d.ts
CHANGED
|
@@ -2,19 +2,23 @@ import { NextStepSuggestion } from './next-step-proposer.js';
|
|
|
2
2
|
import { ChatMessage, TokenUsage } from '@buildaharness/runtime';
|
|
3
3
|
import { AssistantConfig } from './config.js';
|
|
4
4
|
import { MemorySummary, MemoryExport, TranscriptSearchHit, MemoryPendingOutcome } from './assistant.js';
|
|
5
|
+
import { AuditEntry, MemoryStatus, MemoryInjection } from './memory-service.js';
|
|
5
6
|
import { GoalGraphState } from './goal-graph-service.js';
|
|
6
7
|
import { UndoLogEntry } from './action-snapshot.js';
|
|
8
|
+
import { UserFact } from './fact-extraction.js';
|
|
7
9
|
/**
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
10
|
+
* Text that came from the model, a tool result, a file or a web page must not reach the terminal raw: an
|
|
11
|
+
* embedded escape sequence can clear the screen, rewrite earlier lines (hiding what an approval prompt is
|
|
12
|
+
* really asking), set the window title or write the clipboard (OSC 52). Newlines and tabs survive; everything
|
|
13
|
+
* that could drive the terminal is removed. Plain text is returned unchanged.
|
|
12
14
|
*/
|
|
15
|
+
export declare function stripTerminalControls(text: string): string;
|
|
13
16
|
export interface CliCommandHelp {
|
|
14
17
|
command: string;
|
|
15
18
|
description: string;
|
|
16
19
|
}
|
|
17
|
-
/**
|
|
20
|
+
/** A bare `exit` / `quit` (with or without a leading slash, any case) ends the session; anything longer is an ordinary message. An exact command match, not a reading of the message. */
|
|
21
|
+
export declare function isQuitCommand(message: string): boolean;
|
|
18
22
|
export declare const CLI_COMMANDS_HELP: CliCommandHelp[];
|
|
19
23
|
export declare function formatHelp(): string;
|
|
20
24
|
export interface StatusInfo {
|
|
@@ -32,6 +36,16 @@ export declare function formatStatus(info: StatusInfo): string;
|
|
|
32
36
|
/** Renders the result of `/memory confirm`/`/memory reject` — cli.ts's handleMemoryConfirm/handleMemoryReject print this directly. */
|
|
33
37
|
export declare function formatMemoryPendingOutcome(action: 'confirmed' | 'rejected' | 'forgotten', outcome: MemoryPendingOutcome): string;
|
|
34
38
|
export declare function formatMemorySummary(summary: MemorySummary): string;
|
|
39
|
+
/** `/memory history` — one line per audit entry. */
|
|
40
|
+
export declare function formatMemoryHistory(entries: AuditEntry[]): string;
|
|
41
|
+
/** `/memory archive` — facts a newer keyed statement replaced. */
|
|
42
|
+
export declare function formatMemoryArchive(facts: UserFact[], restorableCount?: number): string;
|
|
43
|
+
/** The "Why?" / `/why` line: which stored facts the last reply could have known, and how many were left out. Says "in the prompt", not "used". */
|
|
44
|
+
export declare function formatMemoryInjection(injection: MemoryInjection | undefined): string;
|
|
45
|
+
/** `/memory status` and the memory panel header. */
|
|
46
|
+
export declare function formatMemoryStatus(status: MemoryStatus): string;
|
|
47
|
+
/** `/doctor` entries for memory (CLI via doctor-checks.ts, chat-ui directly — same pure function on both surfaces). */
|
|
48
|
+
export declare function memoryStatusChecks(status: MemoryStatus): DoctorCheck[];
|
|
35
49
|
/** Renders `/memory export`'s full, unbounded contents as pretty-printed JSON — a plain formatting function so it's unit-testable the same way as every other cli-session.ts formatter; cli.ts does the actual file write. */
|
|
36
50
|
export declare function formatMemoryExport(data: MemoryExport): string;
|
|
37
51
|
/** Renders `/search <query>`'s results — each hit is one message (session id short form, timestamp, role, snippet), ranked by relevance, never the whole session it came from. An empty list is an explicit "no results" line, never a silent blank output. */
|
package/dist/cli.d.ts
CHANGED
|
@@ -2,6 +2,8 @@ import { FsBackend } from '@buildaharness/runtime';
|
|
|
2
2
|
import { PersonalAssistant } from './assistant.js';
|
|
3
3
|
import { AssistantConfig, ConfigStore } from './config.js';
|
|
4
4
|
import { NonInteractiveApprovalMode } from './non-interactive-mode.js';
|
|
5
|
+
import { VizNode } from './plan-viz/types.js';
|
|
6
|
+
import { TaskStatus } from '@buildaharness/harness';
|
|
5
7
|
import { KeyedBackend, KeyTestResult } from './provider-setup.js';
|
|
6
8
|
/**
|
|
7
9
|
* One choice in a structured multi-option prompt (Phase 7 of the internal plan
|
|
@@ -16,6 +18,22 @@ export interface SelectOption {
|
|
|
16
18
|
label: string;
|
|
17
19
|
}
|
|
18
20
|
export interface RunCliOptions {
|
|
21
|
+
/**
|
|
22
|
+
* The Ink shell's seam for `/plan graph` (planGraphMode enabled): called with the drawable nodes to open the
|
|
23
|
+
* full-screen pane. Without it (plain REPL, piped input) `/plan graph` prints one static render instead.
|
|
24
|
+
*/
|
|
25
|
+
openPlanGraph?: (nodes: VizNode[]) => void;
|
|
26
|
+
/** Live per-task statuses from a running turn, forwarded for the open plan graph pane. */
|
|
27
|
+
onPlanProgress?: (tasks: {
|
|
28
|
+
id: string;
|
|
29
|
+
status: TaskStatus;
|
|
30
|
+
}[]) => void;
|
|
31
|
+
/**
|
|
32
|
+
* Called with true when a conversational turn starts being worked on and false when it has finished (in a
|
|
33
|
+
* `finally`, so also after an error) — including turns run as deferred follow-ups, which no `dispatchLine()`
|
|
34
|
+
* promise covers. The TUI's liveness indicator follows this rather than guessing from output events.
|
|
35
|
+
*/
|
|
36
|
+
onTurnBusyChange?: (busy: boolean) => void;
|
|
19
37
|
dataDir?: string;
|
|
20
38
|
configStore?: ConfigStore;
|
|
21
39
|
backend?: FsBackend;
|
|
@@ -39,8 +57,6 @@ export interface RunCliOptions {
|
|
|
39
57
|
askSelect?: (question: string, options: SelectOption[]) => Promise<string>;
|
|
40
58
|
/** Test seam: skip the interactive first-run setup regardless of TTY state (also implied when `assistant` is passed). */
|
|
41
59
|
skipFirstRunSetup?: boolean;
|
|
42
|
-
/** Test seam: stub `claude` binary detection for the first-run setup. */
|
|
43
|
-
detectClaudeCli?: () => Promise<boolean>;
|
|
44
60
|
/** Test seam: script the first-run setup's line reads. */
|
|
45
61
|
firstRunAsk?: (question: string) => Promise<string>;
|
|
46
62
|
/** Test seam: stub the live API-key check in the first-run setup (defaults to a real call to the provider). */
|
|
@@ -59,6 +75,11 @@ export interface CliInstance {
|
|
|
59
75
|
* readline REPL or by non-interactive/piped mode — only the TUI shell polls this.
|
|
60
76
|
*/
|
|
61
77
|
getStatusIndicators(): Promise<string[]>;
|
|
78
|
+
/** Read-only: the plan graph's drawable nodes (with `live` statuses overlaid), or undefined when planGraphMode is disabled or there is no plan. Feeds the TUI's open plan graph pane. */
|
|
79
|
+
getPlanGraphNodes(live?: {
|
|
80
|
+
id: string;
|
|
81
|
+
status: TaskStatus;
|
|
82
|
+
}[]): Promise<VizNode[] | undefined>;
|
|
62
83
|
}
|
|
63
84
|
/**
|
|
64
85
|
* The CLI's REPL, parameterized so cli.test.ts can import and drive it directly instead of only
|
|
@@ -82,6 +103,9 @@ export declare function runCli(options?: RunCliOptions): Promise<CliInstance>;
|
|
|
82
103
|
* `runTuiApp` is imported dynamically so a disabled (the default) or non-TTY run never loads Ink
|
|
83
104
|
* at all — `main()` behaves byte-for-byte as it does today in both those cases.
|
|
84
105
|
*/
|
|
106
|
+
/** A reason the assistant refuses to start (invalid configuration, unusable environment): shown to the user verbatim, exit code 1. */
|
|
107
|
+
export declare class StartupError extends Error {
|
|
108
|
+
}
|
|
85
109
|
export declare function main(argv?: readonly string[]): Promise<void>;
|
|
86
110
|
/**
|
|
87
111
|
* True when `entryArg` (a `process.argv[1]` value) refers to the same file as
|
package/dist/cli.js
CHANGED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { ProcessConcept } from '@buildaharness/harness';
|
|
2
|
+
import { PlanTemplate } from './plan-templates/index.js';
|
|
3
|
+
/**
|
|
4
|
+
* `AUDIT_CODE_PLAN_TEMPLATES` gate. Default **OFF**: the plan templates are the seven general-purpose ones, exactly as
|
|
5
|
+
* before. On, the harness's four bundled process concepts (debug a failing test, implement a feature, review code,
|
|
6
|
+
* refactor a module — `packages/harness/src/concepts/`) are offered as plan templates too, so the turn-intent
|
|
7
|
+
* classifier can match a code-shaped request to one and the request goes through the ordinary plan path (approval,
|
|
8
|
+
* persistence, per-step prompts, criteria). Until now nothing in aielia could reach those concepts. A truthy value
|
|
9
|
+
* (`1` / `true` / `on` / `yes` / `enabled`) enables it. Read where `plan-templates` builds its list.
|
|
10
|
+
*/
|
|
11
|
+
export declare function codePlanTemplatesEnabled(env?: Record<string, string | undefined>): boolean;
|
|
12
|
+
/**
|
|
13
|
+
* A process concept as a plan template. Step order, dependencies, risk and abstraction level come from the harness's
|
|
14
|
+
* own `seedTaskGraph` (so the level mapping is not copied here); a step's success criteria are appended to its
|
|
15
|
+
* text as "Done when …" because a plan task has no criteria field of its own. Dropped on purpose: the
|
|
16
|
+
* concept's `expectedTools` (their names — `run_tests`, … — are not aielia's tools and would mislead the model) and
|
|
17
|
+
* `strategyHint` (a plan task has nowhere to carry it).
|
|
18
|
+
*/
|
|
19
|
+
export declare function conceptToPlanTemplate(concept: ProcessConcept): PlanTemplate;
|
|
20
|
+
/** The bundled process concepts as plan templates, keyed by concept id. Built once. */
|
|
21
|
+
export declare function codePlanTemplates(): Record<string, PlanTemplate>;
|
package/dist/config.d.ts
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import { OneLoopMode } from './one-loop-flag.js';
|
|
2
2
|
import { AskMode } from './ask-mode-flag.js';
|
|
3
|
+
import { AmbiguityGuardMode } from './ambiguity-guard-flag.js';
|
|
3
4
|
import { PlanRolloutMode } from './plan-mode-flag.js';
|
|
4
5
|
import { TuiMode } from './tui-mode-flag.js';
|
|
5
6
|
import { UpdateCheckMode } from './update-check-flag.js';
|
|
6
7
|
import { GoalGraphMode } from './goal-graph-flag.js';
|
|
8
|
+
import { PlanGraphMode } from './plan-graph-flag.js';
|
|
9
|
+
import { LayerPolicyMode } from './layer-policy-flag.js';
|
|
7
10
|
import { GoalGraphSuggestMode } from './goal-graph-suggest-flag.js';
|
|
11
|
+
import { MemoryWriteMode } from './memory-governance.js';
|
|
8
12
|
export interface AssistantConfig {
|
|
9
13
|
llmBackend: 'proxy' | 'claude-cli' | 'anthropic' | 'openai' | 'openrouter';
|
|
10
14
|
proxyUrl: string;
|
|
@@ -92,6 +96,10 @@ export interface AssistantConfig {
|
|
|
92
96
|
sessionCostLimitUsd?: number;
|
|
93
97
|
/** Secondary ceiling on completed turns this session — see SpendCapConfig's doc comment in spend-cap.ts for why this counts turns, not raw internal LLM calls. */
|
|
94
98
|
sessionCallLimit?: number;
|
|
99
|
+
/** M1: character budget for the per-turn facts block under `AUDIT_MEMORY_BUDGETED_RENDER`. Undefined = DEFAULT_MEMORY_BUDGET_CHARS (memory-service.ts). */
|
|
100
|
+
memoryBudgetChars?: number;
|
|
101
|
+
/** M6: where model-originated memory writes may land — `auto` | `staged` (default) | `user_only`; see memory-governance.ts. */
|
|
102
|
+
memoryWriteMode?: MemoryWriteMode;
|
|
95
103
|
/**
|
|
96
104
|
* R5 of the internal plan — the rollout flag for the harness-driven
|
|
97
105
|
* one-loop proposer (see one-loop-flag.ts's doc comment for the full rationale). Undefined (the
|
|
@@ -127,6 +135,8 @@ export interface AssistantConfig {
|
|
|
127
135
|
* out of DEFAULT_CONFIG so an unset value stays undefined.
|
|
128
136
|
*/
|
|
129
137
|
planMode?: PlanRolloutMode;
|
|
138
|
+
/** AL3a — ask a clarifying question before staging an under-specified consequential request. See ambiguity-guard-flag.ts. Undefined = 'disabled'. */
|
|
139
|
+
ambiguityGuardMode?: AmbiguityGuardMode;
|
|
130
140
|
/**
|
|
131
141
|
* Phase 4 of the internal plan — the rollout flag for the
|
|
132
142
|
* Ink-driven pinned-bottom-input interactive shell (tui-app.ts's runTuiApp()). Undefined (the
|
|
@@ -147,6 +157,8 @@ export interface AssistantConfig {
|
|
|
147
157
|
* check, never the explicit `aielia update` command. CLI-only, like `tuiMode`.
|
|
148
158
|
*/
|
|
149
159
|
updateCheck?: UpdateCheckMode;
|
|
160
|
+
/** Colour theme of the chat-ui/desktop window: 'system' (default, follows the OS), 'dark' or 'light'. The CLI ignores it. */
|
|
161
|
+
theme?: 'system' | 'dark' | 'light';
|
|
150
162
|
/**
|
|
151
163
|
* The project label newly captured project-scoped facts are tagged with, and the one
|
|
152
164
|
* project-scoped facts are filtered against when building a turn's context (see
|
|
@@ -170,6 +182,19 @@ export interface AssistantConfig {
|
|
|
170
182
|
* comment for why that was deliberate up to now.
|
|
171
183
|
*/
|
|
172
184
|
goalGraphMode?: GoalGraphMode;
|
|
185
|
+
/**
|
|
186
|
+
* Read-only plan-graph view (plans/plan_visualization_plan.html). 'disabled' (the package default,
|
|
187
|
+
* kept out of DEFAULT_CONFIG like goalGraphMode) leaves every surface byte-identical to before.
|
|
188
|
+
* Presentation only — never added to LAYER_SETTINGS.
|
|
189
|
+
*/
|
|
190
|
+
planGraphMode?: PlanGraphMode;
|
|
191
|
+
/**
|
|
192
|
+
* AL7b of plans/adaptive_layer_selection_plan.html — 'static' (default; also the kill switch) |
|
|
193
|
+
* 'shadow' (record what adaptive would decide, execute static) | 'adaptive'. Undefined falls back
|
|
194
|
+
* to `DEFAULT_LAYER_POLICY_MODE`. Chain: `ASSISTANT_LAYER_POLICY`, `VITE_ASSISTANT_LAYER_POLICY`,
|
|
195
|
+
* `/config set layerPolicyMode`; consumed via `isAdaptivePolicyEnabled()`.
|
|
196
|
+
*/
|
|
197
|
+
layerPolicyMode?: LayerPolicyMode;
|
|
173
198
|
/**
|
|
174
199
|
* Phase 8 — the same shared config seam as `goalGraphMode` above, for the next-step proposer's
|
|
175
200
|
* (Tier 1.5) independent gate (Q8: a regression there shouldn't block Tier 0/1). Undefined
|
|
@@ -177,6 +202,12 @@ export interface AssistantConfig {
|
|
|
177
202
|
* set` chain, via `ASSISTANT_GOAL_GRAPH_SUGGEST`/`VITE_ASSISTANT_GOAL_GRAPH_SUGGEST`.
|
|
178
203
|
*/
|
|
179
204
|
goalGraphSuggestMode?: GoalGraphSuggestMode;
|
|
205
|
+
/**
|
|
206
|
+
* Per-layer on/off choices for the reasoning layers (layer-settings.ts's LAYER_SETTINGS), keyed by layer id. An absent id means
|
|
207
|
+
* "the layer's own default". Applied onto the layers' `AUDIT_*` env flags by `applyLayerSettings`; a flag already set in the real
|
|
208
|
+
* environment wins and renders pinned. Edited with the CLI's `/layers` and the Settings screen's Layers section, not `/config set`.
|
|
209
|
+
*/
|
|
210
|
+
layers?: Record<string, boolean>;
|
|
180
211
|
}
|
|
181
212
|
/** Every AssistantConfig key, in the order every surface's settings UI/listing renders them. */
|
|
182
213
|
export declare const CONFIG_KEYS: readonly (keyof AssistantConfig)[];
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { ILLMClient, TokenUsage } from '@buildaharness/runtime';
|
|
2
|
+
export interface ConstraintViolation {
|
|
3
|
+
constraint: string;
|
|
4
|
+
reason?: string;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* `AUDIT_SEMANTIC_CONSTRAINT_CHECK` gate. Default **ON**: the harness's lexical caller-constraint check throws on any
|
|
8
|
+
* reply that names the constraint's subject — including one that obeys it — so this replaces it rather than adding
|
|
9
|
+
* to it, and only runs when the caller has set a constraint (the lexical check's own precondition). Set to a falsy
|
|
10
|
+
* value (`0` / `false` / `off` / `no` / `disabled`) to keep the lexical check. Read at exactly one site: harness-bridge.ts.
|
|
11
|
+
*/
|
|
12
|
+
export declare function semanticConstraintCheckEnabled(env?: Record<string, string | undefined>): boolean;
|
|
13
|
+
/**
|
|
14
|
+
* What to append to a reply the judge still found breaking a constraint after the one revision (the harness hands the answer
|
|
15
|
+
* back with the violation instead of failing the turn). Empty when nothing is unresolved.
|
|
16
|
+
*/
|
|
17
|
+
export declare function renderUnresolvedConstraintNote(violations: ReadonlyArray<ConstraintViolation> | undefined): string;
|
|
18
|
+
/** Most standing constraints kept per session; the oldest drop first. */
|
|
19
|
+
export declare const MAX_STANDING_CONSTRAINTS = 8;
|
|
20
|
+
/**
|
|
21
|
+
* Standing constraints plus the ones stated now: trimmed, de-duplicated (case-insensitive), the newest last, capped at
|
|
22
|
+
* MAX_STANDING_CONSTRAINTS (oldest dropped). A constraint restated moves to the end rather than appearing twice.
|
|
23
|
+
*/
|
|
24
|
+
export declare function mergeStandingConstraints(existing: readonly string[], incoming: readonly string[]): string[];
|
|
25
|
+
/**
|
|
26
|
+
* One bounded LLM call: does this reply break any of these constraints? Fails open — an error, an empty reply or an
|
|
27
|
+
* unparseable answer is "no violations", so a broken check can never fail a turn that would have passed. Only
|
|
28
|
+
* constraints the caller actually set are reported (a constraint the model invented is dropped).
|
|
29
|
+
*/
|
|
30
|
+
export declare function checkConstraints(input: {
|
|
31
|
+
constraints: string[];
|
|
32
|
+
reply: string;
|
|
33
|
+
}, llmClient: ILLMClient, model?: string, onUsage?: (usage: TokenUsage) => void): Promise<{
|
|
34
|
+
violated: ConstraintViolation[];
|
|
35
|
+
}>;
|
|
@@ -15,6 +15,13 @@ export declare function looksLikeCodingFact(statement: string): boolean;
|
|
|
15
15
|
* site — `harness-bridge.ts`, where the `contradictionChecker` host hook is wired.
|
|
16
16
|
*/
|
|
17
17
|
export declare function semanticContradictionEnabled(env?: Record<string, string | undefined>): boolean;
|
|
18
|
+
/**
|
|
19
|
+
* `AUDIT_SEMANTIC_CONTRADICTION_SEVERITY` (default OFF). The checker used to set no severity, so every semantic
|
|
20
|
+
* contradiction recorded as MEDIUM and Tier 1 (DENY) was unreachable through it. On: the judgment also grades each
|
|
21
|
+
* contradiction, and only "HIGH" (two claims that directly and explicitly cannot both hold) is passed on — anything
|
|
22
|
+
* else, or a missing/unknown value, stays MEDIUM. Never LOW or SYSTEM_BREAKING.
|
|
23
|
+
*/
|
|
24
|
+
export declare function semanticContradictionSeverityEnabled(env?: Record<string, string | undefined>): boolean;
|
|
18
25
|
/** A newBelief restating/reinforcing an uncertainFacts or rejectedFacts entry in different words — see checkForContradictions' doc comment. Caller resolves which pool `existingId` came from by id membership (both ids are always from this call's own known-id set, filtered below). */
|
|
19
26
|
export interface Corroboration {
|
|
20
27
|
existingId: string;
|
package/dist/debug-log.d.ts
CHANGED
|
@@ -5,12 +5,21 @@
|
|
|
5
5
|
* caller opts into this explicitly (see PersonalAssistantOptions.onDebugLog) knowing it
|
|
6
6
|
* carries real content, not just metadata.
|
|
7
7
|
*
|
|
8
|
+
* `approval_request` is a state-changing action (write/shell/email) staged for the user's yes/no, and
|
|
9
|
+
* `approval_decision` is how that was resolved ('approved' or 'declined'); the executed result of an
|
|
10
|
+
* approved action is the separate `tool_call` entry, so a log reader can reconstruct the whole exchange.
|
|
11
|
+
*
|
|
12
|
+
* `next_steps` is the numbered list of suggestions printed under a reply (one entry per turn that produced any).
|
|
13
|
+
*
|
|
14
|
+
* `note` records a robustness action the loop took on its own (an empty final answer retried, or replaced by a
|
|
15
|
+
* deterministic fallback), so a log reader can see why a reply is not what the model first returned.
|
|
16
|
+
*
|
|
8
17
|
* Split into its own file so both assistant.ts (user_message/assistant_reply kinds, emitted from
|
|
9
18
|
* `turn()`) and agent-loop.ts (tool_call kind, emitted from the ReAct loop) can depend on it
|
|
10
19
|
* without either owning the other.
|
|
11
20
|
*/
|
|
12
21
|
export interface DebugLogEntry {
|
|
13
|
-
kind: 'user_message' | 'assistant_reply' | 'tool_call';
|
|
22
|
+
kind: 'user_message' | 'user_message_queued' | 'assistant_reply' | 'tool_call' | 'approval_request' | 'approval_decision' | 'note' | 'next_steps';
|
|
14
23
|
sessionId: string;
|
|
15
24
|
content: string;
|
|
16
25
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `AUDIT_DECOMPOSED_ANSWER_ONCE` gate. Default **ON**: an ordinary turn the classifier split into several
|
|
3
|
+
* subtasks answers the user once, and the later subtasks reuse that answer. A falsy value (`0` / `false` /
|
|
4
|
+
* `off` / `no` / `disabled`) restores the one-answer-per-subtask behaviour. Read at exactly one site:
|
|
5
|
+
* assistant.ts, where the proposer is wired.
|
|
6
|
+
*
|
|
7
|
+
* Why: the harness runs each subtask through the same proposer, and every call was given only the user's
|
|
8
|
+
* message, so a request split into nine subtasks produced the complete answer thirteen times and returned
|
|
9
|
+
* the last one. (The pre-one-loop path computed one reply and handed it to every task; this restores that.)
|
|
10
|
+
* A plan's steps are different — each is real work and gets its own instruction (plan-step-prompt.ts) — so
|
|
11
|
+
* they are not affected.
|
|
12
|
+
*/
|
|
13
|
+
export declare function decomposedAnswerOnceEnabled(env?: Record<string, string | undefined>): boolean;
|
|
@@ -7,6 +7,8 @@ import { ILLMClient, TokenUsage } from '@buildaharness/runtime';
|
|
|
7
7
|
* silently create several reminders in one turn.
|
|
8
8
|
*/
|
|
9
9
|
export declare function looksLikeEnumeratedItems(message: string): boolean;
|
|
10
|
+
/** The raw lexical enumeration check, used inside `classifyRisk`'s bulk-reminder gate — which is itself switched by lexicalMode's `risk` family. */
|
|
11
|
+
export declare function looksLikeEnumeratedItemsLexical(message: string): boolean;
|
|
10
12
|
export interface DecomposedTaskSpec {
|
|
11
13
|
id: string;
|
|
12
14
|
description: string;
|
package/dist/doctor-checks.d.ts
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { FsBackend } from '@buildaharness/runtime';
|
|
2
2
|
import { DoctorCheck } from './cli-session.js';
|
|
3
|
+
import { MemoryStatus } from './memory-service.js';
|
|
3
4
|
/** GET <proxyUrl>/health, expecting {status:'ok'} (see packages/proxy/src/index.ts) — hard-timed so a dead proxy can't hang /doctor. */
|
|
4
5
|
export declare function checkProxyHealth(proxyUrl: string): Promise<DoctorCheck>;
|
|
5
6
|
/** Spawns `<claudePath> --version`, same path resolution ClaudeCliLLMClient uses — hard-timed so a hung/missing binary can't hang /doctor. */
|
|
6
7
|
export declare function checkClaudeCli(claudePath: string): Promise<DoctorCheck>;
|
|
8
|
+
/** M6: memory store size vs budget, pending count, last consolidation, audit-log size. The rendering is the shared pure `memoryStatusChecks` (chat-ui calls it too). */
|
|
9
|
+
export declare function checkMemoryHealth(status: MemoryStatus): DoctorCheck[];
|
|
7
10
|
export declare function checkWorkspaceRoot(workspaceRoot: string): Promise<DoctorCheck>;
|
|
8
11
|
export declare function checkDataDirWritable(backend: FsBackend, dataDir: string): Promise<DoctorCheck>;
|
package/dist/email.d.ts
CHANGED
|
@@ -53,8 +53,10 @@ export interface ResendSenderOptions {
|
|
|
53
53
|
*/
|
|
54
54
|
export declare function createResendSender(options: ResendSenderOptions): SendEmail;
|
|
55
55
|
/**
|
|
56
|
-
*
|
|
56
|
+
* Human-readable summary of a staged email, for the approval prompt and trace. Kept here
|
|
57
57
|
* (not in agent-loop.ts) so the MCP server (file-tools-mcp-server.mjs) and the CLI can format the
|
|
58
|
-
* same way without importing the loop.
|
|
58
|
+
* same way without importing the loop. The approver must see everything that will be sent: every
|
|
59
|
+
* recipient (Cc/Bcc included, since a hidden Bcc is a silent exfiltration channel) and the whole
|
|
60
|
+
* body, never a truncated preview.
|
|
59
61
|
*/
|
|
60
|
-
export declare function formatEmailApprovalReason(message: Pick<EmailMessage, 'to' | 'subject' | 'body'>): string;
|
|
62
|
+
export declare function formatEmailApprovalReason(message: Pick<EmailMessage, 'to' | 'subject' | 'body' | 'cc' | 'bcc'>): string;
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { ChatMessage, ILLMClient, MemoryAdapter, TokenUsage } from '@buildaharness/runtime';
|
|
2
|
+
import { UserFact } from './fact-extraction.js';
|
|
3
|
+
/**
|
|
4
|
+
* Episodic tier (M3 of the agent memory framework plan): one rolling handoff digest per conversation,
|
|
5
|
+
* kept apart from durable facts. Never injected into the prompt; read by the recall tool.
|
|
6
|
+
*
|
|
7
|
+
* STORAGE CONTRACT (the recall tool codes against this): a digest lives at `episodic:<digestId>` as a
|
|
8
|
+
* `SessionDigest`. `digestId` is `<sessionId>:<conversationId>` because a CLI/chat-ui session id is
|
|
9
|
+
* reused across `/new`, so a bare session id would overwrite the previous conversation's digest.
|
|
10
|
+
* The id of every live digest is listed in `episodic-index` (the MemoryAdapter has no key listing).
|
|
11
|
+
*/
|
|
12
|
+
export interface SessionDigest {
|
|
13
|
+
/** The digest id (the key suffix), not necessarily the raw session id: `<sessionId>:<conversationId>`. */
|
|
14
|
+
sessionId: string;
|
|
15
|
+
/** ISO time of the last write (the digest is rolling; retention counts from here). */
|
|
16
|
+
createdAt: string;
|
|
17
|
+
oneLine: string;
|
|
18
|
+
objective: string;
|
|
19
|
+
done: string[];
|
|
20
|
+
decisions: string[];
|
|
21
|
+
openItems: string[];
|
|
22
|
+
nextStep: string;
|
|
23
|
+
/** Set when the judge found the digest instruction-shaped. It is still untrusted context; the recall tool wraps it either way. */
|
|
24
|
+
flagged?: boolean;
|
|
25
|
+
}
|
|
26
|
+
export declare const EPISODIC_KEY_PREFIX = "episodic:";
|
|
27
|
+
export declare const EPISODIC_INDEX_KEY = "episodic-index";
|
|
28
|
+
/** D4: start at 90 days, calibrate. `AUDIT_EPISODIC_RETENTION_DAYS` overrides. */
|
|
29
|
+
export declare const DEFAULT_RETENTION_DAYS = 90;
|
|
30
|
+
/** `AUDIT_EPISODIC_DIGEST`: the digest writer and the pre-compaction flush. Default OFF; `1/true/on/yes/enabled` enables. Read where the writer is invoked (assistant.ts). */
|
|
31
|
+
export declare function episodicDigestEnabled(env?: Record<string, string | undefined>): boolean;
|
|
32
|
+
export declare function episodicRetentionDays(env?: Record<string, string | undefined>): number;
|
|
33
|
+
/** Read side, and the owner of the digest keys. The recall tool builds one of these over the same MemoryAdapter. */
|
|
34
|
+
export declare class DigestStore {
|
|
35
|
+
private readonly memory;
|
|
36
|
+
constructor(memory: MemoryAdapter);
|
|
37
|
+
private ids;
|
|
38
|
+
/** One digest by id, or undefined when absent or past retention. Never writes. */
|
|
39
|
+
getDigest(id: string): Promise<SessionDigest | undefined>;
|
|
40
|
+
/** The most recent `limit` digests (default 10), newest first, past-retention ones excluded. Never writes. */
|
|
41
|
+
listDigests(limit?: number): Promise<SessionDigest[]>;
|
|
42
|
+
/** Writes one digest and prunes past-retention ones (D4). The only place episodic keys are written. */
|
|
43
|
+
put(digest: SessionDigest): Promise<void>;
|
|
44
|
+
pruneExpired(): Promise<number>;
|
|
45
|
+
/** `/memory forget digest <id>` / `/memory forget digests` (no id). Returns how many were removed, expired ones included. */
|
|
46
|
+
forget(id?: string): Promise<number>;
|
|
47
|
+
/** Every stored digest, unbounded and ignoring retention, for `/memory export`. */
|
|
48
|
+
exportAll(): Promise<SessionDigest[]>;
|
|
49
|
+
}
|
|
50
|
+
export declare function listDigests(memory: MemoryAdapter, limit?: number): Promise<SessionDigest[]>;
|
|
51
|
+
export declare function getDigest(memory: MemoryAdapter, id: string): Promise<SessionDigest | undefined>;
|
|
52
|
+
/** The id of `sessionId`'s current conversation, minted on first need and cleared by `endConversation` (after the final digest). */
|
|
53
|
+
export declare function conversationDigestId(memory: MemoryAdapter, sessionId: string): Promise<string>;
|
|
54
|
+
export declare function endConversation(memory: MemoryAdapter, sessionId: string): Promise<void>;
|
|
55
|
+
/** The marker scripted-llm-client.ts's SIDE_CALL_MARKERS keys on. */
|
|
56
|
+
export declare const DIGEST_SYSTEM_MARKER = "You write a session handoff digest";
|
|
57
|
+
type DigestBody = Omit<SessionDigest, 'sessionId' | 'createdAt' | 'flagged'>;
|
|
58
|
+
export interface DigestCallResult {
|
|
59
|
+
body: DigestBody;
|
|
60
|
+
flagged: boolean;
|
|
61
|
+
facts: UserFact[];
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* One bounded call. Returns null on any error, unparseable output, empty digest, or a MISSING secret/instruction
|
|
65
|
+
* judgement — this write fails closed (a missed secret would reach disk), the one deliberate exception to "side
|
|
66
|
+
* calls fail open"; the consequence of null is only that no digest is written. The whole digest goes through
|
|
67
|
+
* `admitCandidate` with the gate forced on (independent of AUDIT_MEMORY_WRITE_GATE): a flagged secret is
|
|
68
|
+
* replaced by the model's `redactedDigest` (an unusable redaction drops the digest).
|
|
69
|
+
*/
|
|
70
|
+
export declare function callDigest(llm: ILLMClient, input: {
|
|
71
|
+
messages: ChatMessage[];
|
|
72
|
+
prior?: SessionDigest;
|
|
73
|
+
extractFacts: boolean;
|
|
74
|
+
digestId: string;
|
|
75
|
+
sessionId: string;
|
|
76
|
+
}, model?: string, onUsage?: (usage: TokenUsage) => void): Promise<DigestCallResult | null>;
|
|
77
|
+
/**
|
|
78
|
+
* Writes/refreshes the conversation's digest from `messages`, folding in whatever digest already exists. Fails open for
|
|
79
|
+
* the caller (returns null, writes nothing, no partial entry). Never touches DURABLE_FACTS_KEY.
|
|
80
|
+
*/
|
|
81
|
+
export declare function writeDigest(memory: MemoryAdapter, llm: ILLMClient, args: {
|
|
82
|
+
sessionId: string;
|
|
83
|
+
messages: ChatMessage[];
|
|
84
|
+
extractFacts: boolean;
|
|
85
|
+
}, model?: string, onUsage?: (usage: TokenUsage) => void): Promise<{
|
|
86
|
+
digest: SessionDigest;
|
|
87
|
+
facts: UserFact[];
|
|
88
|
+
} | null>;
|
|
89
|
+
export {};
|
|
@@ -70,6 +70,37 @@ export interface UserFact {
|
|
|
70
70
|
* project is currently active.
|
|
71
71
|
*/
|
|
72
72
|
project?: string;
|
|
73
|
+
/**
|
|
74
|
+
* M1 (agent memory framework): a model-chosen stable key for a fact naming a single-valued
|
|
75
|
+
* attribute ("home_city", "preferred_editor"). A new fact with the same key replaces the old
|
|
76
|
+
* one (see `MemoryService.recordFacts()`). Never derived from wording in code; undefined for
|
|
77
|
+
* a fact that names no single-valued attribute, which keeps today's accumulate behaviour.
|
|
78
|
+
*/
|
|
79
|
+
key?: string;
|
|
80
|
+
/** M1: set on the replacing fact — the text of the entry it retired. */
|
|
81
|
+
supersedes?: string;
|
|
82
|
+
/** M1: set on an entry moved to `facts:retired` when a keyed fact replaced it. */
|
|
83
|
+
retiredAt?: string;
|
|
84
|
+
/** M1 usage fields, updated lazily (batched, flushed from `recordFacts()`) when the fact is rendered into a prompt. */
|
|
85
|
+
injectedCount?: number;
|
|
86
|
+
lastInjectedAt?: string;
|
|
87
|
+
/** M2: where the claim came from. Undefined = `user`. A non-`user` origin can only ever be episodic (see `tierForFact`). */
|
|
88
|
+
origin?: FactOrigin;
|
|
89
|
+
/** M2: the user's own supporting words for a `model_inferred` claim, returned by the classifier. Stored for audit/`/memory` display, never string-matched. */
|
|
90
|
+
evidence?: string;
|
|
91
|
+
/** M2: set on a pending entry the write gate's semantic injection judgement flagged as instruction-shaped; never auto-promoted. */
|
|
92
|
+
flagged?: boolean;
|
|
93
|
+
/** M2: transient classifier judgement carried from `buildTurnFacts` to the write gate; stripped before anything is persisted. */
|
|
94
|
+
judgement?: CandidateJudgement;
|
|
95
|
+
}
|
|
96
|
+
/** M2: structured provenance next to `FactSource`; only `user` may reach a Knowledge tier. */
|
|
97
|
+
export type FactOrigin = 'user' | 'agent' | 'tool' | 'web';
|
|
98
|
+
/** M2: the classifier's per-fact judgement. Either field undefined means the judgement is missing (the gate fails closed). */
|
|
99
|
+
export interface CandidateJudgement {
|
|
100
|
+
containsSecret?: boolean;
|
|
101
|
+
/** Fact text with the secret removed; empty/undefined when the whole claim is the secret. */
|
|
102
|
+
redactedText?: string;
|
|
103
|
+
looksLikeInstruction?: boolean;
|
|
73
104
|
}
|
|
74
105
|
/** Every fact has a certainty for `/memory` display purposes, even one with no `confidence` gradient (user_asserted/observed/externally_verified) — those are exactly as certain as a stated fact gets, so they display as 'high' rather than blank. Never used for promotion/tier logic, which still reads `fact.confidence` directly and treats undefined as "no LLM confidence signal" (see that field's own doc comment) — this is purely a rendering convenience. */
|
|
75
106
|
export declare function certaintyLabel(fact: UserFact): FactConfidence;
|
|
@@ -126,6 +157,14 @@ export declare const TIER_RULES: Record<MemoryTier, TierRule>;
|
|
|
126
157
|
* `procedural`/`commitment` are never returned (see `TIER_RULES`'s doc comment).
|
|
127
158
|
*/
|
|
128
159
|
export declare function tierForFact(fact: UserFact): MemoryTier;
|
|
160
|
+
/**
|
|
161
|
+
* The reliability the harness's world model should give this fact's belief — 'HIGH' (confidence
|
|
162
|
+
* 1.0, the >= 0.8 bar the change reviewer and contradiction severity read) for a fact the user
|
|
163
|
+
* stated directly or that has been externally verified, and for a `model_inferred` one that
|
|
164
|
+
* cleared the same durable + high-confidence bar `tierForFact` uses to treat it as Knowledge;
|
|
165
|
+
* everything else stays 'MEDIUM' (0.5), so an unconfirmed guess never reads as an established fact.
|
|
166
|
+
*/
|
|
167
|
+
export declare function factReliability(fact: UserFact): 'HIGH' | 'MEDIUM';
|
|
129
168
|
/** Whether `tier` counts as the Knowledge tier for contradiction-detection purposes — see harness-bridge.ts's factExtractor and TIER_RULES.*.contradictionChecked. */
|
|
130
169
|
export declare function isKnowledgeTier(tier: MemoryTier): boolean;
|
|
131
170
|
/**
|