@zhushanwen/pi-context-engineering 0.1.2 → 0.1.4
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/package.json +8 -4
- package/src/__tests__/compressor.test.ts +13 -12
- package/src/__tests__/frozen-fresh.test.ts +2 -1
- package/src/__tests__/integration.test.ts +12 -11
- package/src/commands.ts +7 -2
- package/src/compressor.ts +37 -131
- package/src/config.ts +10 -6
- package/src/index.ts +13 -8
- package/src/types.ts +133 -0
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zhushanwen/pi-context-engineering",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "Progressive context compression for Pi — L0 zero-cost cleanup, L1 rule-based condensation, L2 emergency truncation, with recall mechanism.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.ts",
|
|
7
7
|
"pi": {
|
|
8
8
|
"extensions": [
|
|
9
|
-
"./
|
|
9
|
+
"./index.ts"
|
|
10
10
|
]
|
|
11
11
|
},
|
|
12
12
|
"keywords": [
|
|
@@ -22,9 +22,13 @@
|
|
|
22
22
|
],
|
|
23
23
|
"peerDependencies": {
|
|
24
24
|
"@mariozechner/pi-coding-agent": "*",
|
|
25
|
-
"
|
|
25
|
+
"typebox": "*"
|
|
26
26
|
},
|
|
27
27
|
"scripts": {
|
|
28
|
-
"typecheck": "npx tsc --noEmit"
|
|
28
|
+
"typecheck": "npx tsc --noEmit",
|
|
29
|
+
"test": "vitest run"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"vitest": "^4.1.8"
|
|
29
33
|
}
|
|
30
34
|
}
|
|
@@ -1,24 +1,25 @@
|
|
|
1
|
-
import { describe, it
|
|
1
|
+
import { describe, expect,it } from "vitest";
|
|
2
|
+
|
|
2
3
|
import {
|
|
4
|
+
type AgentMessage,
|
|
5
|
+
type AssistantMessage,
|
|
6
|
+
type BashExecutionMessage,
|
|
3
7
|
compressContext,
|
|
4
|
-
|
|
8
|
+
type ContextUsage,
|
|
9
|
+
findCompactBoundary,
|
|
5
10
|
getToolResultText,
|
|
6
|
-
processMicrocompact,
|
|
7
11
|
processBudget,
|
|
8
|
-
|
|
9
|
-
type
|
|
12
|
+
processMicrocompact,
|
|
13
|
+
type TextContent,
|
|
14
|
+
type ThinkingContent,
|
|
10
15
|
type ToolCall,
|
|
11
|
-
type AssistantMessage,
|
|
12
16
|
type ToolResultMessage,
|
|
13
|
-
type BashExecutionMessage,
|
|
14
17
|
type UserMessage,
|
|
15
|
-
|
|
16
|
-
type ThinkingContent,
|
|
17
|
-
type ContextUsage,
|
|
18
|
+
validateToolPairing,
|
|
18
19
|
} from "../compressor";
|
|
19
|
-
import { createRecallStore } from "../recall-store";
|
|
20
|
-
import { createFrozenFreshState } from "../frozen-fresh";
|
|
21
20
|
import { DEFAULT_CONFIG } from "../config";
|
|
21
|
+
import { createFrozenFreshState } from "../frozen-fresh";
|
|
22
|
+
import { createRecallStore } from "../recall-store";
|
|
22
23
|
|
|
23
24
|
// ── Test helpers ──
|
|
24
25
|
|
|
@@ -1,22 +1,23 @@
|
|
|
1
|
-
import { describe, it
|
|
1
|
+
import { describe, expect,it } from "vitest";
|
|
2
|
+
|
|
3
|
+
import { handleContextEngineeringCommand, handleContextStatsCommand } from "../commands";
|
|
2
4
|
import {
|
|
3
|
-
compressContext,
|
|
4
|
-
validateToolPairing,
|
|
5
|
-
getToolResultText,
|
|
6
5
|
type AgentMessage,
|
|
7
|
-
type ToolCall,
|
|
8
6
|
type AssistantMessage,
|
|
9
|
-
type ToolResultMessage,
|
|
10
7
|
type BashExecutionMessage,
|
|
11
|
-
|
|
8
|
+
compressContext,
|
|
9
|
+
type ContextUsage,
|
|
10
|
+
getToolResultText,
|
|
12
11
|
type TextContent,
|
|
13
12
|
type ThinkingContent,
|
|
14
|
-
type
|
|
13
|
+
type ToolCall,
|
|
14
|
+
type ToolResultMessage,
|
|
15
|
+
type UserMessage,
|
|
16
|
+
validateToolPairing,
|
|
15
17
|
} from "../compressor";
|
|
16
|
-
import {
|
|
17
|
-
import { DEFAULT_CONFIG, type ContextEngineeringConfig } from "../config";
|
|
18
|
+
import { type ContextEngineeringConfig,DEFAULT_CONFIG } from "../config";
|
|
18
19
|
import { createFrozenFreshState } from "../frozen-fresh";
|
|
19
|
-
import {
|
|
20
|
+
import { createRecallStore } from "../recall-store";
|
|
20
21
|
|
|
21
22
|
// ── Helpers ──
|
|
22
23
|
|
package/src/commands.ts
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
|
+
import type { CompressionStats } from "./compressor";
|
|
1
2
|
import type { ContextEngineeringConfig } from "./config";
|
|
2
3
|
import { parseLevelArgs } from "./config";
|
|
3
|
-
import type { CompressionStats } from "./compressor";
|
|
4
4
|
|
|
5
5
|
// ── 格式化辅助 ──
|
|
6
6
|
|
|
7
|
+
// 百分比转换因子(小数 → 整数百分比)
|
|
8
|
+
const PERCENT_FACTOR = 100;
|
|
9
|
+
|
|
7
10
|
function formatConfigSummary(config: ContextEngineeringConfig): string {
|
|
8
11
|
const lines = [
|
|
9
12
|
"Context Engineering Plugin",
|
|
@@ -64,7 +67,7 @@ function formatConfigSummary(config: ContextEngineeringConfig): string {
|
|
|
64
67
|
if (config.l2.enabled) {
|
|
65
68
|
lines.push("L2 (Emergency compression):");
|
|
66
69
|
lines.push(" Enabled: true");
|
|
67
|
-
const thresholdPercent = Math.round(config.l2.emergencyThreshold *
|
|
70
|
+
const thresholdPercent = Math.round(config.l2.emergencyThreshold * PERCENT_FACTOR);
|
|
68
71
|
lines.push(
|
|
69
72
|
` Threshold: ${thresholdPercent}% | Protect recent: ${config.l2.protectRecentTurns} turns`,
|
|
70
73
|
);
|
|
@@ -143,6 +146,8 @@ export function handleContextEngineeringCommand(
|
|
|
143
146
|
config.l2.enabled = onOff;
|
|
144
147
|
return `L2 (Emergency compression) ${action === "on" ? "enabled" : "disabled"}.`;
|
|
145
148
|
}
|
|
149
|
+
// Defensive fallback — should be unreachable if parseLevelArgs validates correctly
|
|
150
|
+
return USAGE_HELP;
|
|
146
151
|
}
|
|
147
152
|
|
|
148
153
|
export function handleContextStatsCommand(stats: CompressionStats): string {
|
package/src/compressor.ts
CHANGED
|
@@ -1,148 +1,54 @@
|
|
|
1
1
|
// compressor.ts — L0/L1/L2 compression engine with tool pairing validation
|
|
2
2
|
|
|
3
|
-
import type { L0Config, L1Config, L2Config, McConfig
|
|
4
|
-
import type { RecallStore } from "./recall-store.ts";
|
|
3
|
+
import type { BudgetConfig, ContextEngineeringConfig,L0Config, L1Config, L2Config, McConfig } from "./config.ts";
|
|
5
4
|
import type { FrozenFreshState } from "./frozen-fresh.ts";
|
|
5
|
+
import type { RecallStore } from "./recall-store.ts";
|
|
6
|
+
|
|
7
|
+
// Re-export types from types.ts for backward compatibility
|
|
8
|
+
export type {
|
|
9
|
+
AgentMessage,
|
|
10
|
+
AssistantMessage,
|
|
11
|
+
BashExecutionMessage,
|
|
12
|
+
BudgetStats,
|
|
13
|
+
CompactionSummaryMessage,
|
|
14
|
+
CompressionStats,
|
|
15
|
+
ContextUsage,
|
|
16
|
+
ImageContent,
|
|
17
|
+
L0Stats,
|
|
18
|
+
McStats,
|
|
19
|
+
TextContent,
|
|
20
|
+
ThinkingContent,
|
|
21
|
+
ToolCall,
|
|
22
|
+
ToolResultMessage,
|
|
23
|
+
TurnBoundary,
|
|
24
|
+
UserMessage,
|
|
25
|
+
} from "./types.ts";
|
|
26
|
+
|
|
27
|
+
// Import types for internal use
|
|
28
|
+
import type {
|
|
29
|
+
AgentMessage,
|
|
30
|
+
BudgetStats,
|
|
31
|
+
CompressionStats,
|
|
32
|
+
ContextUsage,
|
|
33
|
+
L0Stats,
|
|
34
|
+
McStats,
|
|
35
|
+
TextContent,
|
|
36
|
+
ThinkingContent,
|
|
37
|
+
ToolResultMessage,
|
|
38
|
+
TurnBoundary,
|
|
39
|
+
} from "./types.ts";
|
|
6
40
|
|
|
7
41
|
// chars→tokens 估算因子和 fallback 上下文窗口大小
|
|
8
42
|
const CHARS_PER_TOKEN = 4;
|
|
9
43
|
const DEFAULT_CONTEXT_WINDOW = 200_000;
|
|
10
44
|
|
|
11
|
-
// ── Message types (structural subset of pi-ai + Pi coding agent) ──
|
|
12
|
-
|
|
13
|
-
export interface TextContent {
|
|
14
|
-
type: "text";
|
|
15
|
-
text: string;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export interface ThinkingContent {
|
|
19
|
-
type: "thinking";
|
|
20
|
-
thinking: string;
|
|
21
|
-
thinkingSignature?: string;
|
|
22
|
-
redacted?: boolean;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export interface ImageContent {
|
|
26
|
-
type: "image";
|
|
27
|
-
data: string;
|
|
28
|
-
mimeType: string;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export interface ToolCall {
|
|
32
|
-
type: "toolCall";
|
|
33
|
-
id: string;
|
|
34
|
-
name: string;
|
|
35
|
-
arguments: Record<string, unknown>;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export interface UserMessage {
|
|
39
|
-
role: "user";
|
|
40
|
-
content: string | (TextContent | ImageContent)[];
|
|
41
|
-
timestamp: number;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export interface AssistantMessage {
|
|
45
|
-
role: "assistant";
|
|
46
|
-
content: (TextContent | ThinkingContent | ToolCall)[];
|
|
47
|
-
api: string;
|
|
48
|
-
provider: string;
|
|
49
|
-
model: string;
|
|
50
|
-
usage: {
|
|
51
|
-
input: number;
|
|
52
|
-
output: number;
|
|
53
|
-
cacheRead: number;
|
|
54
|
-
cacheWrite: number;
|
|
55
|
-
totalTokens: number;
|
|
56
|
-
cost: { input: number; output: number; cacheRead: number; cacheWrite: number; total: number };
|
|
57
|
-
};
|
|
58
|
-
stopReason: string;
|
|
59
|
-
timestamp: number;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
export interface ToolResultMessage {
|
|
63
|
-
role: "toolResult";
|
|
64
|
-
toolCallId: string;
|
|
65
|
-
toolName: string;
|
|
66
|
-
content: (TextContent | ImageContent)[];
|
|
67
|
-
details?: unknown;
|
|
68
|
-
isError: boolean;
|
|
69
|
-
timestamp: number;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
export interface BashExecutionMessage {
|
|
73
|
-
role: "bashExecution";
|
|
74
|
-
command: string;
|
|
75
|
-
output: string;
|
|
76
|
-
exitCode: number | undefined;
|
|
77
|
-
cancelled: boolean;
|
|
78
|
-
truncated: boolean;
|
|
79
|
-
fullOutputPath?: string;
|
|
80
|
-
timestamp: number;
|
|
81
|
-
excludeFromContext?: boolean;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
export interface CompactionSummaryMessage {
|
|
85
|
-
role: "compactionSummary";
|
|
86
|
-
summary: string;
|
|
87
|
-
tokensBefore: number;
|
|
88
|
-
timestamp: number;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
export type AgentMessage =
|
|
92
|
-
| UserMessage
|
|
93
|
-
| AssistantMessage
|
|
94
|
-
| ToolResultMessage
|
|
95
|
-
| BashExecutionMessage
|
|
96
|
-
| CompactionSummaryMessage;
|
|
97
|
-
|
|
98
|
-
export interface ContextUsage {
|
|
99
|
-
tokens: number | null;
|
|
100
|
-
contextWindow: number;
|
|
101
|
-
percent: number | null;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
// ── Exported data types ──
|
|
105
|
-
|
|
106
|
-
export interface TurnBoundary {
|
|
107
|
-
startIndex: number;
|
|
108
|
-
endIndex: number; // 不含
|
|
109
|
-
timestamp: number;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
export interface L0Stats {
|
|
113
|
-
expired: number;
|
|
114
|
-
truncated: number;
|
|
115
|
-
thinkingCleared: number;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
export interface CompressionStats {
|
|
119
|
-
l0Expired: number;
|
|
120
|
-
l0Truncated: number;
|
|
121
|
-
l0ThinkingCleared: number;
|
|
122
|
-
l1Condensed: number;
|
|
123
|
-
l2Triggered: boolean;
|
|
124
|
-
validationFailed: boolean;
|
|
125
|
-
mcTriggered: boolean;
|
|
126
|
-
mcCleared: number;
|
|
127
|
-
budgetPersisted: number;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
// ── Turn boundary detection ──
|
|
131
|
-
|
|
132
45
|
// MC: 可被 Microcompact 清理的工具集
|
|
133
46
|
export const COMPACTABLE_TOOLS = new Set([
|
|
134
47
|
"read", "bash", "bash_background", "grep", "glob",
|
|
135
48
|
"web_search", "web_fetch", "edit", "write",
|
|
136
49
|
]);
|
|
137
50
|
|
|
138
|
-
|
|
139
|
-
triggered: boolean;
|
|
140
|
-
cleared: number;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
export interface BudgetStats {
|
|
144
|
-
persisted: number;
|
|
145
|
-
}
|
|
51
|
+
// ── Turn boundary detection ──
|
|
146
52
|
|
|
147
53
|
export function findTurnBoundaries(messages: AgentMessage[]): TurnBoundary[] {
|
|
148
54
|
if (messages.length === 0) return [];
|
package/src/config.ts
CHANGED
|
@@ -119,20 +119,21 @@ export function loadConfig(
|
|
|
119
119
|
settingsPath?: string,
|
|
120
120
|
): ContextEngineeringConfig {
|
|
121
121
|
const filePath =
|
|
122
|
-
settingsPath ?? join(homedir(), ".pi", "agent", "
|
|
122
|
+
settingsPath ?? join(homedir(), ".pi", "agent", "extensions", "context-engineering", "config.json");
|
|
123
123
|
|
|
124
124
|
let raw: string;
|
|
125
125
|
try {
|
|
126
126
|
raw = readFileSync(filePath, "utf-8");
|
|
127
|
-
} catch {
|
|
128
|
-
return { ...DEFAULT_CONFIG };
|
|
127
|
+
} catch (err) {
|
|
128
|
+
if ((err as NodeJS.ErrnoException).code === "ENOENT") return { ...DEFAULT_CONFIG };
|
|
129
|
+
throw new Error(`Failed to read config ${filePath}: ${(err as Error).message}`);
|
|
129
130
|
}
|
|
130
131
|
|
|
131
132
|
let parsed: Record<string, unknown>;
|
|
132
133
|
try {
|
|
133
134
|
parsed = JSON.parse(raw) as Record<string, unknown>;
|
|
134
|
-
} catch {
|
|
135
|
-
|
|
135
|
+
} catch (err) {
|
|
136
|
+
throw new Error(`Invalid JSON in ${filePath}: ${(err as Error).message}`);
|
|
136
137
|
}
|
|
137
138
|
|
|
138
139
|
const override = parsed["context-engineering"];
|
|
@@ -148,11 +149,14 @@ export function loadConfig(
|
|
|
148
149
|
|
|
149
150
|
// ── 命令参数解析 ──
|
|
150
151
|
|
|
152
|
+
// 命令参数最小部分数(target + action)
|
|
153
|
+
const MIN_COMMAND_TOKENS = 2;
|
|
154
|
+
|
|
151
155
|
export function parseLevelArgs(
|
|
152
156
|
args: string,
|
|
153
157
|
): { target: "global" | "l0" | "l1" | "l2" | "mc" | "budget"; action: "on" | "off" } | null {
|
|
154
158
|
const tokens = args.trim().split(/\s+/);
|
|
155
|
-
if (tokens.length <
|
|
159
|
+
if (tokens.length < MIN_COMMAND_TOKENS) {
|
|
156
160
|
return null;
|
|
157
161
|
}
|
|
158
162
|
|
package/src/index.ts
CHANGED
|
@@ -4,15 +4,16 @@ import type {
|
|
|
4
4
|
} from "@mariozechner/pi-coding-agent";
|
|
5
5
|
import { Type } from "typebox";
|
|
6
6
|
|
|
7
|
-
import {
|
|
8
|
-
import { createRecallStore, type RecallStore } from "./recall-store";
|
|
9
|
-
import { createFrozenFreshState, type FrozenFreshState } from "./frozen-fresh";
|
|
7
|
+
import { handleContextEngineeringCommand, handleContextStatsCommand } from "./commands";
|
|
10
8
|
import {
|
|
9
|
+
type AgentMessage as CompressorMessage,
|
|
11
10
|
compressContext,
|
|
12
11
|
type CompressionStats,
|
|
13
|
-
type
|
|
12
|
+
type ContextUsage as CompressorContextUsage,
|
|
14
13
|
} from "./compressor";
|
|
15
|
-
import {
|
|
14
|
+
import { type ContextEngineeringConfig,loadConfig } from "./config";
|
|
15
|
+
import { createFrozenFreshState, type FrozenFreshState } from "./frozen-fresh";
|
|
16
|
+
import { createRecallStore, type RecallStore } from "./recall-store";
|
|
16
17
|
|
|
17
18
|
const RecallParams = Type.Object({
|
|
18
19
|
id: Type.String({ description: "Context ID (ctx-xxxxxxxx) to recall" }),
|
|
@@ -62,13 +63,13 @@ export default function contextEngineeringExtension(pi: ExtensionAPI): void {
|
|
|
62
63
|
frozenFreshState = createFrozenFreshState();
|
|
63
64
|
});
|
|
64
65
|
|
|
65
|
-
pi.on("context", (event:
|
|
66
|
+
pi.on("context", (event: { messages: unknown[] }, ctx: { getContextUsage(): unknown }) => {
|
|
66
67
|
try {
|
|
67
68
|
// Pi Extension API types differ from our internal message types.
|
|
68
69
|
// Both sides define the same shape but TypeScript can't verify across packages.
|
|
69
70
|
// If Pi's message format changes, compressContext will gracefully fail via the catch below.
|
|
70
71
|
const msgs = event.messages as unknown as CompressorMessage[];
|
|
71
|
-
const result = compressContext(msgs, config, store, ctx.getContextUsage() as unknown as
|
|
72
|
+
const result = compressContext(msgs, config, store, ctx.getContextUsage() as unknown as CompressorContextUsage, frozenFreshState);
|
|
72
73
|
addStats(cumulativeStats, result.stats);
|
|
73
74
|
return { messages: result.messages as unknown as (typeof event.messages)[number][] };
|
|
74
75
|
} catch (err) {
|
|
@@ -80,13 +81,17 @@ export default function contextEngineeringExtension(pi: ExtensionAPI): void {
|
|
|
80
81
|
}
|
|
81
82
|
});
|
|
82
83
|
|
|
84
|
+
pi.on("session_tree", async () => {
|
|
85
|
+
// 切换分支后,cumulativeStats 将在下次 context 事件时自然更新
|
|
86
|
+
});
|
|
87
|
+
|
|
83
88
|
pi.registerTool({
|
|
84
89
|
name: "recall_context",
|
|
85
90
|
label: "Recall Compressed Context",
|
|
86
91
|
description: "Recall original content compressed by context engineering. Use when you need the full content of an expired, truncated, or condensed tool result.",
|
|
87
92
|
promptSnippet: "recall_context(id) — retrieve original content compressed by context engineering",
|
|
88
93
|
parameters: RecallParams,
|
|
89
|
-
execute: async (_tcId: string, params:
|
|
94
|
+
execute: async (_tcId: string, params: { id: string }, _sig: unknown, _upd: unknown, _ctx: unknown) => recallResult(params.id, store),
|
|
90
95
|
});
|
|
91
96
|
|
|
92
97
|
pi.registerCommand("context-engineering", {
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
// types.ts — Shared type definitions for context-engineering extension
|
|
2
|
+
|
|
3
|
+
// ── Message content block types ──
|
|
4
|
+
|
|
5
|
+
export interface TextContent {
|
|
6
|
+
type: "text";
|
|
7
|
+
text: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface ThinkingContent {
|
|
11
|
+
type: "thinking";
|
|
12
|
+
thinking: string;
|
|
13
|
+
thinkingSignature?: string;
|
|
14
|
+
redacted?: boolean;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface ImageContent {
|
|
18
|
+
type: "image";
|
|
19
|
+
data: string;
|
|
20
|
+
mimeType: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface ToolCall {
|
|
24
|
+
type: "toolCall";
|
|
25
|
+
id: string;
|
|
26
|
+
name: string;
|
|
27
|
+
arguments: Record<string, unknown>;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// ── Message types (structural subset of pi-ai + Pi coding agent) ──
|
|
31
|
+
|
|
32
|
+
export interface UserMessage {
|
|
33
|
+
role: "user";
|
|
34
|
+
content: string | (TextContent | ImageContent)[];
|
|
35
|
+
timestamp: number;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface AssistantMessage {
|
|
39
|
+
role: "assistant";
|
|
40
|
+
content: (TextContent | ThinkingContent | ToolCall)[];
|
|
41
|
+
api: string;
|
|
42
|
+
provider: string;
|
|
43
|
+
model: string;
|
|
44
|
+
usage: {
|
|
45
|
+
input: number;
|
|
46
|
+
output: number;
|
|
47
|
+
cacheRead: number;
|
|
48
|
+
cacheWrite: number;
|
|
49
|
+
totalTokens: number;
|
|
50
|
+
cost: { input: number; output: number; cacheRead: number; cacheWrite: number; total: number };
|
|
51
|
+
};
|
|
52
|
+
stopReason: string;
|
|
53
|
+
timestamp: number;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export interface ToolResultMessage {
|
|
57
|
+
role: "toolResult";
|
|
58
|
+
toolCallId: string;
|
|
59
|
+
toolName: string;
|
|
60
|
+
content: (TextContent | ImageContent)[];
|
|
61
|
+
details?: unknown;
|
|
62
|
+
isError: boolean;
|
|
63
|
+
timestamp: number;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export interface BashExecutionMessage {
|
|
67
|
+
role: "bashExecution";
|
|
68
|
+
command: string;
|
|
69
|
+
output: string;
|
|
70
|
+
exitCode: number | undefined;
|
|
71
|
+
cancelled: boolean;
|
|
72
|
+
truncated: boolean;
|
|
73
|
+
fullOutputPath?: string;
|
|
74
|
+
timestamp: number;
|
|
75
|
+
excludeFromContext?: boolean;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export interface CompactionSummaryMessage {
|
|
79
|
+
role: "compactionSummary";
|
|
80
|
+
summary: string;
|
|
81
|
+
tokensBefore: number;
|
|
82
|
+
timestamp: number;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export type AgentMessage =
|
|
86
|
+
| UserMessage
|
|
87
|
+
| AssistantMessage
|
|
88
|
+
| ToolResultMessage
|
|
89
|
+
| BashExecutionMessage
|
|
90
|
+
| CompactionSummaryMessage;
|
|
91
|
+
|
|
92
|
+
// ── Domain types ──
|
|
93
|
+
|
|
94
|
+
export interface ContextUsage {
|
|
95
|
+
tokens: number | null;
|
|
96
|
+
contextWindow: number;
|
|
97
|
+
percent: number | null;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export interface TurnBoundary {
|
|
101
|
+
startIndex: number;
|
|
102
|
+
endIndex: number; // 不含
|
|
103
|
+
timestamp: number;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// ── Stats types ──
|
|
107
|
+
|
|
108
|
+
export interface L0Stats {
|
|
109
|
+
expired: number;
|
|
110
|
+
truncated: number;
|
|
111
|
+
thinkingCleared: number;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export interface CompressionStats {
|
|
115
|
+
l0Expired: number;
|
|
116
|
+
l0Truncated: number;
|
|
117
|
+
l0ThinkingCleared: number;
|
|
118
|
+
l1Condensed: number;
|
|
119
|
+
l2Triggered: boolean;
|
|
120
|
+
validationFailed: boolean;
|
|
121
|
+
mcTriggered: boolean;
|
|
122
|
+
mcCleared: number;
|
|
123
|
+
budgetPersisted: number;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export interface McStats {
|
|
127
|
+
triggered: boolean;
|
|
128
|
+
cleared: number;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export interface BudgetStats {
|
|
132
|
+
persisted: number;
|
|
133
|
+
}
|