billion-context-omp 0.2.6 → 0.2.7
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 +1 -1
- package/README.zh-CN.md +1 -1
- package/dist/config.d.ts +14 -8
- package/dist/index.js +915 -279
- package/dist/index.js.map +1 -1
- package/dist/messages.d.ts +19 -0
- package/dist/runtime.d.ts +16 -1
- package/dist/transform-mode.d.ts +5 -0
- package/dist/wire-fold.d.ts +116 -0
- package/package.json +7 -7
- package/dist/wire-transform.d.ts +0 -71
package/dist/messages.d.ts
CHANGED
|
@@ -20,7 +20,26 @@ export interface StreamCompressCall {
|
|
|
20
20
|
}[];
|
|
21
21
|
}
|
|
22
22
|
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;
|
|
23
41
|
export declare function extractText(content: unknown, stripTags?: boolean): string;
|
|
42
|
+
export declare function stripRefTag(text: string): string;
|
|
24
43
|
export declare function messageIdentity(message: unknown): string;
|
|
25
44
|
export declare function matchesStoredText(stored: string, visible: string): boolean;
|
|
26
45
|
export declare function coreOutToAgentMessages(coreOut: CoreMessage[], originalById: Map<string, AgentMessage>): AgentMessage[];
|
package/dist/runtime.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
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
|
+
import type { BiliMessage } from "acp-kernel/wire";
|
|
4
5
|
import { type AgentMessage } from "./messages.js";
|
|
5
6
|
export interface FoldResult {
|
|
6
7
|
state: CompressionState;
|
|
@@ -8,6 +9,13 @@ export interface FoldResult {
|
|
|
8
9
|
originalById: Map<string, AgentMessage>;
|
|
9
10
|
streamLen: number;
|
|
10
11
|
}
|
|
12
|
+
/** Core-space fold result (provider mode): no originalById — the output
|
|
13
|
+
* rebuilds straight onto the wire via the kernel codecs. */
|
|
14
|
+
export interface CoreFoldResult {
|
|
15
|
+
state: CompressionState;
|
|
16
|
+
coreMessages: BiliMessage[];
|
|
17
|
+
streamLen: number;
|
|
18
|
+
}
|
|
11
19
|
export interface AcpRuntime {
|
|
12
20
|
core: CompressionCore;
|
|
13
21
|
adapter: AdapterConfig;
|
|
@@ -17,10 +25,17 @@ export interface AcpRuntime {
|
|
|
17
25
|
liveContextLimit(ctx: ExtensionContext): number;
|
|
18
26
|
configFor(ctx: ExtensionContext): Config;
|
|
19
27
|
foldStream(ctx: ExtensionContext, stream: AgentMessage[]): FoldResult;
|
|
28
|
+
/** 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). */
|
|
31
|
+
foldStreamCore(ctx: ExtensionContext, stream: BiliMessage[]): CoreFoldResult;
|
|
20
32
|
stateFor(ctx: ExtensionContext): Promise<{
|
|
21
33
|
state: CompressionState;
|
|
22
34
|
coreMessages: CoreMessage[];
|
|
23
35
|
}>;
|
|
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). */
|
|
24
39
|
commitFoldState(ctx: ExtensionContext, state: CompressionState, toolCallId?: string): void;
|
|
25
40
|
/** Record the identity sequence of the last rebuilt output so the next
|
|
26
41
|
* foldStream can recognize omp re-feeding it (issue #52). */
|
|
@@ -32,7 +47,7 @@ export interface AcpRuntime {
|
|
|
32
47
|
forgetSession(sid: string): void;
|
|
33
48
|
/** Rebuild blocks from the persisted session at session_start so /acp and
|
|
34
49
|
* acp_status show them BEFORE the first LLM call of a resumed session.
|
|
35
|
-
* Provider mode folds the WIRE projection (
|
|
50
|
+
* Provider mode folds the WIRE projection (wire-fold.ts mirrors — the
|
|
36
51
|
* authoritative fold runs on the wire-synthesized stream, which differs
|
|
37
52
|
* from the raw session view; issue #64). The slot is marked preview and
|
|
38
53
|
* always re-folded authoritatively at the first live event (the live
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { AdapterConfig } from "./config.js";
|
|
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";
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { type BiliMessage } from "acp-kernel/wire";
|
|
2
|
+
import { type CompressionState, type CoreMessage } from "acp-kernel";
|
|
3
|
+
import type { AgentMessage, BlockLike, StreamCompressCall } from "./messages.js";
|
|
4
|
+
export type ProviderWireFormat = "anthropic" | "openai";
|
|
5
|
+
/** Kernel format detection narrowed to the formats the omp pipeline can
|
|
6
|
+
* rebuild onto the wire. null = fail-open (pass the payload through). */
|
|
7
|
+
export declare function detectProviderWireFormat(payload: unknown): ProviderWireFormat | null;
|
|
8
|
+
export declare function payloadToCore(payload: unknown, fmt: ProviderWireFormat): {
|
|
9
|
+
msgs: BiliMessage[];
|
|
10
|
+
cacheControls?: Map<string, unknown>;
|
|
11
|
+
};
|
|
12
|
+
export declare function coreToPayloadMessages(msgs: BiliMessage[], fmt: ProviderWireFormat, cacheControls?: Map<string, unknown>): unknown[];
|
|
13
|
+
/** omp's wire tag contract (issue #66) on top of the kernel's "text-only"
|
|
14
|
+
* render: the proxy keeps tool content pristine, but omp's nudge ranges
|
|
15
|
+
* target tool results — the model must be able to cite them by ref, so tag
|
|
16
|
+
* the tool-result pieces (kernel renderer, format single-sourced). The
|
|
17
|
+
* kernel's "text-only" also tags assistant text — strip it: the model
|
|
18
|
+
* echoes tags it sees on its own responses (the contract patchRefTag
|
|
19
|
+
* enforced in the AgentMessage bridge). Tool-call args stay clean (replay
|
|
20
|
+
* JSON-parses them). */
|
|
21
|
+
export declare function applyWireTagContract(msgs: BiliMessage[], state: CompressionState): BiliMessage[];
|
|
22
|
+
/** Stable cross-turn identity for the core-space LCP fold. The text carries
|
|
23
|
+
* our own <acp> ref tags from the previous turn's output (the model sees
|
|
24
|
+
* them and they ride back in the next request) — stripped before hashing
|
|
25
|
+
* so re-folds of an unmutated prefix stay incremental. */
|
|
26
|
+
export declare function coreIdentity(msg: BiliMessage): string;
|
|
27
|
+
/** toolCallId → toolName from the stream's tool-call pieces. The kernel
|
|
28
|
+
* codecs do not carry tool names on tool-result pieces, so protection
|
|
29
|
+
* checks (compress results stay ref-BLOCKED) resolve the name here. */
|
|
30
|
+
export declare function toolCallNames(msgs: BiliMessage[]): Map<string, string>;
|
|
31
|
+
export declare function toolResultTextsCore(msgs: BiliMessage[]): Map<string, string>;
|
|
32
|
+
/** Compress calls carried by a core tool-call piece. Same two shapes as the
|
|
33
|
+
* AgentMessage stream (direct compress; legacy xd://compress via write),
|
|
34
|
+
* with the arguments JSON-encoded in the piece's text. */
|
|
35
|
+
export declare function findCompressCallsCore(msg: BiliMessage): StreamCompressCall[];
|
|
36
|
+
/** Span fingerprint in content-hash space: hash the content keys of the
|
|
37
|
+
* exact first/last covered pieces. Boundary ids are pre-resolved (byRef /
|
|
38
|
+
* block lookup) — unlike the pN-space spanFingerprint there is no
|
|
39
|
+
* position parsing, ids are unique per piece. */
|
|
40
|
+
export declare function spanFingerprintCore(coreMessages: CoreMessage[], startId: string, endId: string): string;
|
|
41
|
+
/** Index-based span fingerprint (issue #91 replay fallback): hash the content
|
|
42
|
+
* keys of the pieces AT the given stream positions. The stored fp still
|
|
43
|
+
* decides keep/drop — the position is only a recovery hint for a drifted
|
|
44
|
+
* boundary whose content-hash id no longer matches, so a benign tail drift
|
|
45
|
+
* (first-4096 intact) is kept while a real rewrite mismatches. */
|
|
46
|
+
export declare function spanFingerprintCoreIdx(coreMessages: CoreMessage[], startIdx: number, endIdx: number): string;
|
|
47
|
+
/** Resolve a range boundary to the exact id of the piece it names, in
|
|
48
|
+
* content-hash space. Message refs go through byRef; block refs resolve to
|
|
49
|
+
* the earliest (min) or latest (max) covered piece by STREAM ORDER
|
|
50
|
+
* (index in coreMessages — the hash ids carry no position). */
|
|
51
|
+
export declare function boundaryRawCore(ref: string, byRef: Record<string, string>, blocks: BlockLike[], coreMessages: CoreMessage[], pick: "min" | "max"): string;
|
|
52
|
+
/** Resolve a range boundary to its STREAM INDEX in content-hash space. byRef /
|
|
53
|
+
* block lookup first (the exact piece it names, by array order); on a missed
|
|
54
|
+
* id (a drift re-hashed the piece so its carried ref dangles) fall back to
|
|
55
|
+
* the compress-time recorded index — the position hint, issue #91. -1 =
|
|
56
|
+
* unresolvable. */
|
|
57
|
+
export declare function boundaryIndexCore(ref: string, byRef: Record<string, string>, blocks: BlockLike[], coreMessages: CoreMessage[], pick: "min" | "max", fallbackIdx?: number): number;
|
|
58
|
+
/** Structured replay-guard verdict (issue #91, rework): the position
|
|
59
|
+
* fallback recovers the STREAM INDEX of a drifted boundary, but the kernel
|
|
60
|
+
* resolves ranges by REF — so when a recorded m-ref dangles, the replay
|
|
61
|
+
* must re-apply that boundary under the CURRENT ref of the recovered piece.
|
|
62
|
+
* `remap` carries exactly that (only dangling m-refs are remapped; block
|
|
63
|
+
* refs resolve themselves inside the kernel and are never touched). */
|
|
64
|
+
export type ReplayRangeVerdict = {
|
|
65
|
+
/** Stale: the range must be dropped (master semantics, unchanged). */
|
|
66
|
+
reject?: string;
|
|
67
|
+
/** Dangling m-refs recovered by position, remapped to current refs. */
|
|
68
|
+
remap?: {
|
|
69
|
+
startRef?: string;
|
|
70
|
+
endRef?: string;
|
|
71
|
+
};
|
|
72
|
+
/** True when the result text carried a [pos=] pair for this range —
|
|
73
|
+
* with `reject` set it marks a RECOVERY FAILURE (always logged). */
|
|
74
|
+
hint?: boolean;
|
|
75
|
+
/** Diagnostics — always logged when a recovery happens. */
|
|
76
|
+
recovered?: {
|
|
77
|
+
pos: string;
|
|
78
|
+
startIdx: number;
|
|
79
|
+
endIdx: number;
|
|
80
|
+
};
|
|
81
|
+
};
|
|
82
|
+
/** Current m-ref of the piece at stream index idx (inverse byRef scan).
|
|
83
|
+
* "" when the piece has no ref (protected) — the replay must fail closed
|
|
84
|
+
* rather than hand the kernel a ref it does not know. Replay-time only
|
|
85
|
+
* (replayed compress calls), so the O(refs) scan stays off the hot path. */
|
|
86
|
+
export declare function refOfPieceCore(coreMessages: BiliMessage[], idx: number, byRef: Record<string, string>): string;
|
|
87
|
+
export declare function staleRangeCore(r: {
|
|
88
|
+
startRef: string;
|
|
89
|
+
endRef: string;
|
|
90
|
+
}, rangeIndex: number, resultText: string, coreMessages: BiliMessage[], callIndex: number, byRef: Record<string, string>, blocks: BlockLike[]): ReplayRangeVerdict;
|
|
91
|
+
/** One fingerprint per range for the replay guard, content-hash space
|
|
92
|
+
* (mirrors rangeFingerprints for the pN space). */
|
|
93
|
+
export declare function rangeFingerprintsCore(ranges: Array<{
|
|
94
|
+
startRef: string;
|
|
95
|
+
endRef: string;
|
|
96
|
+
}>, coreMessages: BiliMessage[], byRef: Record<string, string>, blocks: BlockLike[]): string[];
|
|
97
|
+
/** One boundary-index pair per range for the replay fallback (issue #91),
|
|
98
|
+
* aligned with rangeFingerprintsCore: the stream index of each range's exact
|
|
99
|
+
* first/last covered piece at record time ("-1" pair when a boundary can't
|
|
100
|
+
* be positioned), so the replay can recover a drifted boundary by position. */
|
|
101
|
+
export declare function rangePositionsCore(ranges: Array<{
|
|
102
|
+
startRef: string;
|
|
103
|
+
endRef: string;
|
|
104
|
+
}>, coreMessages: CoreMessage[], byRef: Record<string, string>, blocks: BlockLike[]): string[];
|
|
105
|
+
/** Rebuild the WIRE-SHAPE projection of the persisted session (the mirror
|
|
106
|
+
* of the host's convertToLlm for openai chat) and parse it with the kernel
|
|
107
|
+
* codec, so primeFold (provider mode) folds exactly the space the live
|
|
108
|
+
* provider requests fold: system prompt first (it takes m00001), one
|
|
109
|
+
* tool-result piece per tool result, thinking dropped (issue #64). */
|
|
110
|
+
export declare function viewToCoreStream(view: AgentMessage[], systemText: string): BiliMessage[];
|
|
111
|
+
/** Anthropic-flavoured wire mirror for primeFold: the live anthropic
|
|
112
|
+
* request carries the system prompt as the TOP-LEVEL `system` field (out
|
|
113
|
+
* of the fold space) and folds tool results into user messages — mirror
|
|
114
|
+
* exactly that, or the preview lands in a different ref space than the
|
|
115
|
+
* live request (issue #64). */
|
|
116
|
+
export declare function viewToAnthropicCore(view: AgentMessage[]): BiliMessage[];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "billion-context-omp",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.7",
|
|
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",
|
|
@@ -62,13 +62,13 @@
|
|
|
62
62
|
"@oh-my-pi/omptype": ">=17.0.0"
|
|
63
63
|
},
|
|
64
64
|
"devDependencies": {
|
|
65
|
-
"@oh-my-pi/omptype": "17.3.
|
|
66
|
-
"@oh-my-pi/pi-agent-core": "17.3.
|
|
67
|
-
"@oh-my-pi/pi-ai": "17.3.
|
|
68
|
-
"@oh-my-pi/pi-coding-agent": "17.3.
|
|
69
|
-
"@oh-my-pi/pi-utils": "17.3.
|
|
65
|
+
"@oh-my-pi/omptype": "17.3.8",
|
|
66
|
+
"@oh-my-pi/pi-agent-core": "17.3.8",
|
|
67
|
+
"@oh-my-pi/pi-ai": "17.3.8",
|
|
68
|
+
"@oh-my-pi/pi-coding-agent": "17.3.8",
|
|
69
|
+
"@oh-my-pi/pi-utils": "17.3.8",
|
|
70
70
|
"@types/node": "^26.1.2",
|
|
71
|
-
"acp-kernel": "0.0.
|
|
71
|
+
"acp-kernel": "0.0.28",
|
|
72
72
|
"billion-context-kit": "0.2.0",
|
|
73
73
|
"bun-types": "^1.3.14",
|
|
74
74
|
"tsup": "^8.5.1",
|
package/dist/wire-transform.d.ts
DELETED
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
import type { AgentMessage } from "./messages.js";
|
|
2
|
-
import type { AnthropicRequestBody } from "acp-kernel/wire";
|
|
3
|
-
export type WireFormat = "anthropic" | "openai" | "unknown";
|
|
4
|
-
interface AnthropicBlock {
|
|
5
|
-
type?: string;
|
|
6
|
-
text?: string;
|
|
7
|
-
id?: string;
|
|
8
|
-
name?: string;
|
|
9
|
-
input?: unknown;
|
|
10
|
-
tool_use_id?: string;
|
|
11
|
-
content?: unknown;
|
|
12
|
-
is_error?: boolean;
|
|
13
|
-
cache_control?: unknown;
|
|
14
|
-
[k: string]: unknown;
|
|
15
|
-
}
|
|
16
|
-
interface AnthropicWireMessage {
|
|
17
|
-
role: string;
|
|
18
|
-
content: string | AnthropicBlock[];
|
|
19
|
-
[k: string]: unknown;
|
|
20
|
-
}
|
|
21
|
-
interface OpenAIWireMessage {
|
|
22
|
-
role: string;
|
|
23
|
-
content?: unknown;
|
|
24
|
-
tool_calls?: Array<{
|
|
25
|
-
id: string;
|
|
26
|
-
function?: {
|
|
27
|
-
name?: string;
|
|
28
|
-
arguments?: string;
|
|
29
|
-
};
|
|
30
|
-
}>;
|
|
31
|
-
tool_call_id?: string;
|
|
32
|
-
[k: string]: unknown;
|
|
33
|
-
}
|
|
34
|
-
export interface SynthesisResult {
|
|
35
|
-
stream: AgentMessage[];
|
|
36
|
-
back: Array<{
|
|
37
|
-
wi: number;
|
|
38
|
-
kind: "text" | "toolCall" | "toolResult";
|
|
39
|
-
}>;
|
|
40
|
-
format: WireFormat;
|
|
41
|
-
}
|
|
42
|
-
export declare function detectWireFormat(payload: unknown): WireFormat;
|
|
43
|
-
export declare function synthesizeStream(payload: unknown, format: WireFormat): SynthesisResult;
|
|
44
|
-
/** Rebuild the wire payload from the transformed stream. Survivors reuse the
|
|
45
|
-
* ORIGINAL wire message objects (patched text only) so every field we do not
|
|
46
|
-
* understand — cache_control, citations, provider extras — passes through
|
|
47
|
-
* byte-identical. Only synthesized messages (nudge) are built from scratch.
|
|
48
|
-
* Returns the ORIGINAL payload object when nothing changed (cache-safe). */
|
|
49
|
-
export declare function rebuildWirePayload(rebuilt: AgentMessage[], payload: unknown, synth: SynthesisResult): unknown;
|
|
50
|
-
/** Rebuild the WIRE-SHAPE view of the persisted session (the mirror of the
|
|
51
|
-
* host's convertToLlm) and run it through the SAME synthesizeStream the
|
|
52
|
-
* live provider fold uses, so primeFold (provider mode) folds exactly the
|
|
53
|
-
* authoritative projection. The raw session view is NOT equivalent: for
|
|
54
|
-
* openai-style payloads the system prompt is a message in the wire body —
|
|
55
|
-
* it becomes the first core piece and takes m00001 — and the openai
|
|
56
|
-
* synthesis cannot recover tool names for `role:"tool"` entries (a
|
|
57
|
-
* compress result gets toolName "" instead of "compress", so it is not
|
|
58
|
-
* ref-BLOCKED there). Folding the raw view puts the fold in a different
|
|
59
|
-
* ref/fingerprint space: stored span fingerprints mismatch, the guard
|
|
60
|
-
* rejects every in-stream replay, and a resumed session shows
|
|
61
|
-
* "Blocks: none" until the first provider request (issue #64).
|
|
62
|
-
*
|
|
63
|
-
* Message shapes mirror the captured live payload (openai chat):
|
|
64
|
-
* system first; assistant text and/or tool_calls (content "" when only
|
|
65
|
-
* calls); one `role:"tool"` message per tool result; thinking dropped
|
|
66
|
-
* (the host does not carry it in this format). */
|
|
67
|
-
export declare function viewToWireStream(view: AgentMessage[], systemText: string): AgentMessage[];
|
|
68
|
-
/** True when the payload carries no messages we could fold (e.g. an empty
|
|
69
|
-
* tools-only probe). The caller bypasses instead of transforming. */
|
|
70
|
-
export declare function synthesisIsEmpty(synth: SynthesisResult): boolean;
|
|
71
|
-
export type { AnthropicRequestBody, OpenAIWireMessage, AnthropicWireMessage };
|