@buildaharness/aielia 0.3.4 → 0.3.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +63 -20
- package/dist/PlanGraphPane.d.ts +19 -0
- package/dist/_memory-core-generated.d.ts +1764 -0
- package/dist/agent-loop.d.ts +23 -8
- package/dist/ambiguity-guard-flag.d.ts +12 -0
- package/dist/ambiguity-guard.d.ts +20 -0
- package/dist/answer-claim.d.ts +13 -1
- package/dist/ask-clarification-service.d.ts +12 -1
- package/dist/ask-response-format.d.ts +6 -0
- package/dist/assistant-session.d.ts +12 -1
- package/dist/assistant-source.d.ts +7 -0
- package/dist/assistant-types.d.ts +17 -1
- package/dist/assistant.d.ts +128 -6
- package/dist/benchmark-injected-failure.d.ts +6 -0
- package/dist/bin-CjKpxDxl.js +4836 -0
- package/dist/bin-CjKpxDxl.js.map +1 -0
- package/dist/cli-session.d.ts +14 -1
- package/dist/cli.d.ts +17 -2
- package/dist/cli.js +1 -1
- package/dist/code-plan-templates.d.ts +21 -0
- package/dist/config.d.ts +29 -0
- package/dist/constraint-check.d.ts +35 -0
- package/dist/contradiction-checker.d.ts +7 -0
- package/dist/decomposed-answer.d.ts +13 -0
- package/dist/decomposition-classifier.d.ts +2 -0
- package/dist/doctor-checks.d.ts +3 -0
- package/dist/episodic-digest.d.ts +89 -0
- package/dist/fact-extraction.d.ts +39 -0
- package/dist/file-tools-mcp-server.mjs +138 -12
- package/dist/file-tools.d.ts +4 -0
- package/dist/first-run.d.ts +0 -2
- 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 +20 -1
- package/dist/index.js +165 -94
- package/dist/index.js.map +1 -1
- package/dist/layer-policy-flag.d.ts +13 -0
- package/dist/layer-policy-wiring.d.ts +77 -0
- package/dist/layer-settings.d.ts +49 -0
- package/dist/layer-telemetry.d.ts +2 -0
- package/dist/lexical/lexical-mode.d.ts +29 -0
- package/dist/memory-consolidation.d.ts +80 -0
- package/dist/memory-governance.d.ts +30 -0
- package/dist/memory-reviewer.d.ts +114 -0
- package/dist/memory-service.d.ts +348 -9
- package/dist/model-json.d.ts +17 -0
- package/dist/next-step-context.d.ts +51 -0
- package/dist/next-step-proposer.d.ts +3 -2
- package/dist/plan-graph-flag.d.ts +20 -0
- package/dist/plan-question.d.ts +60 -0
- package/dist/plan-service.d.ts +6 -2
- package/dist/plan-step-prompt.d.ts +15 -0
- package/dist/plan-store.d.ts +7 -1
- package/dist/plan-viz/normalize.d.ts +14 -0
- package/dist/plan-viz/plan-detail-lines.d.ts +3 -0
- package/dist/plan-viz/plan-layout.d.ts +48 -0
- package/dist/plan-viz/plan-nav.d.ts +29 -0
- package/dist/plan-viz/plan-raster.d.ts +36 -0
- package/dist/plan-viz/plan-routes.d.ts +6 -0
- package/dist/plan-viz/plan-snapshot.d.ts +73 -0
- package/dist/plan-viz/plan-viewport.d.ts +29 -0
- package/dist/plan-viz/plan-width.d.ts +15 -0
- package/dist/plan-viz/testkit/display-width.d.ts +12 -0
- package/dist/plan-viz/testkit/generators.d.ts +61 -0
- package/dist/plan-viz/testkit/grid-oracles.d.ts +38 -0
- package/dist/plan-viz/testkit/nav-oracles.d.ts +79 -0
- package/dist/plan-viz/testkit/types.d.ts +8 -0
- package/dist/plan-viz/types.d.ts +34 -0
- package/dist/{provider-setup-CPbB5y_V.js → provider-setup-LFsaTkpf.js} +9308 -5510
- package/dist/provider-setup-LFsaTkpf.js.map +1 -0
- package/dist/recall-tool.d.ts +43 -0
- package/dist/recovery-note.d.ts +22 -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/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/transcript-compaction.d.ts +9 -0
- package/dist/{tui-app-DeyZ4Pr9.js → tui-app-BLR-PRFp.js} +321 -7
- package/dist/tui-app-BLR-PRFp.js.map +1 -0
- package/dist/tui-app.d.ts +38 -0
- package/dist/turn-intent-classifier.d.ts +75 -16
- package/dist/turn-interpreter.d.ts +25 -3
- package/dist/version.d.ts +1 -1
- package/package.json +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
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { ToolDefinition } from '@buildaharness/runtime';
|
|
2
|
+
import { DigestStore, SessionDigest } from './episodic-digest.js';
|
|
3
|
+
/**
|
|
4
|
+
* Phase M3 (agent_memory_framework_plan.html), recall half: a read-only `recall_memory` tool over
|
|
5
|
+
* the episodic digests. v1 is deliberately keyword-free (D2): with no argument it returns an INDEX
|
|
6
|
+
* of the most recent digests; with a digest id it returns that digest's text. The model decides
|
|
7
|
+
* which digest to open, so the semantic matching is the model's, not a scorer's.
|
|
8
|
+
*
|
|
9
|
+
* Flag: AUDIT_RECALL_TOOL, default OFF, read only in `recallToolEnabled()`.
|
|
10
|
+
*
|
|
11
|
+
* The digest writer and store live in episodic-digest.ts. `DigestReader` is the seam; production
|
|
12
|
+
* wraps the assistant's `DigestStore` (`storeDigestReader`). The id shown in the index is the
|
|
13
|
+
* digest id exactly as `listDigests` returns it (`<sessionId>:<conversationId>`, in `sessionId`).
|
|
14
|
+
*/
|
|
15
|
+
export interface DigestReader {
|
|
16
|
+
/** Most recent first, at most `limit`. */
|
|
17
|
+
list(limit: number): Promise<SessionDigest[]>;
|
|
18
|
+
get(id: string): Promise<SessionDigest | undefined>;
|
|
19
|
+
}
|
|
20
|
+
export declare const RECALL_INDEX_LIMIT = 20;
|
|
21
|
+
export declare function recallToolEnabled(env?: Record<string, string | undefined>): boolean;
|
|
22
|
+
export declare const RECALL_MEMORY_TOOL: ToolDefinition;
|
|
23
|
+
export declare const RECALL_TOOLS: ToolDefinition[];
|
|
24
|
+
/**
|
|
25
|
+
* Runs the tool. Never throws for a bad id or a reader failure — those come back as an
|
|
26
|
+
* `Error: ...` string (the loop's convention for a failed read), so the model sees them.
|
|
27
|
+
*/
|
|
28
|
+
export declare function executeRecallTool(reader: DigestReader, input: Record<string, unknown>): Promise<string>;
|
|
29
|
+
/** Production reader: a thin adapter over the assistant's DigestStore (`memory.digests`). Retention is applied by the store. */
|
|
30
|
+
export declare function storeDigestReader(store: Pick<DigestStore, 'listDigests' | 'getDigest'>): DigestReader;
|
|
31
|
+
/** In-memory fake for tests; takes A's SessionDigest shape. */
|
|
32
|
+
export declare class InMemoryDigestReader implements DigestReader {
|
|
33
|
+
private readonly digests;
|
|
34
|
+
constructor(digests?: SessionDigest[]);
|
|
35
|
+
list(limit: number): Promise<SessionDigest[]>;
|
|
36
|
+
get(id: string): Promise<SessionDigest | undefined>;
|
|
37
|
+
}
|
|
38
|
+
export declare const RECALL_POINTER_LINE = "\nEarlier sessions are summarised in memory. When the user asks what you worked on before, what was decided, or what the next step was, call the recall_memory tool (no arguments for an index, then an id to open a digest) and answer from it; the facts above are only part of what is recorded.";
|
|
39
|
+
/**
|
|
40
|
+
* M3: the one-line pointer that tells the model the digests exist. Returned only when AUDIT_RECALL_TOOL is on AND at least one
|
|
41
|
+
* digest exists, so a flag-off or digest-less run has a byte-identical prompt. No per-turn judgement: a pointer, not content.
|
|
42
|
+
*/
|
|
43
|
+
export declare function recallPointerBlock(reader: Pick<DigestReader, 'list'> | undefined): Promise<string>;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The failure-mode recovery bias (packages/harness's rollback-replan.ts's failureModeHint) only
|
|
3
|
+
* changes bookkeeping — the chosen strategy is never read by any execution node, so nothing about
|
|
4
|
+
* what the proposer actually tries next changes on its own. This is what turns a confident
|
|
5
|
+
* failure-mode switch into something the proposer reads and can act on: a steering note under its
|
|
6
|
+
* own header, drained the same way review-checker.ts's REVIEW_NOTE_PREFIX notes are (see
|
|
7
|
+
* agent-loop.ts's createHarnessProposer).
|
|
8
|
+
*/
|
|
9
|
+
export declare const RECOVERY_NOTE_PREFIX = "[recovery] ";
|
|
10
|
+
/**
|
|
11
|
+
* The proposer-facing steering note for a failure-mode-biased strategy switch — what the
|
|
12
|
+
* harness's own onFailureModeSwitch event turns into. Kept separate from reviewNoticeText's
|
|
13
|
+
* user-facing text (see AssistantTurnResult.reviewNotice): this note is for the model, not shown
|
|
14
|
+
* to the user directly.
|
|
15
|
+
*/
|
|
16
|
+
export declare function recoveryNoteText(failureClass: string, strategy: string): string;
|
|
17
|
+
/**
|
|
18
|
+
* The proposer-facing note for a switch the experience-learning feed picked (AUDIT_EXPERIENCE_LEARNING): the same hint as a
|
|
19
|
+
* failure-mode switch, but it says why this approach — it is the one that worked after this kind of failure in earlier runs.
|
|
20
|
+
* `failureClass` is empty for a failure no curated pattern matched.
|
|
21
|
+
*/
|
|
22
|
+
export declare function learnedRecoveryNoteText(failureClass: string, strategy: string): string;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { EscalationHalt, HarnessCheckpoint, VerificationResult, LayerActivityEvent, HarnessRunResult } from '@buildaharness/harness';
|
|
2
2
|
import { MemoryAdapter, TokenUsage } from '@buildaharness/runtime';
|
|
3
|
+
import { GroundingResult } from './grounding-check.js';
|
|
3
4
|
import { TurnIntentClassification } from './turn-intent-classifier.js';
|
|
4
5
|
import { PlanRecord } from './plan-store.js';
|
|
5
6
|
import { PlanService } from './plan-service.js';
|
|
@@ -24,7 +25,12 @@ export declare class ResponseService {
|
|
|
24
25
|
private readonly onTrace;
|
|
25
26
|
private readonly memory?;
|
|
26
27
|
private readonly nextStepProposer?;
|
|
27
|
-
|
|
28
|
+
private readonly groundingChecker?;
|
|
29
|
+
constructor(memoryService: MemoryService, session: AssistantSession, planService: PlanService, onTrace: ((event: TraceEvent) => void) | undefined, memory?: MemoryAdapter | undefined, nextStepProposer?: ((thread: GoalThread, onUsage: ((usage: TokenUsage) => void) | undefined, sessionId: string) => Promise<ThreadSuggestion[]>) | undefined, groundingChecker?: ((input: {
|
|
30
|
+
question: string;
|
|
31
|
+
reply: string;
|
|
32
|
+
sources: AssistantSource[] | undefined;
|
|
33
|
+
}, onUsage: ((usage: TokenUsage) => void) | undefined) => Promise<GroundingResult>) | undefined);
|
|
28
34
|
/**
|
|
29
35
|
* INV-42's concrete mechanism: mirrors the `activePlan`-based `saveAndSummarize` sync just
|
|
30
36
|
* above/below each call site, but onto `threadId`'s own `GoalThread.tasks` via
|
|
@@ -62,6 +68,8 @@ export declare class ResponseService {
|
|
|
62
68
|
usageTotal: TokenUsage | undefined;
|
|
63
69
|
onUsage?: (usage: TokenUsage) => void;
|
|
64
70
|
goalThreadId?: string;
|
|
71
|
+
/** Task id → why the completion check judged it not done, from this run; persisted on the plan. */
|
|
72
|
+
taskNotes?: Record<string, string>;
|
|
65
73
|
}): Promise<AssistantTurnResult>;
|
|
66
74
|
buildSuccessResult(params: {
|
|
67
75
|
sessionId: string;
|
|
@@ -78,6 +86,8 @@ export declare class ResponseService {
|
|
|
78
86
|
usageTotal: TokenUsage | undefined;
|
|
79
87
|
onUsage?: (usage: TokenUsage) => void;
|
|
80
88
|
goalThreadId?: string;
|
|
89
|
+
/** Task id → why the completion check judged it not done, from this run; persisted on the plan. */
|
|
90
|
+
taskNotes?: Record<string, string>;
|
|
81
91
|
}): Promise<AssistantTurnResult>;
|
|
82
92
|
buildEscalatedResult(params: {
|
|
83
93
|
sessionId: string;
|
package/dist/review-checker.d.ts
CHANGED
|
@@ -10,6 +10,10 @@ import { BeliefCandidate } from './contradiction-checker.js';
|
|
|
10
10
|
* (contradiction-checker.ts).
|
|
11
11
|
*/
|
|
12
12
|
export declare function semanticChangeReviewEnabled(env?: Record<string, string | undefined>): boolean;
|
|
13
|
+
/** Marks a steering note as coming from the change reviewer rather than from the user — agent-loop.ts gives it its own header so the proposer isn't told the user said it. */
|
|
14
|
+
export declare const REVIEW_NOTE_PREFIX = "[review] ";
|
|
15
|
+
/** The user-facing line for a conflict the reviewer found — see AssistantTurnResult.reviewNotice. */
|
|
16
|
+
export declare function reviewNoticeText(reasons: string[]): string;
|
|
13
17
|
/**
|
|
14
18
|
* One LLM call checking a proposed change against everything relevant at once (never one call
|
|
15
19
|
* per belief/prediction) — layered on top of review-proposed-change.ts's lexical `isNegation`
|
|
@@ -19,10 +23,12 @@ export declare function semanticChangeReviewEnabled(env?: Record<string, string
|
|
|
19
23
|
* which is why decomposition-classifier.ts and plan-builder.ts prompt task descriptions to lead
|
|
20
24
|
* with their subject. A
|
|
21
25
|
* paraphrased conflict ("we're dropping the login feature" vs. a belief that login is required)
|
|
22
|
-
* slips past that phrase list entirely.
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
+
* slips past that phrase list entirely. It runs for every change, coding-shaped or not: it used to
|
|
27
|
+
* skip a description that looked like a coding action on the theory that the lexical check
|
|
28
|
+
* covers that domain, but that gate was a keyword list ("build", "test"…) that also matched
|
|
29
|
+
* ordinary requests ("Build the offsite catering plan…"), and the lexical checks are being rolled
|
|
30
|
+
* back — the semantic check must not depend on them. The host only wires this when there is a
|
|
31
|
+
* trusted fact or prediction to check against, which is what bounds its cost. Falls back to "no conflict" on any parse
|
|
26
32
|
* failure or LLM error, matching this codebase's other LLM-backed classifiers — a missed conflict
|
|
27
33
|
* costs nothing worse than the lexical-only behavior this is layered on top of.
|
|
28
34
|
*/
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { ReviewerVerdict } from '@buildaharness/harness';
|
|
2
|
+
/** Marks a proposer-facing note that carries a reviewer finding to revise the answer against (see AgentLoop.createHarnessProposer). */
|
|
3
|
+
export declare const REVISION_NOTE_PREFIX = "[revision] ";
|
|
4
|
+
/**
|
|
5
|
+
* `AUDIT_REVIEWER_REVISION` gate. Default **OFF**: the reviewer pass's verdict only feeds the resolver's next call, exactly as
|
|
6
|
+
* before. A truthy value (`1` / `true` / `on` / `yes` / `enabled`) lets a finding at the END of a run send the last answer back
|
|
7
|
+
* to the proposer once, with the finding in front of it. It also stops the implementer lens reporting the generic default
|
|
8
|
+
* criterion as "not covered" — which it does on nearly every turn, since no belief can ever state a meta-instruction. It changes
|
|
9
|
+
* what the assistant says and costs a second answer when it fires, so it ships off until a benchmark shows it helps. Read at
|
|
10
|
+
* one site: harness-bridge.ts.
|
|
11
|
+
*/
|
|
12
|
+
export declare function reviewerRevisionEnabled(env?: Record<string, string | undefined>): boolean;
|
|
13
|
+
/** A success criterion a belief could state or paraphrase — everything except the generic "respond helpfully" default. */
|
|
14
|
+
export declare function isCheckableCriterion(criterion: string): boolean;
|
|
15
|
+
/**
|
|
16
|
+
* Which verdicts are worth a second answer. HIGH always (an unresolved contradiction, a contradicted high-reliability belief).
|
|
17
|
+
* MEDIUM only from the implementer lens — a real success criterion no belief covers at the end of the run. The reviewer and
|
|
18
|
+
* adversarial lens's MEDIUM findings ("most beliefs are low confidence", "high prior for a failure class") say something about the
|
|
19
|
+
* run's state, not about what the answer should say, so they are not acted on.
|
|
20
|
+
*/
|
|
21
|
+
export declare function reviewerRevisionNote(verdict: ReviewerVerdict): string | null;
|
|
22
|
+
/** The user turn the proposer sees for a revision note (the note text without its prefix). */
|
|
23
|
+
export declare function revisionContextMessage(noteBody: string): string;
|
|
@@ -4,4 +4,11 @@ export interface RiskClassification {
|
|
|
4
4
|
requiresApproval: boolean;
|
|
5
5
|
reason: string;
|
|
6
6
|
}
|
|
7
|
+
/**
|
|
8
|
+
* The lexical risk judgment, gated by lexicalMode's `risk` family (off by default). Off → no judgment
|
|
9
|
+
* is made and the answer is the conservative one an unknown risk gets: HIGH, requiring approval. Its
|
|
10
|
+
* only production caller is a durable plan step persisted without its own risk level.
|
|
11
|
+
*/
|
|
7
12
|
export declare function classifyRisk(message: string): RiskClassification;
|
|
13
|
+
/** The raw keyword judgment, never switched off — for test doubles standing in for the classifier model (scripted-llm-client.ts). */
|
|
14
|
+
export declare function classifyRiskLexical(message: string): RiskClassification;
|
|
@@ -11,10 +11,21 @@ import { ILLMClient, LLMStructuredResponse } from '@buildaharness/runtime';
|
|
|
11
11
|
* answers on its own from a lightweight, deterministic default — so `responses` only has to
|
|
12
12
|
* script the *tool loop / one-loop proposer's* own calls, not that bookkeeping call.
|
|
13
13
|
*
|
|
14
|
-
* `responses` entries are consumed in order, one per non-classifier
|
|
14
|
+
* `responses` entries are consumed in order, one per non-classifier, non-side-call
|
|
15
|
+
* `callChatStructured` call:
|
|
15
16
|
* - a plain `string` → `{ content: string }` (a final answer, no tool calls)
|
|
16
17
|
* - an `LLMStructuredResponse` → use as-is (set `toolCalls` to simulate the model calling a tool)
|
|
17
18
|
*
|
|
19
|
+
* A handful of other calls are auxiliary semantic escalations (the change reviewer, the failure
|
|
20
|
+
* matcher, the LLM injection classifier) that a tool-using turn can trigger without any script
|
|
21
|
+
* author asking for them — with lexicalMode's default now `disabled`, the lexical checks these
|
|
22
|
+
* sit on top of never short-circuit them, so they fire on every qualifying call, not just ones a
|
|
23
|
+
* scenario is specifically testing. Answered from a safe, inert default (see SIDE_CALL_MARKERS)
|
|
24
|
+
* so they never silently consume a `responses` slot meant for the real tool loop — the exact
|
|
25
|
+
* silent-consumption bug that broke chat-ui's W5 proxy e2e test when the default flipped. Override
|
|
26
|
+
* or add to this list via `sideResponses` for a test that specifically wants one of these calls to
|
|
27
|
+
* answer something else (e.g. a genuine injection flag).
|
|
28
|
+
*
|
|
18
29
|
* `callChat`/`callChatSync` (the no-tools reply path, and post-approval synthesis) stream
|
|
19
30
|
* `streamChunks` (default: `['']`).
|
|
20
31
|
*/
|
|
@@ -29,7 +40,21 @@ export interface ScriptedLLMClientScript {
|
|
|
29
40
|
* `undefined` to keep the derived default for that message.
|
|
30
41
|
*/
|
|
31
42
|
classify?: (userMessage: string) => Record<string, unknown> | undefined;
|
|
43
|
+
/**
|
|
44
|
+
* Overrides/extends SIDE_CALL_MARKERS' default answers for a system-prompt substring — checked
|
|
45
|
+
* before the built-in defaults, so a test can make the change reviewer/failure matcher/injection
|
|
46
|
+
* classifier answer something other than "nothing to see here" without it consuming a
|
|
47
|
+
* `responses` slot either way. `[marker, rawJsonContent]` pairs, same shape as the built-ins.
|
|
48
|
+
*/
|
|
49
|
+
sideResponses?: Array<[string, string]>;
|
|
32
50
|
}
|
|
51
|
+
/**
|
|
52
|
+
* Known auxiliary semantic-escalation system prompts and their safe, inert default answer — see
|
|
53
|
+
* ScriptedLLMClientScript's doc comment. Kept in sync by hand with each check's own system prompt
|
|
54
|
+
* (review-checker.ts, failure-mode-matcher.ts, trust-tagging.ts, grounding-check.ts, task-completion-check.ts, constraint-check.ts, semantic-compaction.ts, source-reliability.ts, semantic-hypotheses.ts, episodic-digest.ts, memory-consolidation.ts, memory-reviewer.ts) since there's no shared constant
|
|
55
|
+
* to import without a circular dependency back into this package's own public surface.
|
|
56
|
+
*/
|
|
57
|
+
export declare const SIDE_CALL_MARKERS: Array<[string, string]>;
|
|
33
58
|
/**
|
|
34
59
|
* Builds a scripted {@link ILLMClient}. See {@link ScriptedLLMClientScript}. The returned value
|
|
35
60
|
* is a plain `ILLMClient` — pass it straight to `PersonalAssistant.create({ llmClient })`.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { ChatMessage, ILLMClient, TokenUsage } from '@buildaharness/runtime';
|
|
2
|
+
/**
|
|
3
|
+
* `AUDIT_SEMANTIC_COMPACTION` gate. Default **OFF**: once a transcript is long, transcript-compaction.ts keeps the
|
|
4
|
+
* first 200 characters of each older message and nothing else, so a detail deep in an earlier message (a pasted
|
|
5
|
+
* document, a long answer) is gone from what the model sees — and the model has no tool to search the message index.
|
|
6
|
+
* On, ONE bounded call writes the summary instead (see summarizeOlderMessages); any failure falls back to the
|
|
7
|
+
* truncated form. Costs one call each time the thresholds trip. A truthy value (`1` / `true` / `on` / `yes` /
|
|
8
|
+
* `enabled`) enables it. Read at exactly one site: assistant.ts.
|
|
9
|
+
*/
|
|
10
|
+
export declare function semanticCompactionEnabled(env?: Record<string, string | undefined>): boolean;
|
|
11
|
+
/**
|
|
12
|
+
* One bounded LLM call: the older messages of a long conversation, condensed with their specifics kept. Returns null
|
|
13
|
+
* — the caller then uses the truncated form — on any error, an empty or unparseable answer, or input too large.
|
|
14
|
+
*/
|
|
15
|
+
export declare function summarizeOlderMessages(older: ChatMessage[], llmClient: ILLMClient, model?: string, onUsage?: (usage: TokenUsage) => void): Promise<string | null>;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { ILLMClient, TokenUsage } from '@buildaharness/runtime';
|
|
2
|
+
import { SemanticHypothesisProposal } from '@buildaharness/harness';
|
|
3
|
+
/** Marks a proposer-facing note that carries competing explanations (see AgentLoop.createHarnessProposer). */
|
|
4
|
+
export declare const HYPOTHESIS_NOTE_PREFIX = "[hypotheses] ";
|
|
5
|
+
/**
|
|
6
|
+
* `AUDIT_SEMANTIC_HYPOTHESES` gate. Default **OFF**: hypotheses stay the template seeds the harness generates and
|
|
7
|
+
* nothing is shown to the model. A truthy value (`1` / `true` / `on` / `yes` / `enabled`) lets the harness ask, once
|
|
8
|
+
* per turn, for competing explanations of a request the classifier judged underdetermined, judge them against the
|
|
9
|
+
* evidence each execution gathers, and put them in front of the proposer. It changes what the assistant says, so it
|
|
10
|
+
* ships off until a benchmark shows it helps. Read at one site: harness-bridge.ts.
|
|
11
|
+
*/
|
|
12
|
+
export declare function semanticHypothesesEnabled(env?: Record<string, string | undefined>): boolean;
|
|
13
|
+
/** One bounded LLM call: 2-4 competing explanations, or none. Fails open — any error or unusable answer is null. */
|
|
14
|
+
export declare function proposeCompetingExplanations(input: {
|
|
15
|
+
request: string;
|
|
16
|
+
observations: string[];
|
|
17
|
+
beliefs: string[];
|
|
18
|
+
}, llmClient: ILLMClient, model?: string, onUsage?: (usage: TokenUsage) => void): Promise<SemanticHypothesisProposal[] | null>;
|
|
19
|
+
/** One bounded LLM call: which of the explanations do these observations rule out? Fails open — null. */
|
|
20
|
+
export declare function judgeHypothesesAgainstEvidence(input: {
|
|
21
|
+
hypotheses: Array<{
|
|
22
|
+
id: string;
|
|
23
|
+
explanation: string;
|
|
24
|
+
predicted_observations: string[];
|
|
25
|
+
}>;
|
|
26
|
+
observations: string[];
|
|
27
|
+
}, llmClient: ILLMClient, model?: string, onUsage?: (usage: TokenUsage) => void): Promise<{
|
|
28
|
+
contradicted: Array<{
|
|
29
|
+
id: string;
|
|
30
|
+
reason?: string;
|
|
31
|
+
}>;
|
|
32
|
+
} | null>;
|
|
33
|
+
/** The proposer-facing note: the competing explanations and what would tell them apart. */
|
|
34
|
+
export declare function renderHypothesisNote(hypotheses: Array<{
|
|
35
|
+
explanation: string;
|
|
36
|
+
predicted_observations: string[];
|
|
37
|
+
separating_check?: string;
|
|
38
|
+
}>): string;
|
|
39
|
+
/** The user turn the proposer sees for a hypothesis note (the note text without its prefix). */
|
|
40
|
+
export declare function hypothesisContextMessage(noteBody: string): string;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { ILLMClient, TokenUsage } from '@buildaharness/runtime';
|
|
2
|
+
import { AssistantSource } from './assistant-source.js';
|
|
3
|
+
export type SourceReliability = 'HIGH' | 'MEDIUM' | 'LOW';
|
|
4
|
+
export interface SourceAssessment {
|
|
5
|
+
path: string;
|
|
6
|
+
reliability: SourceReliability;
|
|
7
|
+
reason: string;
|
|
8
|
+
}
|
|
9
|
+
export interface SourceWeighing {
|
|
10
|
+
assessments: SourceAssessment[];
|
|
11
|
+
/**
|
|
12
|
+
* `false` only when the sources materially disagree or differ in reliability AND the reply leans on a
|
|
13
|
+
* lower-reliability one, or presents them as equal without saying so. Everything else is `true`.
|
|
14
|
+
*/
|
|
15
|
+
weighed: boolean;
|
|
16
|
+
/** One or two sentences telling the assistant how to weigh the sources — used only when `weighed` is false. */
|
|
17
|
+
note?: string;
|
|
18
|
+
}
|
|
19
|
+
/** Prefix of the evidence ids this module writes, so a reader can tell an assessment from a tool observation. */
|
|
20
|
+
export declare const SOURCE_RELIABILITY_EVIDENCE_PREFIX = "source-reliability:";
|
|
21
|
+
/**
|
|
22
|
+
* `AUDIT_SEMANTIC_SOURCE_RELIABILITY` gate. Default **OFF**: a turn's sources are never assessed and the
|
|
23
|
+
* reply is never revised, exactly as before. A truthy value (`1` / `true` / `on` / `yes` / `enabled`)
|
|
24
|
+
* turns on one bounded LLM call per multi-source turn, and one revision of an answer the call judged not to
|
|
25
|
+
* have weighed its sources. It changes what the assistant says, so it ships off until a benchmark shows it
|
|
26
|
+
* helps. Read at one site: `AgentLoop.createHarnessProposer`.
|
|
27
|
+
*/
|
|
28
|
+
export declare function sourceReliabilityEnabled(env?: Record<string, string | undefined>): boolean;
|
|
29
|
+
/** The distinct read sources a turn used (a directory listing is not a source of facts). Deduplicated by tool + path. */
|
|
30
|
+
export declare function distinctSources(sources: AssistantSource[]): AssistantSource[];
|
|
31
|
+
/**
|
|
32
|
+
* One bounded LLM call over a turn that read two or more distinct sources. Fails open: fewer than two
|
|
33
|
+
* sources, no reply, an error or an unparseable response all return null, so a broken check can never
|
|
34
|
+
* change a reply that would have gone out today.
|
|
35
|
+
*/
|
|
36
|
+
export declare function assessSourceReliability(input: {
|
|
37
|
+
question: string;
|
|
38
|
+
sources: AssistantSource[];
|
|
39
|
+
reply: string;
|
|
40
|
+
}, llmClient: ILLMClient, model?: string, onUsage?: (usage: TokenUsage) => void): Promise<SourceWeighing | null>;
|
|
41
|
+
/** The minimal evidence-store surface this module writes to — both the harness's and the turn-local store satisfy it. */
|
|
42
|
+
export interface EvidenceSink {
|
|
43
|
+
addObservation(evidence: {
|
|
44
|
+
id: string;
|
|
45
|
+
obs: string;
|
|
46
|
+
reliability: SourceReliability;
|
|
47
|
+
source: string;
|
|
48
|
+
evidence_type: 'OBSERVATION';
|
|
49
|
+
freshness: string;
|
|
50
|
+
}): void;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Records each assessment as an observation carrying the assessed reliability. Written straight to the
|
|
54
|
+
* store's `observations` — deliberately NOT through updateWorldModel: a LOW belief weighs 0 in
|
|
55
|
+
* `belief_health.support`, which could push a run into the resolver's Tier 2 DENY for a source the
|
|
56
|
+
* assistant merely judged less reliable.
|
|
57
|
+
*/
|
|
58
|
+
export declare function recordSourceAssessments(store: EvidenceSink, assessments: SourceAssessment[], now?: string): void;
|
|
59
|
+
/** The user turn that asks the assistant to answer again with the sources weighed. */
|
|
60
|
+
export declare function renderSourceNote(weighing: SourceWeighing): string;
|
|
61
|
+
/**
|
|
62
|
+
* The "Why?" lines for the sources a turn judged less reliable — one per LOW assessment recorded in the
|
|
63
|
+
* claim's evidence. Empty when the check did not run or nothing was judged LOW, so a quiet turn stays quiet.
|
|
64
|
+
*/
|
|
65
|
+
export declare function lowerConfidenceSourceLines(claim: {
|
|
66
|
+
evidence: Array<{
|
|
67
|
+
id: string;
|
|
68
|
+
obs: string;
|
|
69
|
+
reliability: SourceReliability;
|
|
70
|
+
}>;
|
|
71
|
+
}): string[];
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { ILLMClient, TokenUsage } from '@buildaharness/runtime';
|
|
2
|
+
export interface TaskCompletionResult {
|
|
3
|
+
/** `false` only when the check positively judged the output did not accomplish the task. */
|
|
4
|
+
done: boolean;
|
|
5
|
+
reason?: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* `AUDIT_SEMANTIC_TASK_COMPLETION` gate. Default **OFF**: the harness marks a plan task COMPLETE as
|
|
9
|
+
* soon as the reply is produced, exactly as before. A truthy value (`1` / `true` / `on` / `yes` /
|
|
10
|
+
* `enabled`) turns on the per-task check for a durable plan's execution. Unlike the other semantic
|
|
11
|
+
* hooks this one changes plan behaviour (a task judged not done fails instead of completing), so it
|
|
12
|
+
* ships off until a benchmark shows it helps. Read at exactly one site: harness-bridge.ts.
|
|
13
|
+
*/
|
|
14
|
+
export declare function semanticTaskCompletionEnabled(env?: Record<string, string | undefined>): boolean;
|
|
15
|
+
export declare function shortenForCheck(text: string): string;
|
|
16
|
+
/**
|
|
17
|
+
* One bounded LLM call: did this output accomplish the task? Fails open — any error, empty output or
|
|
18
|
+
* unparseable response is `done: true`, so a broken check can never strand a plan that would have
|
|
19
|
+
* completed today; only a positive "not done" changes anything.
|
|
20
|
+
*/
|
|
21
|
+
export declare function checkTaskCompletion(input: {
|
|
22
|
+
taskDescription: string;
|
|
23
|
+
output: unknown;
|
|
24
|
+
}, llmClient: ILLMClient, model?: string, onUsage?: (usage: TokenUsage) => void): Promise<TaskCompletionResult>;
|
|
@@ -37,17 +37,49 @@ export interface TurnControlPlaneState {
|
|
|
37
37
|
readonly diagnostics: Diagnostics;
|
|
38
38
|
readonly failureDiagnostics: FailureDiagnostics;
|
|
39
39
|
controlState: ControlState;
|
|
40
|
+
/** How many times each identical call has already come back negative or failed this turn (see `ToolOutcome.callKey`). */
|
|
41
|
+
readonly unproductiveCalls: Map<string, number>;
|
|
42
|
+
/**
|
|
43
|
+
* EVAL-ONLY ablation (see `controlStateToolPolicyEnabled`): when true this state stays at its
|
|
44
|
+
* default ALLOW/NORMAL — `recordToolOutcome` still records evidence but never re-resolves, and
|
|
45
|
+
* agent-loop does not fold the harness's per-iteration state in — so tool policy never sees a DENY.
|
|
46
|
+
*/
|
|
47
|
+
readonly pinNormal?: boolean;
|
|
40
48
|
}
|
|
49
|
+
/**
|
|
50
|
+
* `AUDIT_CONTROL_STATE_TOOL_POLICY` gate — feature-value audit, EVAL-ONLY: default **ON** (unset /
|
|
51
|
+
* empty / truthy keeps today's behaviour). Only the benchmark's `controlStateToolPolicyOff` and
|
|
52
|
+
* `controlStateOff` arms set a falsy value (`0` / `false` / `off` / `no` / `disabled`), which pins the
|
|
53
|
+
* ControlState that `evaluateToolPolicy` reads at ALLOW/NORMAL. Read at exactly one call site
|
|
54
|
+
* (`createControlPlaneState`); the harness's own gate is a separate switch (`AUDIT_CONTROL_STATE_GATE`).
|
|
55
|
+
*/
|
|
56
|
+
export declare function controlStateToolPolicyEnabled(env?: Record<string, string | undefined>): boolean;
|
|
57
|
+
/**
|
|
58
|
+
* `AUDIT_CONTROL_STATE_GATE` gate — feature-value audit, EVAL-ONLY: default **ON**. Only the
|
|
59
|
+
* `controlStateOff` arm sets a falsy value, which makes `HarnessBridge.run` pass
|
|
60
|
+
* `skipControlState: true` to HarnessRuntime so `resolveAndStamp` leaves the harness's own state at
|
|
61
|
+
* ALLOW/NORMAL (no gate BLOCK/ESCALATE, no reviewer-verdict CAUTIOUS). Read at one call site.
|
|
62
|
+
*/
|
|
63
|
+
export declare function controlStateGateEnabled(env?: Record<string, string | undefined>): boolean;
|
|
41
64
|
/**
|
|
42
65
|
* A fresh EvidenceStore defaults to an EMPTY tool_availability_manifest, which makes
|
|
43
66
|
* gatherEvidence() silently no-op for every tool. Seed it with every tool name this turn's
|
|
44
67
|
* config actually enables, so tool outcomes are never silently dropped.
|
|
45
68
|
*/
|
|
46
69
|
export declare function toolAvailabilityManifest(toolNames: string[]): Record<string, ToolAvailability>;
|
|
47
|
-
export declare function createTurnControlPlaneState(toolNames: string[]
|
|
70
|
+
export declare function createTurnControlPlaneState(toolNames: string[], opts?: {
|
|
71
|
+
pinNormal?: boolean;
|
|
72
|
+
}): TurnControlPlaneState;
|
|
48
73
|
export interface ToolOutcome {
|
|
49
74
|
toolName: string;
|
|
50
75
|
ok: boolean;
|
|
76
|
+
/**
|
|
77
|
+
* The call worked and the answer was "not there" (a missing file). Not a fault, so it does not count as a failure —
|
|
78
|
+
* unless the identical call has already come back negative twice (`callKey`), which is a retry of a known answer.
|
|
79
|
+
*/
|
|
80
|
+
negative?: boolean;
|
|
81
|
+
/** Identifies the call (tool + arguments) so repeats of an already-negative or failed call can be recognised. */
|
|
82
|
+
callKey?: string;
|
|
51
83
|
/** Short, human-readable — never the full resultText (can be large/untrusted). */
|
|
52
84
|
summary: string;
|
|
53
85
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ToolEffectClass } from '@buildaharness/harness';
|
|
2
|
+
/**
|
|
3
|
+
* AL5a: each tool's effect class — a non-linguistic source for which tools a turn may use to
|
|
4
|
+
* change the world. Feeds `deriveConsequentialTools` (write / execute are consequential; `network`
|
|
5
|
+
* here is outbound read-only egress and is not). Keep in step with the tool definitions in
|
|
6
|
+
* file-tools.ts, web-tools.ts, shell-tools.ts, reminder-tools.ts and action-tools.ts; a tool
|
|
7
|
+
* missing here is treated as consequential by `deriveConsequentialTools`.
|
|
8
|
+
*/
|
|
9
|
+
export declare const TOOL_EFFECT_CLASS: Record<string, ToolEffectClass>;
|
|
@@ -10,4 +10,13 @@ export interface CompactionResult {
|
|
|
10
10
|
* summary — keeps compaction free instead of costing an extra call every time
|
|
11
11
|
* a long session crosses the threshold.
|
|
12
12
|
*/
|
|
13
|
+
export declare const SUMMARY_HEADER = "[Earlier conversation summary]";
|
|
14
|
+
/** The messages compaction would drop for `transcript` right now (the older part), or null when it would not compact. M3's pre-compaction flush reads exactly these. Same threshold, no new trigger. */
|
|
15
|
+
export declare function messagesAboutToBeCompacted(transcript: ChatMessage[]): ChatMessage[] | null;
|
|
13
16
|
export declare function compactTranscript(transcript: ChatMessage[]): CompactionResult;
|
|
17
|
+
/**
|
|
18
|
+
* Same thresholds and same messages kept as `compactTranscript`, but the older part is summarized by `summarize`
|
|
19
|
+
* (semantic-compaction.ts) instead of truncated to 200 characters each. A `summarize` that returns null or throws
|
|
20
|
+
* falls back to the truncated form, so this can never lose more than `compactTranscript` would have.
|
|
21
|
+
*/
|
|
22
|
+
export declare function compactTranscriptSemantic(transcript: ChatMessage[], summarize: (older: ChatMessage[]) => Promise<string | null>): Promise<CompactionResult>;
|