@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.
Files changed (127) hide show
  1. package/README.md +832 -0
  2. package/dist/action-approval-service.d.ts +52 -0
  3. package/dist/action-snapshot.d.ts +173 -0
  4. package/dist/action-tools.d.ts +38 -0
  5. package/dist/agent-loop.d.ts +372 -0
  6. package/dist/answer-claim.d.ts +51 -0
  7. package/dist/ask-clarification-service.d.ts +70 -0
  8. package/dist/ask-mode-flag.d.ts +25 -0
  9. package/dist/ask-response-format.d.ts +8 -0
  10. package/dist/assistant-session.d.ts +267 -0
  11. package/dist/assistant-source.d.ts +14 -0
  12. package/dist/assistant-types.d.ts +158 -0
  13. package/dist/assistant.d.ts +419 -0
  14. package/dist/batch-list-detector.d.ts +15 -0
  15. package/dist/batch-research-fixtures.d.ts +50 -0
  16. package/dist/benchmark-injected-failure.d.ts +27 -0
  17. package/dist/claude-cli-llm-client.d.ts +139 -0
  18. package/dist/claude-cli-prompt.d.ts +86 -0
  19. package/dist/cli-config.d.ts +27 -0
  20. package/dist/cli-session-D0uLdT2A.js +7863 -0
  21. package/dist/cli-session-D0uLdT2A.js.map +1 -0
  22. package/dist/cli-session.d.ts +63 -0
  23. package/dist/cli.d.ts +65 -0
  24. package/dist/cli.js +1693 -0
  25. package/dist/cli.js.map +1 -0
  26. package/dist/config.d.ts +175 -0
  27. package/dist/contradiction-checker.d.ts +27 -0
  28. package/dist/debug-log.d.ts +16 -0
  29. package/dist/decomposition-classifier.d.ts +38 -0
  30. package/dist/doctor-checks.d.ts +8 -0
  31. package/dist/email-smtp.d.ts +19 -0
  32. package/dist/email.d.ts +60 -0
  33. package/dist/error-classifier.d.ts +13 -0
  34. package/dist/execution-mode.d.ts +85 -0
  35. package/dist/fact-extraction.d.ts +143 -0
  36. package/dist/failure-mode-matcher.d.ts +32 -0
  37. package/dist/file-tools-mcp-server.mjs +1027 -0
  38. package/dist/file-tools.d.ts +179 -0
  39. package/dist/first-run.d.ts +22 -0
  40. package/dist/harness-bridge.d.ts +103 -0
  41. package/dist/index.d.ts +58 -0
  42. package/dist/index.js +212 -0
  43. package/dist/index.js.map +1 -0
  44. package/dist/ink-test-render.d.ts +24 -0
  45. package/dist/lexical/patterns/batch-list-markers.json +8 -0
  46. package/dist/lexical/patterns/batch-list-markers.json.d.ts +11 -0
  47. package/dist/lexical/patterns/coding-fact-markers.json +8 -0
  48. package/dist/lexical/patterns/coding-fact-markers.json.d.ts +11 -0
  49. package/dist/lexical/patterns/enumeration-markers.json +20 -0
  50. package/dist/lexical/patterns/enumeration-markers.json.d.ts +23 -0
  51. package/dist/lexical/patterns/fact-markers.json +16 -0
  52. package/dist/lexical/patterns/fact-markers.json.d.ts +19 -0
  53. package/dist/lexical/patterns/injection-patterns.json +20 -0
  54. package/dist/lexical/patterns/injection-patterns.json.d.ts +23 -0
  55. package/dist/lexical/patterns/plan-mode-markers.json +10 -0
  56. package/dist/lexical/patterns/plan-mode-markers.json.d.ts +13 -0
  57. package/dist/lexical/patterns/risk-patterns.json +122 -0
  58. package/dist/lexical/patterns/risk-patterns.json.d.ts +125 -0
  59. package/dist/lexical/patterns/task-cancel-markers.json +22 -0
  60. package/dist/lexical/patterns/task-cancel-markers.json.d.ts +25 -0
  61. package/dist/lexical/patterns/template-keywords.json +20 -0
  62. package/dist/lexical/patterns/template-keywords.json.d.ts +23 -0
  63. package/dist/lexical/patterns/tool-yield-markers.json +22 -0
  64. package/dist/lexical/patterns/tool-yield-markers.json.d.ts +25 -0
  65. package/dist/lexical/patterns.d.ts +64 -0
  66. package/dist/memory-service.d.ts +219 -0
  67. package/dist/model-pricing.d.ts +19 -0
  68. package/dist/network-containment.d.ts +21 -0
  69. package/dist/node-config-store.d.ts +29 -0
  70. package/dist/node-display-names.d.ts +26 -0
  71. package/dist/node-fs-backend.d.ts +8 -0
  72. package/dist/non-interactive-mode.d.ts +22 -0
  73. package/dist/one-loop-flag.d.ts +38 -0
  74. package/dist/plan-approval-service.d.ts +62 -0
  75. package/dist/plan-builder.d.ts +32 -0
  76. package/dist/plan-drafting-service.d.ts +87 -0
  77. package/dist/plan-drafting.d.ts +58 -0
  78. package/dist/plan-mode-flag.d.ts +34 -0
  79. package/dist/plan-service.d.ts +61 -0
  80. package/dist/plan-sketch-service.d.ts +24 -0
  81. package/dist/plan-sketch.d.ts +20 -0
  82. package/dist/plan-store.d.ts +232 -0
  83. package/dist/plan-templates/data/content_creation.json.d.ts +75 -0
  84. package/dist/plan-templates/data/decision_making.json.d.ts +66 -0
  85. package/dist/plan-templates/data/problem_solving.json.d.ts +75 -0
  86. package/dist/plan-templates/data/process_improvement.json.d.ts +57 -0
  87. package/dist/plan-templates/data/project_planning.json.d.ts +66 -0
  88. package/dist/plan-templates/data/research_analysis.json.d.ts +66 -0
  89. package/dist/plan-templates/data/trip_planning.json.d.ts +66 -0
  90. package/dist/plan-templates/index.d.ts +33 -0
  91. package/dist/plan-verification.d.ts +31 -0
  92. package/dist/reminder-tools.d.ts +13 -0
  93. package/dist/response-service.d.ts +73 -0
  94. package/dist/review-checker.d.ts +22 -0
  95. package/dist/risk-classifier.d.ts +7 -0
  96. package/dist/scripted-llm-client.d.ts +37 -0
  97. package/dist/semantic-criterion-coverage.d.ts +30 -0
  98. package/dist/shell-executor.d.ts +14 -0
  99. package/dist/shell-tools.d.ts +84 -0
  100. package/dist/spend-cap.d.ts +41 -0
  101. package/dist/spike.d.ts +1 -0
  102. package/dist/spike.js +18 -0
  103. package/dist/spike.js.map +1 -0
  104. package/dist/supervisor-decider.d.ts +3 -0
  105. package/dist/system-prompt.d.ts +8 -0
  106. package/dist/task-mapping.d.ts +42 -0
  107. package/dist/tool-control-plane.d.ts +67 -0
  108. package/dist/tool-policy.d.ts +45 -0
  109. package/dist/tool-step.d.ts +23 -0
  110. package/dist/tool-yield-classifier.d.ts +7 -0
  111. package/dist/trace-events.d.ts +126 -0
  112. package/dist/transcript-compaction.d.ts +13 -0
  113. package/dist/trust-tagging.d.ts +38 -0
  114. package/dist/tui-app-DxLPSGh2.js +481 -0
  115. package/dist/tui-app-DxLPSGh2.js.map +1 -0
  116. package/dist/tui-app.d.ts +125 -0
  117. package/dist/tui-input.d.ts +51 -0
  118. package/dist/tui-mode-flag.d.ts +36 -0
  119. package/dist/tui-output-capture.d.ts +30 -0
  120. package/dist/tui-spike.d.ts +1 -0
  121. package/dist/turn-intent-classifier.d.ts +96 -0
  122. package/dist/turn-interpreter.d.ts +71 -0
  123. package/dist/turn-policy.d.ts +45 -0
  124. package/dist/web-fetch-core.d.ts +65 -0
  125. package/dist/web-search-provider.d.ts +12 -0
  126. package/dist/web-tools.d.ts +26 -0
  127. package/package.json +69 -0
