@vib-rato/agent-core 0.16.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 (69) hide show
  1. package/CHANGELOG.md +852 -0
  2. package/README.md +493 -0
  3. package/dist/types/agent-loop.d.ts +229 -0
  4. package/dist/types/agent.d.ts +533 -0
  5. package/dist/types/append-only-context.d.ts +141 -0
  6. package/dist/types/attempt-scope.d.ts +84 -0
  7. package/dist/types/compaction/adaptive.d.ts +31 -0
  8. package/dist/types/compaction/branch-summarization.d.ts +103 -0
  9. package/dist/types/compaction/compaction.d.ts +330 -0
  10. package/dist/types/compaction/entries.d.ts +124 -0
  11. package/dist/types/compaction/errors.d.ts +26 -0
  12. package/dist/types/compaction/index.d.ts +12 -0
  13. package/dist/types/compaction/messages.d.ts +61 -0
  14. package/dist/types/compaction/openai.d.ts +65 -0
  15. package/dist/types/compaction/pruning.d.ts +130 -0
  16. package/dist/types/compaction/utils.d.ts +32 -0
  17. package/dist/types/compaction.d.ts +1 -0
  18. package/dist/types/harmony-leak.d.ts +100 -0
  19. package/dist/types/heap-eviction-retainers.test.d.ts +1 -0
  20. package/dist/types/image-placeholder-guard.d.ts +4 -0
  21. package/dist/types/index.d.ts +13 -0
  22. package/dist/types/proxy.d.ts +95 -0
  23. package/dist/types/run-collector.d.ts +223 -0
  24. package/dist/types/run-resource-ledger.d.ts +2 -0
  25. package/dist/types/telemetry.d.ts +605 -0
  26. package/dist/types/thinking.d.ts +18 -0
  27. package/dist/types/tool-dispatch-identity.d.ts +27 -0
  28. package/dist/types/types.d.ts +790 -0
  29. package/package.json +72 -0
  30. package/src/agent-loop.ts +5632 -0
  31. package/src/agent.ts +2437 -0
  32. package/src/append-only-context.ts +496 -0
  33. package/src/attempt-scope.ts +195 -0
  34. package/src/compaction/adaptive.ts +92 -0
  35. package/src/compaction/branch-summarization.ts +358 -0
  36. package/src/compaction/compaction.ts +1569 -0
  37. package/src/compaction/entries.ts +158 -0
  38. package/src/compaction/errors.ts +31 -0
  39. package/src/compaction/index.ts +13 -0
  40. package/src/compaction/messages.ts +212 -0
  41. package/src/compaction/openai.ts +580 -0
  42. package/src/compaction/prompts/auto-handoff-threshold-focus.md +1 -0
  43. package/src/compaction/prompts/branch-summary-context.md +5 -0
  44. package/src/compaction/prompts/branch-summary-preamble.md +2 -0
  45. package/src/compaction/prompts/branch-summary.md +30 -0
  46. package/src/compaction/prompts/compaction-short-summary.md +9 -0
  47. package/src/compaction/prompts/compaction-summary-context.md +5 -0
  48. package/src/compaction/prompts/compaction-summary.md +38 -0
  49. package/src/compaction/prompts/compaction-turn-prefix.md +17 -0
  50. package/src/compaction/prompts/compaction-update-summary.md +45 -0
  51. package/src/compaction/prompts/file-operations.md +10 -0
  52. package/src/compaction/prompts/handoff-document.md +56 -0
  53. package/src/compaction/prompts/summarization-system.md +3 -0
  54. package/src/compaction/pruning.ts +1026 -0
  55. package/src/compaction/utils.ts +189 -0
  56. package/src/compaction.ts +1 -0
  57. package/src/harmony-leak.ts +457 -0
  58. package/src/heap-eviction-retainers.test.ts +293 -0
  59. package/src/image-placeholder-guard.ts +20 -0
  60. package/src/index.ts +23 -0
  61. package/src/prompts/escaped-nonascii-recovery.md +3 -0
  62. package/src/prompts/repeated-tool-failure-recovery.md +1 -0
  63. package/src/proxy.ts +408 -0
  64. package/src/run-collector.ts +728 -0
  65. package/src/run-resource-ledger.ts +345 -0
  66. package/src/telemetry.ts +2161 -0
  67. package/src/thinking.ts +20 -0
  68. package/src/tool-dispatch-identity.ts +87 -0
  69. package/src/types.ts +882 -0
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Compaction error types.
3
+ *
4
+ * `CompactionCancelledError` is the canonical signal raised when a compaction
5
+ * is explicitly aborted — operator Esc, extension hook returning `cancel`,
6
+ * programmatic `session.abortCompaction()` call, or any other deliberate
7
+ * abort source. Downstream callers (e.g. `executeCompaction`) discriminate
8
+ * cancellation from other failures via `instanceof CompactionCancelledError`
9
+ * rather than introspecting error messages or `name` fields — the typed
10
+ * sentinel makes classification source-agnostic and refactor-stable.
11
+ */
12
+ export declare class CompactionCancelledError extends Error {
13
+ readonly name: "CompactionCancelledError";
14
+ constructor(message?: string);
15
+ }
16
+ /**
17
+ * Outcome of a compaction attempt, surfaced by `CommandController.executeCompaction`
18
+ * so callers (e.g. the plan-mode approval flow) can distinguish a deliberate abort
19
+ * from an unrelated failure.
20
+ *
21
+ * "ok" — compaction completed; transcript was summarized.
22
+ * "cancelled" — `CompactionCancelledError` was raised. Operator Esc, extension
23
+ * hook, programmatic abort — all source-agnostic.
24
+ * "failed" — any other rejection from `session.compact()`.
25
+ */
26
+ export type CompactionOutcome = "ok" | "cancelled" | "failed";
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Compaction and summarization utilities.
3
+ */
4
+ export * from "./adaptive";
5
+ export * from "./branch-summarization";
6
+ export * from "./compaction";
7
+ export * from "./entries";
8
+ export * from "./errors";
9
+ export * from "./messages";
10
+ export * from "./openai";
11
+ export * from "./pruning";
12
+ export * from "./utils";
@@ -0,0 +1,61 @@
1
+ import type { ImageContent, Message, MessageAttribution, ProviderPayload, TextContent } from "@vib-rato/ai";
2
+ import type { AgentMessage } from "../types";
3
+ export interface CustomMessage<T = unknown> {
4
+ role: "custom";
5
+ customType: string;
6
+ content: string | (TextContent | ImageContent)[];
7
+ display: boolean;
8
+ details?: T;
9
+ /** Who initiated this message for billing/attribution semantics. */
10
+ attribution?: MessageAttribution;
11
+ timestamp: number;
12
+ }
13
+ /** Legacy hook message type (pre-extensions). Kept for session migration. */
14
+ export interface HookMessage<T = unknown> {
15
+ role: "hookMessage";
16
+ customType: string;
17
+ content: string | (TextContent | ImageContent)[];
18
+ display: boolean;
19
+ details?: T;
20
+ /** Who initiated this message for billing/attribution semantics. */
21
+ attribution?: MessageAttribution;
22
+ timestamp: number;
23
+ }
24
+ export interface BranchSummaryMessage {
25
+ role: "branchSummary";
26
+ summary: string;
27
+ fromId: string;
28
+ timestamp: number;
29
+ }
30
+ export interface CompactionSummaryMessage {
31
+ role: "compactionSummary";
32
+ summary: string;
33
+ shortSummary?: string;
34
+ tokensBefore: number;
35
+ providerPayload?: ProviderPayload;
36
+ timestamp: number;
37
+ }
38
+ export type CoreCompactionMessage = CustomMessage | HookMessage | BranchSummaryMessage | CompactionSummaryMessage;
39
+ declare module "../types" {
40
+ interface CustomAgentMessages {
41
+ custom: CustomMessage;
42
+ hookMessage: HookMessage;
43
+ branchSummary: BranchSummaryMessage;
44
+ compactionSummary: CompactionSummaryMessage;
45
+ }
46
+ }
47
+ export type ConvertToLlm = (messages: AgentMessage[]) => Message[];
48
+ export declare function renderBranchSummaryContext(summary: string): string;
49
+ export declare function renderCompactionSummaryContext(summary: string): string;
50
+ export declare function createBranchSummaryMessage(summary: string, fromId: string, timestamp: string): BranchSummaryMessage;
51
+ export declare function createCompactionSummaryMessage(summary: string, tokensBefore: number, timestamp: string, shortSummary?: string, providerPayload?: ProviderPayload): CompactionSummaryMessage;
52
+ export declare function createCustomMessage(customType: string, content: string | (TextContent | ImageContent)[], display: boolean, details: unknown | undefined, timestamp: string, attribution?: MessageAttribution): CustomMessage;
53
+ /**
54
+ * Default compaction-domain transformer.
55
+ *
56
+ * Embedders with their own app messages should pass a richer transformer through
57
+ * `SummaryOptions.convertToLlm`; this default intentionally preserves only the
58
+ * core LLM roles and the compaction messages owned by this package.
59
+ */
60
+ export declare function defaultConvertToLlm(messages: AgentMessage[]): Message[];
61
+ export declare const convertToLlm: typeof defaultConvertToLlm;
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Remote compaction utilities.
3
+ *
4
+ * Provider-side conversation summarization endpoints. Two flavors:
5
+ *
6
+ * - **OpenAI remote compaction** (`/responses/compact`): preserves encrypted
7
+ * reasoning across compactions by submitting the full responses-API native
8
+ * history and storing the returned `compaction` / `compaction_summary`
9
+ * item in `preserveData` so future turns can replay the encrypted state.
10
+ * - **Generic remote compaction**: a thin POST helper for self-hosted
11
+ * summarization endpoints that accept `{ systemPrompt, prompt }` and reply
12
+ * with `{ summary, shortSummary? }`.
13
+ */
14
+ import type { Message, Model } from "@vib-rato/ai/types";
15
+ export declare const OPENAI_REMOTE_COMPACTION_PRESERVE_KEY = "openaiRemoteCompaction";
16
+ export type OpenAiRemoteCompactionItem = {
17
+ type: "compaction" | "compaction_summary";
18
+ encrypted_content?: string;
19
+ summary?: string;
20
+ };
21
+ export interface OpenAiRemoteCompactionPreserveData {
22
+ provider?: string;
23
+ replacementHistory: Array<Record<string, unknown>>;
24
+ compactionItem: OpenAiRemoteCompactionItem;
25
+ }
26
+ export interface OpenAiRemoteCompactionRequest {
27
+ model: string;
28
+ input: Array<Record<string, unknown>>;
29
+ instructions: string;
30
+ }
31
+ export interface OpenAiRemoteCompactionResponse extends OpenAiRemoteCompactionPreserveData {
32
+ }
33
+ export interface RemoteCompactionRequest {
34
+ systemPrompt: string;
35
+ prompt: string;
36
+ }
37
+ export interface RemoteCompactionResponse {
38
+ summary: string;
39
+ shortSummary?: string;
40
+ }
41
+ export declare function shouldUseOpenAiRemoteCompaction(model: Model): boolean;
42
+ /** Test seam: the compaction endpoint as resolved from trusted env. */
43
+ export declare function resolveOpenAiCompactEndpointForTest(model: Model, authCredentialType?: "api_key" | "oauth"): string;
44
+ export declare function getPreservedOpenAiRemoteCompactionData(preserveData: Record<string, unknown> | undefined): OpenAiRemoteCompactionPreserveData | undefined;
45
+ export declare function withOpenAiRemoteCompactionPreserveData(preserveData: Record<string, unknown> | undefined, remoteCompaction: OpenAiRemoteCompactionPreserveData | undefined): Record<string, unknown> | undefined;
46
+ export declare function estimateOpenAiCompactInputTokens(input: Array<Record<string, unknown>>, instructions: string): number;
47
+ export declare function trimOpenAiCompactInput(input: Array<Record<string, unknown>>, contextWindow: number, instructions: string): Array<Record<string, unknown>>;
48
+ export declare function resolveOpenAiCompactInputBudget(contextWindow: number, maxOutputTokens?: number): number;
49
+ /**
50
+ * Build the OpenAI Responses-API native history array from LLM messages.
51
+ *
52
+ * Caller is responsible for converting any custom message types to
53
+ * `Message[]` first (e.g. via the agent's `convertToLlm`); this function
54
+ * operates purely on the LLM-domain shape.
55
+ *
56
+ * @param messages - LLM messages to encode.
57
+ * @param model - Target model (used for provider gating + tool-call id rules).
58
+ * @param previousReplacementHistory - History from a prior compaction whose
59
+ * encrypted reasoning we want to preserve.
60
+ */
61
+ export declare function buildOpenAiNativeHistory(messages: Message[], model: Model, previousReplacementHistory?: Array<Record<string, unknown>>): Array<Record<string, unknown>>;
62
+ export declare function requestOpenAiRemoteCompaction(model: Model, apiKey: string, compactInput: Array<Record<string, unknown>>, instructions: string, signal?: AbortSignal, options?: {
63
+ authCredentialType?: "api_key" | "oauth";
64
+ }): Promise<OpenAiRemoteCompactionResponse>;
65
+ export declare function requestRemoteCompaction(endpoint: string, request: RemoteCompactionRequest, signal?: AbortSignal): Promise<RemoteCompactionResponse>;
@@ -0,0 +1,130 @@
1
+ /**
2
+ * Tool output pruning utilities for compaction.
3
+ *
4
+ * Candidate selection is staleness-aware: tool results that have been
5
+ * superseded by a later result for the same target (same file read again,
6
+ * same search re-run) or invalidated by a later successful edit/write to a
7
+ * covered file are pruned in preference to merely-old results. Protect-window
8
+ * and minimum-savings hysteresis semantics are unchanged.
9
+ */
10
+ import type { ToolCall, ToolResultMessage } from "@vib-rato/ai";
11
+ import type { SessionEntry, SessionMessageEntry } from "./entries";
12
+ export interface PruneConfig {
13
+ /** Keep the most recent tool output tokens intact. */
14
+ protectTokens: number;
15
+ /** Only prune if total savings meets this threshold. */
16
+ minimumSavings: number;
17
+ /** Tool names that should never be pruned. */
18
+ protectedTools: string[];
19
+ /** Number of newest user turns whose tool outputs must remain intact. Defaults to 2. */
20
+ protectRecentTurns?: number;
21
+ /**
22
+ * Tools in `protectedTools` whose protection is waived once the result is
23
+ * superseded (a later result for the same target, or a later successful
24
+ * edit/write to the covered file). The most recent result per target is
25
+ * never considered superseded. Optional; defaults to none.
26
+ */
27
+ staleOverridableTools?: string[];
28
+ }
29
+ export declare const DEFAULT_PRUNE_CONFIG: PruneConfig;
30
+ export interface ToolOutputPruneDigest {
31
+ entryId: string;
32
+ sha256: string;
33
+ bytes: number;
34
+ }
35
+ export interface ToolOutputPruneReplacement {
36
+ entryId: string;
37
+ replacementText: string;
38
+ /** Text-only results are the only entries safe to evict to an artifact. */
39
+ complete: boolean;
40
+ tokens: number;
41
+ }
42
+ export interface ToolOutputPrunePlan {
43
+ prunedCount: number;
44
+ tokensSaved: number;
45
+ /** Digest-only identity records; no original output text is retained. */
46
+ digests: readonly ToolOutputPruneDigest[];
47
+ /** Immutable replacement proposals keyed by entry id. */
48
+ replacements: readonly ToolOutputPruneReplacement[];
49
+ }
50
+ export interface ToolOutputPruneEvictionHandle {
51
+ v: 1;
52
+ artifactId: string;
53
+ uri: string;
54
+ encoding: "utf-8";
55
+ bytes: number;
56
+ sha256: string;
57
+ complete: true;
58
+ }
59
+ export interface ToolOutputPruneCommitReplacement {
60
+ replacementText?: string;
61
+ eviction?: ToolOutputPruneEvictionHandle;
62
+ }
63
+ export interface ToolOutputPruneCommitOptions {
64
+ replacements?: ReadonlyMap<string, ToolOutputPruneCommitReplacement>;
65
+ }
66
+ export type ToolOutputCommitOutcome = {
67
+ entryId: string;
68
+ outcome: "committed";
69
+ } | {
70
+ entryId: string;
71
+ outcome: "mismatch";
72
+ diagnostic: string;
73
+ } | {
74
+ entryId: string;
75
+ outcome: "unavailable";
76
+ diagnostic: string;
77
+ };
78
+ export declare function extractToolOutputText(message: ToolResultMessage): {
79
+ text: string;
80
+ complete: boolean;
81
+ };
82
+ export declare function createPrunedNotice(tokens: number, message?: ToolResultMessage, call?: ToolCall, artifact?: string): string;
83
+ export interface AssistantArgumentPruneResult {
84
+ argumentPrunedCount: number;
85
+ argumentTokensSaved: number;
86
+ /**
87
+ * The mutated assistant message entries. Callers whose entry source returns
88
+ * materialized copies must write these back into their canonical store by id.
89
+ */
90
+ prunedEntries: SessionMessageEntry[];
91
+ }
92
+ export declare function pruneAssistantToolArguments(entries: SessionEntry[], config?: PruneConfig): AssistantArgumentPruneResult;
93
+ /**
94
+ * Estimate conservative savings for a digest-only prune plan without mutating
95
+ * entries or invoking artifact publication.
96
+ */
97
+ export declare function estimateToolOutputPruneSavings(entries: SessionEntry[], config?: PruneConfig, options?: PruneToolOutputsOptions): {
98
+ prunableCount: number;
99
+ tokensSaved: number;
100
+ };
101
+ /**
102
+ * Evidence gate for below-threshold maintenance pruning (Finding 13). Pruning
103
+ * forces a prompt-cache-epoch reset, so it only runs when opted in AND the
104
+ * estimated stale savings clear a high minimum AND exceed the one-time reset
105
+ * cost (so the reclaim pays the reset back). Default-off/blocked until live
106
+ * evidence justifies enabling.
107
+ */
108
+ export declare function shouldRunMaintenancePrune(args: {
109
+ enabled: boolean;
110
+ estimatedSavings: number;
111
+ minSavings: number;
112
+ cacheEpochResetCost: number;
113
+ }): boolean;
114
+ export interface PruneToolOutputsOptions {
115
+ /** Lower the usual minimum only when the caller is already over its compaction threshold. */
116
+ relaxedMinimum?: number;
117
+ /** Conservative maximum ASCII length of every planned artifact reference. */
118
+ artifactRefMaxChars?: number;
119
+ }
120
+ /**
121
+ * Build a digest-only pruning plan. This function is deliberately read-only:
122
+ * candidates are inspected in private locals and the returned plan never keeps
123
+ * references to the source entries or their original output text.
124
+ */
125
+ export declare function planToolOutputPrune(entries: SessionEntry[], config?: PruneConfig, options?: PruneToolOutputsOptions): ToolOutputPrunePlan;
126
+ /**
127
+ * Re-check and commit a digest-only plan against the supplied live entries.
128
+ * Each entry is mutated only after its canonical full-text digest matches.
129
+ */
130
+ export declare function commitToolOutputPrune(entries: SessionEntry[], plan: ToolOutputPrunePlan, options?: ToolOutputPruneCommitOptions): ToolOutputCommitOutcome[];
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Shared utilities for compaction and branch summarization.
3
+ */
4
+ import type { Message } from "@vib-rato/ai";
5
+ import type { AgentMessage } from "../types";
6
+ export interface FileOperations {
7
+ read: Set<string>;
8
+ written: Set<string>;
9
+ edited: Set<string>;
10
+ }
11
+ export declare function createFileOps(): FileOperations;
12
+ /**
13
+ * Extract file operations from tool calls in an assistant message.
14
+ */
15
+ export declare function extractFileOpsFromMessage(message: AgentMessage, fileOps: FileOperations): void;
16
+ /**
17
+ * Compute final file lists from file operations.
18
+ * Returns readFiles (files only read, not modified) and modifiedFiles.
19
+ */
20
+ export declare function computeFileLists(fileOps: FileOperations): {
21
+ readFiles: string[];
22
+ modifiedFiles: string[];
23
+ };
24
+ export declare function formatFileOperations(readFiles: string[], modifiedFiles: string[]): string;
25
+ export declare function upsertFileOperations(summary: string, readFiles: string[], modifiedFiles: string[]): string;
26
+ /**
27
+ * Serialize LLM messages to text for summarization.
28
+ * This prevents the model from treating it as a conversation to continue.
29
+ * Call convertToLlm() first to handle custom message types.
30
+ */
31
+ export declare function serializeConversation(messages: Message[]): string;
32
+ export declare const SUMMARIZATION_SYSTEM_PROMPT: string;
@@ -0,0 +1 @@
1
+ export * from "./compaction/index";
@@ -0,0 +1,100 @@
1
+ /**
2
+ * GPT-5 Harmony-header leakage detection and recovery.
3
+ *
4
+ * Background and policy: see `docs/ERRATA-GPT5-HARMONY.md`. This module
5
+ * implements §3 of that document: detection by signal fusion, plus a
6
+ * truncate-and-resume primitive for the `edit` tool when its input is in
7
+ * hashline DSL form. Other tools and surfaces fall through to
8
+ * abort-and-retry handled by the agent loop.
9
+ */
10
+ import type { AssistantMessage, Model } from "@vib-rato/ai";
11
+ declare const SIGNAL_ORDER: readonly ["M", "C", "G", "S", "B", "R", "T"];
12
+ export type HarmonySignalClass = "H" | "I" | (typeof SIGNAL_ORDER)[number];
13
+ export type HarmonySurface = "assistant_text" | "assistant_thinking" | "tool_arg";
14
+ export interface HarmonySignal {
15
+ classes: HarmonySignalClass[];
16
+ start: number;
17
+ end: number;
18
+ text: string;
19
+ }
20
+ export interface HarmonyDetection {
21
+ surface: HarmonySurface;
22
+ contentIndex?: number;
23
+ toolName?: string;
24
+ toolCallId?: string;
25
+ signals: HarmonySignal[];
26
+ }
27
+ export interface HarmonyAuditEvent {
28
+ action: "truncate_resume" | "abort_retry" | "escalated";
29
+ surface: HarmonySurface;
30
+ signal: string;
31
+ retryN: number;
32
+ model: string;
33
+ provider: string;
34
+ toolName?: string;
35
+ removedLen: number;
36
+ removedSha8: string;
37
+ removedPreview: string;
38
+ removedBlob?: string;
39
+ }
40
+ export interface HarmonyRecoveredToolCall {
41
+ message: AssistantMessage;
42
+ removed: string;
43
+ }
44
+ /**
45
+ * Whether to run leak detection on responses from this model. We default-on
46
+ * for every OpenAI code provider model rather than enumerating ids, so a future
47
+ * gpt-5.6 (or whatever) doesn't silently bypass the mitigation. Detection
48
+ * itself is cheap; the cost of missing a leak on a new model is not.
49
+ */
50
+ export declare function isHarmonyLeakMitigationTarget(model: Model): boolean;
51
+ export declare function shouldMitigateHarmonyLeak(model: Model, detection: HarmonyDetection): boolean;
52
+ export declare function signalListLabel(signals: readonly HarmonySignal[]): string;
53
+ /**
54
+ * Detect harmony-protocol leakage in `text`. Returns undefined if clean.
55
+ *
56
+ * Trip rule: `H` alone, or `M` paired with at least one co-signal
57
+ * (`C`/`G`/`S`/`B`/`R`/`T`). Bare `M` does not trip — this document, its
58
+ * tests, and bug reports legitimately carry the marker.
59
+ *
60
+ * `parsedEnd`, when supplied, marks the byte at which a structurally valid
61
+ * tool-argument parse ends; markers strictly after it set the `T` co-signal.
62
+ * `contentIndex`/`toolName`/`toolCallId` flow through to the returned
63
+ * detection for downstream auditing.
64
+ */
65
+ export declare function detectHarmonyLeak(text: string, surface: HarmonySurface, options?: {
66
+ parsedEnd?: number;
67
+ contentIndex?: number;
68
+ toolName?: string;
69
+ toolCallId?: string;
70
+ }): HarmonyDetection | undefined;
71
+ /** Scan an assistant message's content blocks; return the first detection. */
72
+ export declare function detectHarmonyLeakInAssistantMessage(message: AssistantMessage): HarmonyDetection | undefined;
73
+ /**
74
+ * Truncate a contaminated tool call at the start of the contaminated line and
75
+ * append the tool's recovery sentinel. Returns a recovered AssistantMessage
76
+ * (containing only the cleaned tool call), a synthetic continuation user
77
+ * message asking the model to re-issue the rest, and the removed substring
78
+ * for auditing. Returns undefined when the tool is not recovery-eligible or
79
+ * the truncation would leave nothing meaningful to dispatch.
80
+ *
81
+ * `providerPayload` is dropped from the recovered message: for OpenAI code backend the
82
+ * encrypted reasoning blob is opaque/signed and we cannot validate that it is
83
+ * uncontaminated. The model re-reasons on the next turn.
84
+ */
85
+ export declare function recoverHarmonyToolCall(message: AssistantMessage, detection: HarmonyDetection): HarmonyRecoveredToolCall | undefined;
86
+ /**
87
+ * Return the contaminated substring from `message` for audit purposes when
88
+ * recovery is not applicable (abort path). Walks from the first detected
89
+ * signal to end-of-content within the relevant block. Returns "" if the
90
+ * detection cannot be resolved against the message.
91
+ */
92
+ export declare function extractHarmonyRemoved(message: AssistantMessage, detection: HarmonyDetection): string;
93
+ export declare function createHarmonyAuditEvent(params: {
94
+ action: HarmonyAuditEvent["action"];
95
+ detection: HarmonyDetection;
96
+ model: Model;
97
+ retryN: number;
98
+ removed: string;
99
+ }): HarmonyAuditEvent;
100
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,4 @@
1
+ import type { ImageContent, TextContent } from "@vib-rato/ai";
2
+ export declare const IMAGE_PLACEHOLDER_ATTACHMENT_GUIDANCE = "Image placeholder text was submitted without an image payload. Paste the image with #paste-image, attach it with @path/to/image.png, or save the image and provide the saved file path.";
3
+ export declare function isImagePlaceholderOnlyText(text: string): boolean;
4
+ export declare function assertImagePlaceholdersHavePayload(text: string, content: readonly (TextContent | ImageContent)[] | undefined): void;
@@ -0,0 +1,13 @@
1
+ export * from "./agent";
2
+ export * from "./agent-loop";
3
+ export * from "./append-only-context";
4
+ export * from "./compaction";
5
+ export * from "./harmony-leak";
6
+ export * from "./image-placeholder-guard";
7
+ export * from "./proxy";
8
+ export * from "./run-collector";
9
+ export * from "./run-resource-ledger";
10
+ export * from "./telemetry";
11
+ export * from "./thinking";
12
+ export * from "./tool-dispatch-identity";
13
+ export * from "./types";
@@ -0,0 +1,95 @@
1
+ /**
2
+ * Proxy stream function for apps that route LLM calls through a server.
3
+ * The server manages auth and proxies requests to LLM providers.
4
+ */
5
+ import { type AssistantMessage, type AssistantMessageEvent, type Context, EventStream, type Model, type SimpleStreamOptions, type StopReason } from "@vib-rato/ai";
6
+ declare class ProxyMessageEventStream extends EventStream<AssistantMessageEvent, AssistantMessage> {
7
+ constructor();
8
+ }
9
+ /**
10
+ * Proxy event types - server sends these with partial field stripped to reduce bandwidth.
11
+ */
12
+ export type ProxyAssistantMessageEvent = {
13
+ type: "start";
14
+ } | {
15
+ type: "text_start";
16
+ contentIndex: number;
17
+ } | {
18
+ type: "text_delta";
19
+ contentIndex: number;
20
+ delta: string;
21
+ } | {
22
+ type: "text_end";
23
+ contentIndex: number;
24
+ contentSignature?: string;
25
+ } | {
26
+ type: "thinking_start";
27
+ contentIndex: number;
28
+ } | {
29
+ type: "thinking_delta";
30
+ contentIndex: number;
31
+ delta: string;
32
+ } | {
33
+ type: "thinking_end";
34
+ contentIndex: number;
35
+ contentSignature?: string;
36
+ } | {
37
+ type: "reasoning_summary_start";
38
+ contentIndex: number;
39
+ } | {
40
+ type: "reasoning_summary_delta";
41
+ contentIndex: number;
42
+ delta: string;
43
+ } | {
44
+ type: "reasoning_summary_end";
45
+ contentIndex: number;
46
+ content?: string;
47
+ } | {
48
+ type: "toolcall_start";
49
+ contentIndex: number;
50
+ id: string;
51
+ toolName: string;
52
+ } | {
53
+ type: "toolcall_delta";
54
+ contentIndex: number;
55
+ delta: string;
56
+ } | {
57
+ type: "toolcall_end";
58
+ contentIndex: number;
59
+ } | {
60
+ type: "done";
61
+ reason: Extract<StopReason, "stop" | "length" | "toolUse">;
62
+ usage: AssistantMessage["usage"];
63
+ } | {
64
+ type: "error";
65
+ reason: Extract<StopReason, "aborted" | "error">;
66
+ errorMessage?: string;
67
+ usage: AssistantMessage["usage"];
68
+ };
69
+ export interface ProxyStreamOptions extends SimpleStreamOptions {
70
+ /** Auth token for the proxy server */
71
+ authToken: string;
72
+ /** Proxy server URL (e.g., "https://genai.example.com") */
73
+ proxyUrl: string;
74
+ }
75
+ /**
76
+ * Stream function that proxies through a server instead of calling LLM providers directly.
77
+ * The server strips the partial field from delta events to reduce bandwidth.
78
+ * We reconstruct the partial message client-side.
79
+ *
80
+ * Use this as the `streamFn` option when creating an Agent that needs to go through a proxy.
81
+ *
82
+ * @example
83
+ * ```typescript
84
+ * const agent = new Agent({
85
+ * streamFn: (model, context, options) =>
86
+ * streamProxy(model, context, {
87
+ * ...options,
88
+ * authToken: await getAuthToken(),
89
+ * proxyUrl: "https://genai.example.com",
90
+ * }),
91
+ * });
92
+ * ```
93
+ */
94
+ export declare function streamProxy(model: Model, context: Context, options: ProxyStreamOptions): ProxyMessageEventStream;
95
+ export {};