billion-context-omp 0.3.1 → 0.3.2-pr.138.3

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.
@@ -8,36 +8,11 @@ export declare function streamToCoreMessages(stream: AgentMessage[]): CoreMessag
8
8
  * skip replaying compress calls that were REJECTED live ("No changes
9
9
  * applied") — only calls that actually created blocks should rebuild them. */
10
10
  export declare function toolResultTexts(stream: AgentMessage[]): Map<string, string>;
11
- export interface StreamCompressCall {
12
- id: string;
13
- ranges: {
14
- startRef: string;
15
- endRef: string;
16
- summary: string;
17
- topic?: string;
18
- summaryMaxChars?: number;
19
- compressCallId: string;
20
- }[];
21
- }
11
+ export type { StreamCompressCall } from "acp-kernel/wire";
12
+ import type { StreamCompressCall } from "acp-kernel/wire";
22
13
  export declare function findCompressCalls(message: AgentMessage): StreamCompressCall[];
23
- /** Extract a compress tool's arguments from a stream toolCall. Two call
24
- * shapes exist: (1) top-level — our tools are registered with
25
- * loadMode:"essential" so omp's tools.xdev does NOT mount them as xd://
26
- * devices; the stream shows name:"compress" directly. (2) legacy xd:// —
27
- * sessions recorded before that change (or hosts with tools.xdev forcing
28
- * discoverable mounting) invoked compress through the write tool with path
29
- * "xd://compress" and the tool args JSON-encoded in the content field. Both
30
- * shapes must replay from the stream. Returns normalized compress args
31
- * (content array
32
- * plus optional topic / summaryMaxChars from wherever they live). */
33
- export declare function compressToolArgs(call: {
34
- name: string;
35
- arguments?: unknown;
36
- }): {
37
- content: unknown[];
38
- topic?: unknown;
39
- summaryMaxChars?: unknown;
40
- } | null;
14
+ import { compressToolArgs } from "acp-kernel/wire";
15
+ export { compressToolArgs };
41
16
  export declare function extractText(content: unknown, stripTags?: boolean): string;
42
17
  export declare function stripRefTag(text: string): string;
43
18
  export declare function messageIdentity(message: unknown): string;
package/dist/runtime.d.ts CHANGED
@@ -2,13 +2,6 @@ import type { ExtensionContext } from "@oh-my-pi/pi-coding-agent";
2
2
  import { type CompressionCore, type CompressionState, type Config, type CoreMessage, type Prompts } from "acp-kernel";
3
3
  import { type AdapterConfig } from "./config.js";
4
4
  import type { BiliMessage } from "acp-kernel/wire";
5
- import { type AgentMessage } from "./messages.js";
6
- export interface FoldResult {
7
- state: CompressionState;
8
- coreMessages: CoreMessage[];
9
- originalById: Map<string, AgentMessage>;
10
- streamLen: number;
11
- }
12
5
  /** Core-space fold result (provider mode): no originalById — the output
13
6
  * rebuilds straight onto the wire via the kernel codecs. */
14
7
  export interface CoreFoldResult {
@@ -24,22 +17,17 @@ export interface AcpRuntime {
24
17
  setPrompts(prompts: Prompts): void;
25
18
  liveContextLimit(ctx: ExtensionContext): number;
26
19
  configFor(ctx: ExtensionContext): Config;
27
- foldStream(ctx: ExtensionContext, stream: AgentMessage[]): FoldResult;
28
20
  /** Core-space fold (provider mode): the wire payload already parsed to
29
- * BiliMessage[] by the kernel codec; same incremental LCP + replay
30
- * semantics as foldStream, content-hash id space (wire-fold.ts). */
21
+ * BiliMessage[] by the kernel codec; incremental LCP + replay semantics,
22
+ * content-hash id space (wire-fold.ts). */
31
23
  foldStreamCore(ctx: ExtensionContext, stream: BiliMessage[]): CoreFoldResult;
32
24
  stateFor(ctx: ExtensionContext): Promise<{
33
25
  state: CompressionState;
34
26
  coreMessages: CoreMessage[];
35
27
  }>;
36
- /** Commit the folded state to the slot space the session's CURRENT mode
37
- * folds in (provider -> core slot, context -> context slot) — the mirror
38
- * of stateFor: a commit must land where the next read goes (issue #90). */
28
+ /** Commit the folded state to the core slot — the mirror of stateFor: a
29
+ * commit must land where the next read goes (issue #90). */
39
30
  commitFoldState(ctx: ExtensionContext, state: CompressionState, toolCallId?: string): void;
40
- /** Record the identity sequence of the last rebuilt output so the next
41
- * foldStream can recognize omp re-feeding it (issue #52). */
42
- recordRebuiltOutput(ctx: ExtensionContext, rebuilt: AgentMessage[]): void;
43
31
  /** Track the per-session streak of consecutively REJECTED compress calls.
44
32
  * `ok=false` increments and returns the new streak; `ok=true` resets to 0.
45
33
  * A re-fold (rewritten stream prefix) drops the slot and starts at 0. */
@@ -48,6 +36,22 @@ export interface AcpRuntime {
48
36
  * mode folds in (issue #104: the nudge must not demand compression while
49
37
  * compress calls are being rejected in a row). */
50
38
  rejectStreakFor(ctx: ExtensionContext): number;
39
+ /** Restore the fold slot from the previous process's checkpoint (issue
40
+ * #130). Returns true when the session already has a live in-memory slot
41
+ * (in-process switch back — never clobbered) or a valid checkpoint was
42
+ * loaded. Callers skip the primeFold mirror: a mirror that guesses the
43
+ * host's view→wire projection lands in a different fingerprint space,
44
+ * which is exactly the bug the checkpoint exists to fix. */
45
+ restoreFold(ctx: ExtensionContext): boolean;
46
+ /** Debounced checkpoint of the live fold slot. Called from the live fold
47
+ * path only (wire fold, turn commit, compress commit) — preview/mirror
48
+ * slots are never persisted. No-op when persistence is disabled. */
49
+ scheduleFoldSnapshot(ctx: ExtensionContext): void;
50
+ /** Synchronously flush the session's checkpoint. For session_shutdown:
51
+ * the host may exit as soon as the handler returns, so a debounced save
52
+ * would be dropped with the process. Returns false when the write
53
+ * failed (the in-memory slot is unaffected either way). */
54
+ flushFoldSync(sid: string): boolean;
51
55
  forgetSession(sid: string): void;
52
56
  /** Rebuild blocks from the persisted session at session_start so /acp and
53
57
  * acp_status show them BEFORE the first LLM call of a resumed session.
@@ -1,20 +1,17 @@
1
- import type { AdapterConfig } from "./config.js";
1
+ export declare const MIN_HOST_VERSION: readonly [number, number, number];
2
2
  export declare function hostVersionAtLeast(min: readonly [number, number, number], version?: string): boolean;
3
- export declare function resolveTransformMode(adapter: Pick<AdapterConfig, "transformMode">, model: {
4
- api?: string;
5
- } | undefined, hostVersion?: string): "context" | "provider";
3
+ /** True when the running host meets the minimum version omp requires. */
4
+ export declare function hostMeetsMinimum(version?: string): boolean;
6
5
  export interface ProviderDeliveryWarning {
7
6
  key: string;
8
7
  reason: string;
9
8
  message: string;
10
9
  }
11
- /** An explicit transformMode "provider" is an escape hatch for patched hosts
12
- * — but on stock hosts some APIs silently deliver NOTHING: before 17.3.8 the
13
- * host drops the before_provider_request replacement on openai-completions /
14
- * bedrock / cursor (upstream can1357/oh-my-pi#8717, issue #83), and bedrock /
15
- * cursor bodies still have no codec path even on newer hosts. The unset
16
- * default already avoids all of this; only an explicit override can land
17
- * here, so surface why instead of failing silently (ework issue #3). */
18
- export declare function providerDeliveryWarning(adapter: Pick<AdapterConfig, "transformMode">, model: {
10
+ /** Compression is delivered only where the kernel has a codec for the wire
11
+ * body. On stock hosts the other APIs (bedrock / cursor / google / devin /
12
+ * unknown) have no codec path yet — the payload passes through untransformed
13
+ * and compression is silently a no-op. Surface why instead of failing
14
+ * silently (issue #83; kernel codecs tracked upstream). */
15
+ export declare function providerDeliveryWarning(model: {
19
16
  api?: string;
20
- } | undefined, hostVersion?: string): ProviderDeliveryWarning | undefined;
17
+ } | undefined): ProviderDeliveryWarning | undefined;
@@ -6,7 +6,6 @@ import type { AdapterConfig, CompressConfig, DelegateConfig } from "./config.js"
6
6
  export interface UserAcpConfig {
7
7
  debug?: boolean;
8
8
  autoUpdate?: boolean;
9
- transformMode?: "context" | "provider";
10
9
  modelContextLimit?: number;
11
10
  toolBashDefaultTimeout?: number;
12
11
  toolOutputMaxBytes?: number;
@@ -1,14 +1,27 @@
1
- import { type BiliMessage } from "acp-kernel/wire";
2
- import { type CompressionState, type Config, type CoreMessage } from "acp-kernel";
3
- import type { AgentMessage, BlockLike, StreamCompressCall } from "./messages.js";
4
- export type ProviderWireFormat = "anthropic" | "openai";
1
+ import { type BiliMessage, type MirrorMessage, type ResponsesProjection } from "acp-kernel/wire";
2
+ import { type CompressionState, type Config } from "acp-kernel";
3
+ import type { AgentMessage } from "./messages.js";
4
+ export type ProviderWireFormat = "anthropic" | "openai" | "responses";
5
5
  /** Kernel format detection narrowed to the formats the omp pipeline can
6
- * rebuild onto the wire. null = fail-open (pass the payload through). */
6
+ * rebuild onto the wire. null = fail-open (pass the payload through).
7
+ * The kernel's detectWireFormat only recognizes `input` arrays as
8
+ * "responses"; string inputs (a single user message) are also responses
9
+ * bodies (the kernel's responsesToCore handles them), so we add that case. */
7
10
  export declare function detectProviderWireFormat(payload: unknown): ProviderWireFormat | null;
8
11
  export declare function payloadToCore(payload: unknown, fmt: ProviderWireFormat): {
9
12
  msgs: BiliMessage[];
10
13
  cacheControls?: Map<string, unknown>;
14
+ systemText?: string;
11
15
  };
16
+ /** Parse a responses body into the kernel's projection (layout + core pieces).
17
+ * The projection is needed for the rebuild (patchResponsesInput) — it carries
18
+ * the original item layout so the round-trip preserves opaque items and
19
+ * patches text in place rather than rebuilding from scratch. */
20
+ export declare function responsesProjection(payload: unknown): ResponsesProjection;
21
+ /** Rebuild the responses `input` from the projection + transformed core
22
+ * messages. Returns a string when the original input was a string (and the
23
+ * transform kept it a single user text piece); otherwise an item array. */
24
+ export declare function responsesRebuild(projection: ResponsesProjection, msgs: BiliMessage[]): string | unknown[];
12
25
  export declare function coreToPayloadMessages(msgs: BiliMessage[], fmt: ProviderWireFormat, cacheControls?: Map<string, unknown>): unknown[];
13
26
  export type Representability = {
14
27
  ok: true;
@@ -29,6 +42,16 @@ export declare function payloadRepresentable(payload: unknown, fmt: ProviderWire
29
42
  * the details and flips "" back to null; this pass re-attaches both so the
30
43
  * post-surgery body keeps the host's wire contract. */
31
44
  export declare function restoreOpenaiWireFidelity(originalMessages: unknown[], rebuilt: unknown[]): unknown[];
45
+ /** Re-attach the leading system/developer messages the kernel hoisted out of
46
+ * the fold id space (acp-kernel 0.0.37). The rebuilt message list no longer
47
+ * carries them; without this pass, a compression covering the old system
48
+ * piece dropped the model's system prompt from the wire entirely (observed
49
+ * on glm-5.3: post-compression requests went from systemLen 45151 to 0).
50
+ * Original messages are re-attached verbatim so the host's wire shape —
51
+ * system vs developer roles, message count, name fields — survives
52
+ * byte-for-byte. Mirrors the anthropic path, where the top-level system
53
+ * field never enters the fold at all. */
54
+ export declare function restoreOpenaiSystemPrefix(originalMessages: unknown[], rebuilt: unknown[]): unknown[];
32
55
  export type WireTagRenderScope = {
33
56
  config: Config;
34
57
  tokenCount: number;
@@ -55,93 +78,23 @@ export declare function applyWireTagContract(msgs: BiliMessage[], state: Compres
55
78
  * them and they ride back in the next request) — stripped before hashing
56
79
  * so re-folds of an unmutated prefix stay incremental. */
57
80
  export declare function coreIdentity(msg: BiliMessage): string;
58
- /** toolCallId → toolName from the stream's tool-call pieces. The kernel
59
- * codecs do not carry tool names on tool-result pieces, so protection
60
- * checks (compress results stay ref-BLOCKED) resolve the name here. */
61
- export declare function toolCallNames(msgs: BiliMessage[]): Map<string, string>;
62
- export declare function toolResultTextsCore(msgs: BiliMessage[]): Map<string, string>;
63
- /** Compress calls carried by a core tool-call piece. Same two shapes as the
64
- * AgentMessage stream (direct compress; legacy xd://compress via write),
65
- * with the arguments JSON-encoded in the piece's text. */
66
- export declare function findCompressCallsCore(msg: BiliMessage): StreamCompressCall[];
67
- /** Span fingerprint in content-hash space: hash the content keys of the
68
- * exact first/last covered pieces. Boundary ids are pre-resolved (byRef /
69
- * block lookup) — unlike the pN-space spanFingerprint there is no
70
- * position parsing, ids are unique per piece. */
71
- export declare function spanFingerprintCore(coreMessages: CoreMessage[], startId: string, endId: string): string;
72
- /** Index-based span fingerprint (issue #91 replay fallback): hash the content
73
- * keys of the pieces AT the given stream positions. The stored fp still
74
- * decides keep/drop — the position is only a recovery hint for a drifted
75
- * boundary whose content-hash id no longer matches, so a benign tail drift
76
- * (first-4096 intact) is kept while a real rewrite mismatches. */
77
- export declare function spanFingerprintCoreIdx(coreMessages: CoreMessage[], startIdx: number, endIdx: number): string;
78
- /** Resolve a range boundary to the exact id of the piece it names, in
79
- * content-hash space. Message refs go through byRef; block refs resolve to
80
- * the earliest (min) or latest (max) covered piece by STREAM ORDER
81
- * (index in coreMessages — the hash ids carry no position). */
82
- export declare function boundaryRawCore(ref: string, byRef: Record<string, string>, blocks: BlockLike[], coreMessages: CoreMessage[], pick: "min" | "max"): string;
83
- /** Resolve a range boundary to its STREAM INDEX in content-hash space. byRef /
84
- * block lookup first (the exact piece it names, by array order); on a missed
85
- * id (a drift re-hashed the piece so its carried ref dangles) fall back to
86
- * the compress-time recorded index — the position hint, issue #91. -1 =
87
- * unresolvable. */
88
- export declare function boundaryIndexCore(ref: string, byRef: Record<string, string>, blocks: BlockLike[], coreMessages: CoreMessage[], pick: "min" | "max", fallbackIdx?: number): number;
89
- /** Structured replay-guard verdict (issue #91, rework): the position
90
- * fallback recovers the STREAM INDEX of a drifted boundary, but the kernel
91
- * resolves ranges by REF — so when a recorded m-ref dangles, the replay
92
- * must re-apply that boundary under the CURRENT ref of the recovered piece.
93
- * `remap` carries exactly that (only dangling m-refs are remapped; block
94
- * refs resolve themselves inside the kernel and are never touched). */
95
- export type ReplayRangeVerdict = {
96
- /** Stale: the range must be dropped (master semantics, unchanged). */
97
- reject?: string;
98
- /** Dangling m-refs recovered by position, remapped to current refs. */
99
- remap?: {
100
- startRef?: string;
101
- endRef?: string;
102
- };
103
- /** True when the result text carried a [pos=] pair for this range —
104
- * with `reject` set it marks a RECOVERY FAILURE (always logged). */
105
- hint?: boolean;
106
- /** Diagnostics — always logged when a recovery happens. */
107
- recovered?: {
108
- pos: string;
109
- startIdx: number;
110
- endIdx: number;
111
- };
112
- };
113
- /** Current m-ref of the piece at stream index idx (inverse byRef scan).
114
- * "" when the piece has no ref (protected) — the replay must fail closed
115
- * rather than hand the kernel a ref it does not know. Replay-time only
116
- * (replayed compress calls), so the O(refs) scan stays off the hot path. */
117
- export declare function refOfPieceCore(coreMessages: BiliMessage[], idx: number, byRef: Record<string, string>): string;
118
- export declare function staleRangeCore(r: {
119
- startRef: string;
120
- endRef: string;
121
- }, rangeIndex: number, resultText: string, coreMessages: BiliMessage[], callIndex: number, byRef: Record<string, string>, blocks: BlockLike[]): ReplayRangeVerdict;
122
- /** One fingerprint per range for the replay guard, content-hash space
123
- * (mirrors rangeFingerprints for the pN space). */
124
- export declare function rangeFingerprintsCore(ranges: Array<{
125
- startRef: string;
126
- endRef: string;
127
- }>, coreMessages: BiliMessage[], byRef: Record<string, string>, blocks: BlockLike[]): string[];
128
- /** One boundary-index pair per range for the replay fallback (issue #91),
129
- * aligned with rangeFingerprintsCore: the stream index of each range's exact
130
- * first/last covered piece at record time ("-1" pair when a boundary can't
131
- * be positioned), so the replay can recover a drifted boundary by position. */
132
- export declare function rangePositionsCore(ranges: Array<{
133
- startRef: string;
134
- endRef: string;
135
- }>, coreMessages: CoreMessage[], byRef: Record<string, string>, blocks: BlockLike[]): string[];
136
- /** Rebuild the WIRE-SHAPE projection of the persisted session (the mirror
137
- * of the host's convertToLlm for openai chat) and parse it with the kernel
138
- * codec, so primeFold (provider mode) folds exactly the space the live
139
- * provider requests fold: system prompt first (it takes m00001), one
140
- * tool-result piece per tool result, thinking dropped (issue #64). */
81
+ export { toolCallNames, toolResultTextsCore, findCompressCallsCore, spanFingerprintCore, spanFingerprintCoreIdx, boundaryRawCore, boundaryIndexCore, refOfPieceCore, staleRangeCore, rangeFingerprintsCore, rangePositionsCore, } from "acp-kernel/wire";
82
+ export type { ReplayRangeVerdict } from "acp-kernel/wire";
83
+ /** Map the persisted session view onto the kernel's neutral MirrorMessage:
84
+ * the only omp-side shape knowledge left in this module — ref-tag
85
+ * stripping (a persisted-format concern, messages.ts) and the pi block
86
+ * types. Every wire-shape rule (system placement, reasoning_content vs
87
+ * thinking blocks vs summary_text, tool_result folding, whitespace
88
+ * handling) lives single-sourced in the acp-kernel mirror constructors
89
+ * (≥0.0.35, PR #114). */
90
+ export declare function toMirrorView(view: AgentMessage[]): MirrorMessage[];
91
+ /** primeFold openai/completions mirror (issue #64): system first, thinking
92
+ * as the `reasoning_content` field (issue #103); inline `<think>` hosts
93
+ * land in the same identity space via kernel normalization (PR #112). */
141
94
  export declare function viewToCoreStream(view: AgentMessage[], systemText: string): BiliMessage[];
142
- /** Anthropic-flavoured wire mirror for primeFold: the live anthropic
143
- * request carries the system prompt as the TOP-LEVEL `system` field (out
144
- * of the fold space) and folds tool results into user messages — mirror
145
- * exactly that, or the preview lands in a different ref space than the
146
- * live request (issue #64). */
95
+ /** primeFold anthropic/messages mirror (issue #64): system out of the fold
96
+ * space, tool results folded into user messages, signed thinking blocks. */
147
97
  export declare function viewToAnthropicCore(view: AgentMessage[]): BiliMessage[];
98
+ /** primeFold responses mirror (issue #64, responses variant): system in the
99
+ * top-level `instructions` field, conversation as the `input` item array. */
100
+ export declare function viewToResponsesCore(view: AgentMessage[], systemText: string): BiliMessage[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "billion-context-omp",
3
- "version": "0.3.1",
3
+ "version": "0.3.2-pr.138.3",
4
4
  "description": "One billion, not one million. Model-driven context management for the oh-my-pi (omp) coding agent.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -68,8 +68,7 @@
68
68
  "@oh-my-pi/pi-coding-agent": "17.3.8",
69
69
  "@oh-my-pi/pi-utils": "17.3.8",
70
70
  "@types/node": "^26.1.2",
71
- "acp-kernel": "0.0.32",
72
- "billion-context-kit": "0.2.0",
71
+ "acp-kernel": "^0.0.42",
73
72
  "bun-types": "^1.3.14",
74
73
  "tsup": "^8.5.1",
75
74
  "tsx": "^4.23.1",