@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
|
@@ -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;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { ILLMClient, TokenUsage } from '@buildaharness/runtime';
|
|
2
|
+
/**
|
|
3
|
+
* A reply can say things the turn did not do (benchmark scenarios 13, 15 and 10): "Done, I added the type hints"
|
|
4
|
+
* with no write behind it, "let me fix all of it" followed by nothing, or facts about a changelog the assistant
|
|
5
|
+
* never read because the network was unavailable. The reply is already on screen when this runs (it is streamed),
|
|
6
|
+
* so the result is a separate notice, like `reviewNotice`.
|
|
7
|
+
*/
|
|
8
|
+
export interface ReplyAuditInput {
|
|
9
|
+
userMessage: string;
|
|
10
|
+
reply: string;
|
|
11
|
+
/** What the system recorded as carried out this turn (write/shell/email), see describeAppliedAction. */
|
|
12
|
+
actions: string[];
|
|
13
|
+
/** Parallel to `actions`: for a write, what it changed (a short diff), so a reply's account of the file can be checked against it. */
|
|
14
|
+
actionDetails?: string[];
|
|
15
|
+
/** What it recorded in earlier turns of this session (most recent last), so restating old results is not mistaken for new work. */
|
|
16
|
+
earlierActions?: string[];
|
|
17
|
+
/** Recent shell commands with the start and end of their output (most recent last). */
|
|
18
|
+
recentCommandOutputs?: {
|
|
19
|
+
command: string;
|
|
20
|
+
output: string;
|
|
21
|
+
}[];
|
|
22
|
+
/** Files and pages the turn read (tool and target). */
|
|
23
|
+
sourcesRead: string[];
|
|
24
|
+
/** Files, directories and pages read in EARLIER turns of this session (most recent last): an answer about them is not an outside fact, and a statement about which tools were used must be checked against them too. */
|
|
25
|
+
earlierSourcesRead?: string[];
|
|
26
|
+
/** A command this session already got the network-containment refusal for. */
|
|
27
|
+
lookupUnavailable: boolean;
|
|
28
|
+
}
|
|
29
|
+
export interface ReplyAudit {
|
|
30
|
+
claimsUnrecordedWork: boolean;
|
|
31
|
+
promisesWorkNotDone: boolean;
|
|
32
|
+
unverifiedOutsideFacts: boolean;
|
|
33
|
+
contradictsCommandOutput: boolean;
|
|
34
|
+
/** The reply denies or contradicts what the system recorded: says it did not touch, run or use something that a recorded write, command or read shows it did (benchmark scenarios 12 and 08). */
|
|
35
|
+
contradictsRecordedWork: boolean;
|
|
36
|
+
/** The reply thinks aloud: it starts a statement, then corrects or retracts it inside the answer, instead of one clean answer (benchmark scenarios 08 and 14). */
|
|
37
|
+
leaksSelfCorrection: boolean;
|
|
38
|
+
/** The reply does not respond to the user's message at all: placeholder text, a stray JSON object, an unrelated topic (benchmark scenario 13 turn 3: the whole reply was `{"favorite_marble":"... the response ..."}`). */
|
|
39
|
+
nonAnswer: boolean;
|
|
40
|
+
}
|
|
41
|
+
export declare const CLEAN_AUDIT: Readonly<ReplyAudit>;
|
|
42
|
+
/** Replies longer than this are never checked for being a non-answer: junk such as a stray JSON object or placeholder text is short, and the extra calls are not worth making for a long reply. */
|
|
43
|
+
export declare const NON_ANSWER_CHECK_MAX_CHARS = 300;
|
|
44
|
+
/**
|
|
45
|
+
* Two audit calls at once, and a third only when they disagree about a category: a category stands when at least two of the calls
|
|
46
|
+
* raise it. One sample of a classifier is noisy both ways: a false flag costs the user a pointless correction turn, a miss lets an
|
|
47
|
+
* invented claim stand (benchmark scenario 10 turn 2: the same reply was flagged by 6 of 8 production audits and passed by the
|
|
48
|
+
* rest). Asking the second call only after a flag made a miss on the first call final; asking both together also takes less time
|
|
49
|
+
* when the endpoint is slow. Fewer than two usable answers (an error or unparseable reply) returns a clean audit: a failed check
|
|
50
|
+
* must never flag a reply.
|
|
51
|
+
*/
|
|
52
|
+
export declare function auditReply(input: ReplyAuditInput, llmClient: ILLMClient, model?: string, onUsage?: (usage: TokenUsage) => void, options?: {
|
|
53
|
+
checkNonAnswer?: boolean;
|
|
54
|
+
}): Promise<ReplyAudit>;
|
|
55
|
+
/** The user-facing lines for what the audit found; undefined when it found nothing. */
|
|
56
|
+
export declare function replyAuditNotice(audit: ReplyAudit, actions: string[]): string | undefined;
|
|
57
|
+
/**
|
|
58
|
+
* `AIELIA_REPLY_AUDIT` gate. Default ON outside vitest (one extra bounded LLM call per successful turn); `0`/`false`/`off`/`no`/`disabled`
|
|
59
|
+
* turns it off. Same shape as `semanticGroundingEnabled()`.
|
|
60
|
+
*/
|
|
61
|
+
export declare function replyAuditEnabled(env?: Record<string, string | undefined>): boolean;
|
|
62
|
+
/**
|
|
63
|
+
* The message for the one automatic retry, or undefined when the reply needs none. A claim or promise of work the system
|
|
64
|
+
* did not record asks for the work to be done now or the claim withdrawn; details that disagree with the command output
|
|
65
|
+
* or outside facts stated as verified ask for a corrected answer.
|
|
66
|
+
*/
|
|
67
|
+
export declare function auditRetryNudge(audit: ReplyAudit, recorded: string[], userMessage?: string): string | undefined;
|
|
@@ -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,30 @@
|
|
|
1
|
+
import { ILLMClient } from '@buildaharness/runtime';
|
|
2
|
+
/**
|
|
3
|
+
* The small structured JSON calls a turn makes around its reply (risk classification, scope and goal-thread matching, the reply
|
|
4
|
+
* audit and its extra samples, next steps) are quick on a healthy endpoint, but a few simply never answer, and a turn waits on all of
|
|
5
|
+
* them: in the benchmark a finished-looking reply stayed busy for minutes and a queued message started late (scenarios 05, 06, 09, 10,
|
|
6
|
+
* 13, 15). Measured on the benchmark's model through OpenRouter with the real risk-classifier prompt (16 calls, 4 at a time): median
|
|
7
|
+
* 12 s, 75th percentile 27 s, 90th percentile 59 s, and one call that had not answered after 300 s. So a legitimate answer can take
|
|
8
|
+
* about a minute, and a fixed short bound kills those (a 45 s bound did: two turns of benchmark scenario 03 ended as "risk
|
|
9
|
+
* classification failed" and were never answered), while a long bound makes every hang cost minutes.
|
|
10
|
+
*
|
|
11
|
+
* So the call is hedged instead of cut off: when the first attempt has not answered after HEDGE_AFTER_MS a second identical attempt
|
|
12
|
+
* starts beside it, and whichever answers first is used. A slow answer is never discarded, a hung call costs about the hedge delay
|
|
13
|
+
* plus a normal response, and each attempt keeps its own hard bound. A failure waits for the other attempt if one is running; after that a
|
|
14
|
+
* transient one (a timeout, 408, 429, 5xx: benchmark scenarios 02, 08 and 10 each ended a classification on "The LLM proxy returned an error")
|
|
15
|
+
* gets one more attempt, while a refusal or a malformed answer would come back the same and is returned at once.
|
|
16
|
+
*/
|
|
17
|
+
export declare const SIDE_CALL_HEDGE_AFTER_MS = 25000;
|
|
18
|
+
export declare const SIDE_CALL_TIMEOUT_MS = 120000;
|
|
19
|
+
/** A failure worth one more attempt: a request that timed out, or an endpoint status that comes and goes (408, 429, any 5xx). A 4xx refusal or a bad answer is final. */
|
|
20
|
+
export declare function isTransientFailure(err: unknown): boolean;
|
|
21
|
+
export interface SideCallPolicyOptions {
|
|
22
|
+
/** Called once when a second attempt is started because the first has not answered yet. */
|
|
23
|
+
onHedge?: (info: {
|
|
24
|
+
afterMs: number;
|
|
25
|
+
}) => void;
|
|
26
|
+
/** Test hook: how long the first attempt gets before the second starts. */
|
|
27
|
+
hedgeAfterMs?: number;
|
|
28
|
+
}
|
|
29
|
+
/** Wraps a client so every structuredOutput call (never a main chat or tool-loop call) is hedged as described above. */
|
|
30
|
+
export declare function withSideCallPolicy(client: ILLMClient, policy?: SideCallPolicyOptions): ILLMClient;
|
|
@@ -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>;
|
package/dist/tool-step.d.ts
CHANGED
|
@@ -31,3 +31,9 @@ export declare function stripMcpToolPrefix(name: string): string;
|
|
|
31
31
|
* parsing) so "what step is this" reads identically no matter where it's rendered.
|
|
32
32
|
*/
|
|
33
33
|
export declare function summarizeToolStep(tool: string, input: Record<string, unknown>): string;
|
|
34
|
+
/**
|
|
35
|
+
* The same step once its turn has finished: a write or command that was only "proposed" while the model was working is
|
|
36
|
+
* reported as done ("Wrote …", "Ran: …"), so the transcript never says "Proposing" about something that already happened.
|
|
37
|
+
* Only call this for a step of a completed turn that was not denied (`deniedReason` unset); every other tool reads the same.
|
|
38
|
+
*/
|
|
39
|
+
export declare function summarizeSettledToolStep(tool: string, input: Record<string, unknown>): string;
|
package/dist/trace-events.d.ts
CHANGED
|
@@ -14,7 +14,7 @@ export type TraceEvent = {
|
|
|
14
14
|
} | {
|
|
15
15
|
kind: 'turn_end';
|
|
16
16
|
sessionId: string;
|
|
17
|
-
status: 'ok' | 'needs_approval' | 'escalated' | 'needs_clarification' | 'needs_plan_approval';
|
|
17
|
+
status: 'ok' | 'needs_approval' | 'escalated' | 'needs_clarification' | 'needs_plan_approval' | 'cancelled';
|
|
18
18
|
} | {
|
|
19
19
|
kind: 'risk_classified';
|
|
20
20
|
riskLevel: RiskLevel;
|
|
@@ -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>;
|
package/dist/trust-tagging.d.ts
CHANGED
|
@@ -7,6 +7,8 @@ import { ILLMClient, TokenUsage } from '@buildaharness/runtime';
|
|
|
7
7
|
* instruction that content in this tag is data, never instructions.
|
|
8
8
|
*/
|
|
9
9
|
export declare function wrapUntrusted(text: string): string;
|
|
10
|
+
/** A literal delimiter tag inside text is neutralised (`<`) so the text cannot close or re-open the untrusted boundary. String scan, not a regex: a structural delimiter check, not a natural-language gate. */
|
|
11
|
+
export declare function defangUntrustedTags(text: string): string;
|
|
10
12
|
export interface InjectionDetection {
|
|
11
13
|
flagged: boolean;
|
|
12
14
|
reason?: string;
|