@@ -0,0 +1,27 @@
1
+ import { ILLMClient, TokenUsage } from '@buildaharness/runtime';
2
+ import { ExternalContradictionInput } from '@buildaharness/harness';
3
+ export interface BeliefCandidate {
4
+ id: string;
5
+ statement: string;
6
+ }
7
+ /** Zero-LLM-call gate: true when a belief statement reads like a structured/technical (build, test, service, file) claim rather than a natural-language personal fact. */
8
+ export declare function looksLikeCodingFact(statement: string): boolean;
9
+ /**
10
+ * `AUDIT_SEMANTIC_CONTRADICTION` gate — feature-value audit (Phase A4 of
11
+ * plans/feature_audit_automation_plan.html). Default **ON**: the semantic contradiction-checker
12
+ * LLM call ships enabled, so an unset / empty / truthy value keeps today's behaviour. Set to a
13
+ * falsy value (`0` / `false` / `off` / `no` / `disabled`) to skip the LLM call entirely and fall
14
+ * back to the harness's always-on lexical / negation-pair check only. Read at exactly one call
15
+ * site — `harness-bridge.ts`, where the `contradictionChecker` host hook is wired.
16
+ */
17
+ export declare function semanticContradictionEnabled(env?: Record<string, string | undefined>): boolean;
18
+ /** 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
+ export interface Corroboration {
20
+ existingId: string;
21
+ newId: string;
22
+ }
23
+ export interface ContradictionCheckResult {
24
+ contradictions: ExternalContradictionInput[];
25
+ corroborations: Corroboration[];
26
+ }
27
+ export declare function checkForContradictions(newBeliefs: BeliefCandidate[], existingBeliefs: BeliefCandidate[], llmClient: ILLMClient, model?: string, onUsage?: (usage: TokenUsage) => void, uncertainFacts?: BeliefCandidate[], rejectedFacts?: BeliefCandidate[]): Promise<ContradictionCheckResult>;
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Full conversation content, for a caller that wants live visibility while debugging — a
3
+ * user's message, the assistant's final reply/reason, or one real tool call's name/input/
4
+ * result. Not privacy-scrubbed and not truncated to name-only the way TraceEvent is; a
5
+ * caller opts into this explicitly (see PersonalAssistantOptions.onDebugLog) knowing it
6
+ * carries real content, not just metadata.
7
+ *
8
+ * Split into its own file so both assistant.ts (user_message/assistant_reply kinds, emitted from
9
+ * `turn()`) and agent-loop.ts (tool_call kind, emitted from the ReAct loop) can depend on it
10
+ * without either owning the other.
11
+ */
12
+ export interface DebugLogEntry {
13
+ kind: 'user_message' | 'assistant_reply' | 'tool_call';
14
+ sessionId: string;
15
+ content: string;
16
+ }
@@ -0,0 +1,38 @@
1
+ import { ILLMClient, TokenUsage } from '@buildaharness/runtime';
2
+ /**
3
+ * True if `message` looks like an enumeration of multiple distinct items — the strong signals
4
+ * above (sequencing markers, comma/semicolon/numbered lists), deliberately WITHOUT a word-count
5
+ * fallback: a single long reminder isn't multiple reminders just because it's wordy. Used by
6
+ * risk-classifier.ts to gate bulk reminder creation on confirmation instead of letting the model
7
+ * silently create several reminders in one turn.
8
+ */
9
+ export declare function looksLikeEnumeratedItems(message: string): boolean;
10
+ export interface DecomposedTaskSpec {
11
+ id: string;
12
+ description: string;
13
+ depends_on: string[];
14
+ /**
15
+ * Per-task risk (LOW/MEDIUM/HIGH), not the turn-level risk broadcast across every task —
16
+ * see Phase 4.2 of the harness layer activation plan: a step like "delete the draft file"
17
+ * shouldn't inherit an unrelated sibling step's risk profile just because they were rendered
18
+ * from the same turn. classifyTurnIntent's LLM call judges this directly for ad hoc
19
+ * decompositions; buildPlanFromTemplate (plan-builder.ts) attaches it from the template's own
20
+ * already-curated per-task risk_level instead of asking the LLM to re-derive it.
21
+ */
22
+ riskLevel: 'LOW' | 'MEDIUM' | 'HIGH';
23
+ }
24
+ /**
25
+ * Reframes a single-task turn's description to lead with its subject — the same phrasing
26
+ * classifyTurnIntent's own decomposedTasks and buildPlanFromTemplate (plan-builder.ts) already
27
+ * produce for their own tasks, applied here for the much more common case where a turn goes
28
+ * through neither: an ad hoc single-task turn whose description otherwise stays the raw verbatim userMessage (see
29
+ * assistant.ts's initialTasks fallback). Without this, only decomposed/planned tasks got
30
+ * subject-first descriptions, so the "Completed: <description>" belief statementsOpposed/
31
+ * isNegation compare against was structured for some tasks and not others. Deliberately not
32
+ * called unconditionally — the caller gates this behind looksLikeCodingFact AND riskLevel !==
33
+ * 'LOW' (the actual precondition for a single task's description to ever reach that belief; see
34
+ * assistant.ts's call site for why looksLikeCodingFact alone isn't a safe gate for a new call).
35
+ * Falls back to null (caller keeps the original message) on any parse failure or LLM error,
36
+ * matching this codebase's other LLM-backed classifiers.
37
+ */
38
+ export declare function reframeTaskDescriptionWithLLM(message: string, llmClient: ILLMClient, model?: string, onUsage?: (usage: TokenUsage) => void): Promise<string | null>;
@@ -0,0 +1,8 @@
1
+ import { FsBackend } from '@buildaharness/runtime';
2
+ import { DoctorCheck } from './cli-session.js';
3
+ /** GET <proxyUrl>/health, expecting {status:'ok'} (see packages/proxy/src/index.ts) — hard-timed so a dead proxy can't hang /doctor. */
4
+ export declare function checkProxyHealth(proxyUrl: string): Promise<DoctorCheck>;
5
+ /** Spawns `<claudePath> --version`, same path resolution ClaudeCliLLMClient uses — hard-timed so a hung/missing binary can't hang /doctor. */
6
+ export declare function checkClaudeCli(claudePath: string): Promise<DoctorCheck>;
7
+ export declare function checkWorkspaceRoot(workspaceRoot: string): Promise<DoctorCheck>;
8
+ export declare function checkDataDirWritable(backend: FsBackend, dataDir: string): Promise<DoctorCheck>;
@@ -0,0 +1,19 @@
1
+ import { SendEmail } from './email.js';
2
+ export interface SmtpSenderOptions {
3
+ host: string;
4
+ port: number;
5
+ /** true for implicit TLS (port 465); false for STARTTLS (587) or plain (25). */
6
+ secure?: boolean;
7
+ auth?: {
8
+ user: string;
9
+ pass: string;
10
+ };
11
+ /** Default sender address, used when a message omits `from`. */
12
+ from: string;
13
+ }
14
+ /**
15
+ * SMTP transport via nodemailer. All connection details come from config
16
+ * (ASSISTANT_EMAIL_SMTP_* / config.json), never from the model. `nodemailer` is a dependency of
17
+ * this package but imported dynamically so it is only loaded when SMTP is actually configured.
18
+ */
19
+ export declare function createSmtpSender(options: SmtpSenderOptions): SendEmail;
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Email as a real, approval-gated "effect" tool (adoption plan F2, path (a)).
3
+ *
4
+ * The assistant's flagship demo — "send an email to my boss saying I quit" → the risk gate
5
+ * stops before anything leaves the machine — only means something if there is an actual send
6
+ * behind the gate. `send_email` is that action, staged exactly like `write_file`/`run_shell_command`
7
+ * (see file-tools.ts's stagePendingAction): the model can only ever *propose* a message, never
8
+ * deliver one, and `applyPendingAction` calls the injected `SendEmail` transport only after a human
9
+ * approves the concrete recipient/subject/body.
10
+ *
11
+ * This module is browser-safe (no static Node imports) so it can be reached from
12
+ * assistant.ts/index.ts, which chat-ui bundles. The Resend transport below is pure `fetch`. The
13
+ * SMTP transport lives in email-smtp.ts (Node-only, lazy-loads nodemailer) and is wired in only by
14
+ * Node callers (cli.ts), the same split shell-executor.ts / node-fs-backend.ts already use.
15
+ */
16
+ /** A concrete message the model has proposed. `from` is filled in by the transport if omitted. */
17
+ export interface EmailMessage {
18
+ to: string;
19
+ subject: string;
20
+ body: string;
21
+ from?: string;
22
+ cc?: string;
23
+ bcc?: string;
24
+ }
25
+ export interface SendEmailResult {
26
+ /** Provider-assigned id for the delivered message, when the transport returns one. */
27
+ id?: string;
28
+ provider: 'resend' | 'smtp';
29
+ }
30
+ /**
31
+ * Delivers a message for real. Injected into applyPendingAction (file-tools.ts) rather than
32
+ * imported, so the staging/approval path has no transport dependency and stays unit-testable with
33
+ * a spy. Throws on a delivery failure — applyPendingAction lets that propagate to the caller.
34
+ */
35
+ export type SendEmail = (message: EmailMessage) => Promise<SendEmailResult>;
36
+ export declare class EmailDeliveryError extends Error {
37
+ readonly provider: 'resend' | 'smtp';
38
+ constructor(provider: 'resend' | 'smtp', detail: string);
39
+ }
40
+ /** Minimal RFC-5322-ish address check — a staged action with a malformed recipient is rejected before it is ever shown for approval. */
41
+ export declare function isLikelyEmailAddress(value: string): boolean;
42
+ export interface ResendSenderOptions {
43
+ apiKey: string;
44
+ /** The verified sender address Resend delivers as. Required — Resend rejects a send with no `from`. */
45
+ from: string;
46
+ /** Override for tests; defaults to the global fetch. */
47
+ fetchImpl?: typeof fetch;
48
+ }
49
+ /**
50
+ * Resend transport (https://resend.com) — a single authenticated POST, works in Node and the
51
+ * browser. `apiKey` and `from` come from config (ASSISTANT_EMAIL_* / config.json), never from the
52
+ * model.
53
+ */
54
+ export declare function createResendSender(options: ResendSenderOptions): SendEmail;
55
+ /**
56
+ * One-line human-readable summary of a staged email, for the approval prompt and trace. Kept here
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.
59
+ */
60
+ export declare function formatEmailApprovalReason(message: Pick<EmailMessage, 'to' | 'subject' | 'body'>): string;
@@ -0,0 +1,13 @@
1
+ import { AssistantConfig } from './config.js';
2
+ export interface ErrorClassification {
3
+ message: string;
4
+ retryable: boolean;
5
+ }
6
+ /**
7
+ * Maps a thrown turn error to user-facing copy and whether retrying is worth offering. Defaults
8
+ * to a generic, still-retryable message for anything unrecognized. `backend` (the caller's
9
+ * current `config.llmBackend`) disambiguates errors whose shape is identical across backends but
10
+ * whose actual cause/remedy differs — see the FlowExecutionError pattern's comment above; omit it
11
+ * only when no backend context exists (e.g. classifying a local file-write error).
12
+ */
13
+ export declare function classifyError(err: unknown, backend?: AssistantConfig['llmBackend']): ErrorClassification;
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Phase 4 of plans/harness_and_assistant_architecture_remediation_plan.html: a named,
3
+ * typed replacement for the three implicit bypass branches runTurn() used to make on its
4
+ * own, ad hoc, with no shared vocabulary between them:
5
+ * - classification.isTrivial → skip the harness run entirely (assistant.ts:1487-1495)
6
+ * - the plan-cancel bypass → skip classifyTurnIntent entirely (assistant.ts:1341-1370)
7
+ * - the batch-confirmation resume → skip the per-turn HarnessRuntime run entirely (assistant.ts:2467-2487)
8
+ * Each of those is a real, distinct guarantee-level a turn can run at — README's "every ordinary
9
+ * message walks the full 11-layer harness" claim is only true for two of the five modes below, and
10
+ * classifyExecutionMode() makes that precise instead of leaving it to be inferred from call-site
11
+ * reading order.
12
+ */
13
+ export type ExecutionMode = 'FAST' | 'TOOL' | 'PLAN' | 'CONSEQUENTIAL' | 'RESEARCH';
14
+ /**
15
+ * Per-mode guarantee documentation — what a caller can and can't rely on for a turn classified
16
+ * into each mode. Kept next to the type (not just in this file's header comment) so a reader
17
+ * inspecting one mode's behavior sees its contract without having to scroll up.
18
+ *
19
+ * - FAST: Trivial, self-contained factual turns (turn-intent-classifier.ts's isTrivial
20
+ * contract). No HarnessRuntime run at all this turn — no verification, no
21
+ * control-state, no reviewer pass, no checkpoint. Fastest path, weakest
22
+ * guarantees; safe only because isTrivial is deliberately conservative.
23
+ * - PLAN: A durable-plan bookkeeping turn (cancel/abandon a task) that never leaves this
24
+ * session's own plan-store state — no external effect, so no harness run and no
25
+ * tool loop either.
26
+ * - RESEARCH: The batch-research path (an explicit N-item list). Runs its own self-calibrating
27
+ * per-item tool-call budget (see budget.ts / BATCH_* constants) instead of the
28
+ * harness's task graph; a confirmed-large batch pauses for approval before
29
+ * spending it. No per-turn HarnessRuntime run backs this mode's own tool calls
30
+ * (though a resumed confirmation still skips it too, matching the direct path).
31
+ * - TOOL: An ordinary tool-using turn with no approval gate tripped. Walks the full
32
+ * HarnessRuntime run (world model, hypothesis, contradiction, control state,
33
+ * verification, recovery, reviewer pass) over the tool loop's already-produced
34
+ * reply — today's real guarantee level, still post-hoc bookkeeping rather than
35
+ * an in-loop control plane (see ToolPolicy for where deterministic, harness-
36
+ * state-informed gating is actually enforced).
37
+ * - CONSEQUENTIAL: turn-policy.ts's evaluateTurnPolicy() returned REQUIRE_APPROVAL, or the
38
+ * turn's tool calls include a write_file/run_shell_command (always staged,
39
+ * independent of risk classification — see ToolPolicy). Never executes without
40
+ * an explicit approve-by-ID round trip; the harness run (when one applies)
41
+ * still runs on top for bookkeeping, but TurnPolicy/ToolPolicy — not
42
+ * classification.riskLevel/requiresApproval directly — are the actual
43
+ * authoritative decision for whether this turn's action proceeds (Phase D3).
44
+ */
45
+ export declare const EXECUTION_MODE_GUARANTEES: Record<ExecutionMode, string>;
46
+ export interface ExecutionModeInput {
47
+ /** True when the plan-cancel bypass (matchTaskCancelAttempt) short-circuited before
48
+ * classifyTurnIntent ever ran this turn. */
49
+ isPlanCancelBypass: boolean;
50
+ /** True when this turn is resolving a batch-research confirmation pause
51
+ * (resolvePendingBatchConfirmation) or is about to enter the batch-research path
52
+ * (runBatchToolLoop) fresh. */
53
+ isBatchResearch: boolean;
54
+ /** turn-intent-classifier.ts's own isTrivial verdict — only meaningful once classification has
55
+ * actually run (never true when isPlanCancelBypass/isBatchResearch already short-circuited). */
56
+ isTrivial: boolean;
57
+ /** turn-policy.ts's evaluateTurnPolicy() decision (REQUIRE_APPROVAL), recomputed from
58
+ * turn-intent-classifier.ts's riskLevel/isBulkReminderRequest signals rather than read directly
59
+ * off its requiresApproval boolean — OR a write_file/run_shell_command tool call was proposed
60
+ * this turn (file-tools.ts's unconditional per-call staging gate). See ToolPolicy for the
61
+ * per-tool-call analog of this same deterministic-gate shape. */
62
+ requiresApproval: boolean;
63
+ }
64
+ /**
65
+ * Pure classification — no I/O, no LLM call. Order matters: earlier bypasses in runTurn's own
66
+ * control flow take precedence over classification fields that were never computed for that path
67
+ * (e.g. isTrivial is meaningless once isPlanCancelBypass already fired), mirroring the exact
68
+ * precedence runTurn's own if/else chain already encodes today.
69
+ */
70
+ export declare function classifyExecutionMode(input: ExecutionModeInput): ExecutionMode;
71
+ /**
72
+ * classifyExecutionMode() plus the trace-emission wrapper every call site used to repeat inline
73
+ * (PersonalAssistant.classifyAndTraceExecutionMode, before the Phase 4d module split) — always
74
+ * traces unconditionally (the ASSISTANT_CONTROL_PLANE flag this used to gate on was removed in
75
+ * Phase 4b). Shared by every module that needs to classify-and-trace this turn's ExecutionMode
76
+ * (action-approval-service.ts's resolvePendingBatchConfirmation, and assistant.ts's own
77
+ * sequencer — TurnInterpreter deliberately never touches onTrace at all, see its own doc
78
+ * comment) instead of each repeating `onTrace?.(...)` separately. Takes the narrowest event
79
+ * shape it actually emits (not the full TraceEvent union) so this file never needs to import
80
+ * trace-events.ts, which itself imports ExecutionMode from here.
81
+ */
82
+ export declare function classifyAndTraceExecutionMode(onTrace: ((event: {
83
+ kind: 'execution_mode_classified';
84
+ mode: ExecutionMode;
85
+ }) => void) | undefined, input: ExecutionModeInput): ExecutionMode;
@@ -0,0 +1,143 @@
1
+ import { FactConfidence, FactCategory } from './turn-intent-classifier.js';
2
+ /**
3
+ * Provenance of a captured fact — Phase 5 of the harness/personal-assistant remediation plan
4
+ * (plans/harness_and_assistant_architecture_remediation_plan.html), replacing the previous bare
5
+ * `durable: boolean` with a typed source plus a promotion policy keyed off it (see
6
+ * assistant.ts's recordFacts()). USER_ASSERTED is this file's own free lexical marker pass
7
+ * (extractFactsFromTurn) — unchanged in behavior and still auto-promotable, exactly as before
8
+ * this phase. MODEL_INFERRED is classifyTurnIntent's statesDurableFact free-form LLM read, only
9
+ * ever consulted when the lexical pass found nothing — no longer auto-promoted to durable status
10
+ * on its own (see recordFacts). OBSERVED and EXTERNALLY_VERIFIED have no producer in this
11
+ * codebase yet (e.g. a future tool-observed state claim, or Phase 6's AnswerClaim evidence
12
+ * trail) — defined now so a future producer has a typed slot to land in rather than overloading
13
+ * MODEL_INFERRED for something with a different trust profile.
14
+ *
15
+ * Storage-taxonomy note (Phase 5b, superseded by Phase E's typed `MemoryTier` below): `UserFact`
16
+ * is this codebase's Knowledge-shaped data ("what we believe") — `text`/`durable` is the belief
17
+ * itself; `FactSource` is its provenance ("why we believe it"). See
18
+ * packages/aielia/README.md's "Memory tiers" section for the full tier map this fits
19
+ * into, and memory-service.ts's DURABLE_FACTS_KEY doc comment for where promoted facts are stored.
20
+ */
21
+ export type FactSource = 'user_asserted' | 'model_inferred' | 'observed' | 'externally_verified';
22
+ export interface UserFact {
23
+ text: string;
24
+ extractedAt: string;
25
+ sourceTurn: string;
26
+ /**
27
+ * True for a fact currently promoted to the cross-session store that survives /new (name,
28
+ * stated preference, health/dietary — see DURABLE_MARKERS below), false for a session-scoped
29
+ * detail (current location, current job, "remember that"-style context, or an unconfirmed
30
+ * MODEL_INFERRED claim) that's expected to change more often or hasn't earned promotion yet.
31
+ * Derived from `source` via the promotion policy in recordFacts(), not set independently.
32
+ * assistant.ts's recordFacts() stores promoted facts in a second, never-cleared store in
33
+ * addition to the per-session one.
34
+ */
35
+ durable: boolean;
36
+ /** See FactSource. */
37
+ source: FactSource;
38
+ /**
39
+ * Confidence `classifyTurnIntent`'s `StatedFact.confidence` (turn-intent-classifier.ts) assigns
40
+ * a `model_inferred` fact — undefined for `user_asserted`/`observed`/`externally_verified`
41
+ * facts, which have no confidence gradient (they either matched a lexical pattern or didn't).
42
+ * Added in Phase 2 of plans/personal_assistant_fact_extraction_llm_confidence_plan.html for
43
+ * `recordFacts()`'s three-way promotion policy; Phase 4 additionally uses it to adjust
44
+ * `tierForFact()` and to annotate the per-turn facts prompt block. `migrateFact()` needs no
45
+ * change for this field — a pre-existing on-disk fact with no `confidence` reads back as
46
+ * `undefined`, which every reader here already treats as "no confidence signal, most
47
+ * conservative".
48
+ */
49
+ confidence?: FactConfidence;
50
+ /**
51
+ * `StatedFact.category` (turn-intent-classifier.ts) carried through onto the stored fact —
52
+ * undefined for `user_asserted`/`observed`/`externally_verified` facts, same "no signal from
53
+ * that source" convention `confidence` already follows. Added in Phase 3 of
54
+ * plans/personal_assistant_fact_extraction_llm_confidence_plan.html so a medium-confidence
55
+ * fact queued to `facts:pending-confirmation` (memory-service.ts) carries the topic its
56
+ * `/memory` grouping needs — see that file's `PendingFact`.
57
+ */
58
+ category?: FactCategory;
59
+ /**
60
+ * The project label this fact is scoped to — undefined means global (always shown, regardless
61
+ * of which project is active). Set by `MemoryService.recordFacts()`/`buildTurnFacts()` only for
62
+ * a fact classified `category: 'project'` (see FactCategory), using whatever
63
+ * `PersonalAssistant`'s `currentProject()` getter resolves to at capture time: an explicit
64
+ * `config.activeProject` override if the user set one via `/project <name>`, else the workspace
65
+ * root the assistant is running in. A fact in any other category is inherently about the user,
66
+ * not a codebase, so it stays global on purpose even while a project is active.
67
+ * `loadFacts()`/`getMemorySummary()` still return every fact regardless of `project` — only the
68
+ * turn's `factsBlock` (what the model actually sees) filters to global-or-current-project, so
69
+ * `/memory` stays a complete inventory the user can review/forget from regardless of which
70
+ * project is currently active.
71
+ */
72
+ project?: string;
73
+ }
74
+ /** 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
+ export declare function certaintyLabel(fact: UserFact): FactConfidence;
76
+ export declare function migrateFact(fact: UserFact): UserFact;
77
+ /**
78
+ * The six-tier taxonomy (Phase E of the harness consolidation plan, criticism001 #8 /
79
+ * criticism002 #6: "transcript ≠ memory"), made real as a type instead of the doc-comment-only
80
+ * split this file's `FactSource` note above already described. `UserFact` only ever populates
81
+ * four of these — `procedural` (the `ExperienceStore`) and `commitment` (`ReminderStore`) are
82
+ * separate stores with their own writers and never routed through `tierForFact`; keeping them in
83
+ * this union (rather than a narrower `UserFactTier`) is what lets `TIER_RULES.procedural`'s empty
84
+ * `allowedSources` structurally enforce INV-16 (no Experience entry is ever reachable as a
85
+ * `UserFact`, let alone a Knowledge one) instead of relying on every caller to remember to check.
86
+ */
87
+ export type MemoryTier = 'episodic' | 'semantic' | 'procedural' | 'preference' | 'commitment' | 'identity';
88
+ export interface TierRule {
89
+ /** FactSource values allowed to populate this tier — see TIER_RULES. */
90
+ allowedSources: FactSource[];
91
+ /** 'session': cleared with the rest of `facts:${sessionId}` on /new. 'durable': survives /new (DURABLE_FACTS_KEY today). */
92
+ retention: 'session' | 'durable';
93
+ /** Whether contradiction detection considers entries in this tier (see harness-bridge.ts's factExtractor). */
94
+ contradictionChecked: boolean;
95
+ }
96
+ /**
97
+ * Retention / contradiction / (implicitly, via `retention`) deletion rule per tier, plus the
98
+ * `FactSource` provenances allowed to populate it — the four properties Phase E's scope calls
99
+ * for. `procedural` and `commitment` have an empty `allowedSources`: no `UserFact` is ever tagged
100
+ * with either tier (see `tierForFact` below), so a `UserFact` can never populate the Experience or
101
+ * Commitment stores through this path — that's the structural half of INV-16, not just a runtime
102
+ * check.
103
+ */
104
+ export declare const TIER_RULES: Record<MemoryTier, TierRule>;
105
+ /**
106
+ * Routes a `UserFact` to its `MemoryTier` per Phase E / E3's rule, extended by Phase 4 of
107
+ * plans/personal_assistant_fact_extraction_llm_confidence_plan.html: `observed` (a future
108
+ * tool-observed claim) always stays `episodic` — an uncorroborated observation, never Knowledge.
109
+ * `model_inferred` (the LLM's `statesDurableFacts` guess) stays `episodic` too UNLESS it's both
110
+ * `durable` and `confidence === 'high'` — Phase 1's own definition of high confidence ("the user
111
+ * states it directly and unhedged about themselves in first person") is the same trust bar
112
+ * `user_asserted` facts clear by construction, so a high-confidence durable guess is routed
113
+ * exactly the same way from here on; medium/low confidence (or no confidence signal at all) stays
114
+ * a musing until/unless it's promoted via `/memory confirm` or corroboration reaches high — see
115
+ * `memory-service.ts`'s `promoteConfirmedFact()`, which re-sources a confirmed fact to
116
+ * `externally_verified` rather than relying on this function's `durable` check, since a fact
117
+ * queued via the low-confidence corroboration path isn't guaranteed to carry `durable: true`.
118
+ * `user_asserted`/`externally_verified`/qualifying `model_inferred` facts land in the durable
119
+ * `identity` or `preference` tier when the text itself reads as a name/preference statement and
120
+ * the fact earned promotion (`durable: true`); every other such fact (a stated job, location, or
121
+ * coding-fact-shaped claim — see `looksLikeCodingFact` — none of which are `durable` under
122
+ * `isDurable()` above) is `semantic`: still a stated claim about what's currently true, still
123
+ * eligible for contradiction detection (the "tests passed"/"tests failed" and nurse-vs-designer
124
+ * job-flip cases this file's admission logic exists to support), just not promoted to
125
+ * cross-session storage. Pure and total — every `UserFact` maps to exactly one tier, and
126
+ * `procedural`/`commitment` are never returned (see `TIER_RULES`'s doc comment).
127
+ */
128
+ export declare function tierForFact(fact: UserFact): MemoryTier;
129
+ /** Whether `tier` counts as the Knowledge tier for contradiction-detection purposes — see harness-bridge.ts's factExtractor and TIER_RULES.*.contradictionChecked. */
130
+ export declare function isKnowledgeTier(tier: MemoryTier): boolean;
131
+ /**
132
+ * Extracts at most one durable fact from a user message — verbatim, not summarized. Returns []
133
+ * when the message doesn't look like a fact statement.
134
+ *
135
+ * Also admits anything looksLikeCodingFact (contradiction-checker.ts) recognizes, unless the
136
+ * message also reads as a request or a question rather than a claim — a build/test/service-state
137
+ * claim like "the tests passed" is exactly what the World Model's belief/contradiction machinery
138
+ * (CODING_FACT_MARKERS, NEGATION_PAIRS) is built to track, but FACT_MARKERS' personal-fact
139
+ * phrasing never matched statements like that, so no belief was ever created for the
140
+ * contradiction checks to compare — a "tests passed" / "tests failed" flip produced zero beliefs
141
+ * and thus zero contradiction detection at any layer, lexical or LLM.
142
+ */
143
+ export declare function extractFactsFromTurn(userMessage: string, sourceTurn: string): UserFact[];
@@ -0,0 +1,32 @@
1
+ import { ILLMClient, TokenUsage } from '@buildaharness/runtime';
2
+ import { FailureModeEntry } from '@buildaharness/harness';
3
+ /**
4
+ * `AUDIT_SEMANTIC_FAILURE_MATCH` gate — feature-value audit (Phase A6 of
5
+ * plans/feature_audit_automation_plan.html). Default **ON**: the semantic failure-mode-matcher
6
+ * LLM call ships enabled, so an unset / empty / truthy value keeps today's behaviour. Set to a
7
+ * falsy value (`0` / `false` / `off` / `no` / `disabled`) to skip the LLM call entirely and fall
8
+ * back to `FailureModeLibrary.match()`'s exact-string-overlap check only. Read at exactly one call
9
+ * site — `harness-bridge.ts`, where the `semanticFailureMatcher` host hook is wired. Same shape as
10
+ * `semanticContradictionEnabled()` (contradiction-checker.ts) / `llmInjectionDetectEnabled()`
11
+ * (trust-tagging.ts) and the harness's `supervisorEnabled()`.
12
+ */
13
+ export declare function semanticFailureMatchEnabled(env?: Record<string, string | undefined>): boolean;
14
+ /**
15
+ * One LLM call checking a symptom set against the whole failure-mode library at once (never
16
+ * one call per entry) — layered on top of FailureModeLibrary.match()'s own exact-string-overlap
17
+ * check, which requires a symptom to be byte-for-byte identical to a curated one. That exact-match
18
+ * floor (and the shared-subject gates in detect-contradictions.ts / review-proposed-change.ts —
19
+ * see looksLikeCodingFact's doc comment in contradiction-checker.ts) is why decomposition-classifier.ts
20
+ * and plan-builder.ts prompt task descriptions to lead with their concrete subject: consistent
21
+ * subject vocabulary gives every lexical layer, not just this one, real overlap to match on. Since
22
+ * observations are free text ("Task executed: ...", "Result: ..."), exact equality against a
23
+ * curated list almost never happens by chance — this is what actually lets the library
24
+ * recognize a known failure pattern described in different words. Falls back to "no match" on
25
+ * any parse failure or LLM error, matching this codebase's other LLM-backed classifiers — a
26
+ * missed match costs nothing worse than the exact-match-only behavior this is layered on top of.
27
+ */
28
+ export declare function checkSemanticFailureMatch(symptoms: string[], libraryEntries: readonly FailureModeEntry[], llmClient: ILLMClient, model?: string, onUsage?: (usage: TokenUsage) => void): Promise<{
29
+ failure_class: string;
30
+ confidence: number;
31
+ matched_pattern: string;
32
+ } | null>;