compressed-context 0.1.0 → 0.1.1
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 +64 -64
- package/src/compression/active-summary-cache.ts +50 -50
- package/src/compression/adopt.ts +57 -57
- package/src/compression/auto.ts +372 -372
- package/src/compression/babel.ts +85 -85
- package/src/compression/block.ts +25 -25
- package/src/compression/cache-history.ts +75 -75
- package/src/compression/compaction.ts +189 -189
- package/src/compression/decompress-tool.ts +74 -74
- package/src/compression/decompress.ts +292 -292
- package/src/compression/deleted-sessions.ts +24 -24
- package/src/compression/distill.ts +220 -220
- package/src/compression/events.ts +275 -275
- package/src/compression/markdown.ts +53 -53
- package/src/compression/normalize.ts +114 -114
- package/src/compression/render.ts +70 -70
- package/src/compression/schema.ts +84 -84
- package/src/compression/select.ts +123 -123
- package/src/compression/session-message.ts +112 -112
- package/src/compression/settings-rpc.ts +111 -111
- package/src/compression/settings.ts +175 -175
- package/src/compression/state.ts +248 -248
- package/src/compression/summarize.ts +595 -595
- package/src/compression/summary.ts +73 -73
- package/src/compression/tool.ts +142 -142
- package/src/compression/transcript-store.ts +258 -258
- package/src/compression/transcript.ts +63 -63
- package/src/compression/validate.ts +81 -81
- package/src/i18n/en.ts +93 -93
- package/src/i18n/index.ts +28 -28
- package/src/i18n/types.ts +89 -89
- package/src/i18n/zh.ts +93 -93
- package/src/index.ts +108 -108
- package/src/shared/blocks.ts +17 -17
- package/src/shared/cache.ts +199 -199
- package/src/shared/format.ts +23 -23
- package/src/shared/media.ts +184 -184
- package/src/shared/parse.ts +25 -25
- package/src/shared/parts.ts +72 -72
- package/src/shared/rpc.ts +145 -145
- package/src/shared/scan.ts +32 -32
- package/src/shared/settings.ts +471 -471
- package/src/shared/stats.ts +142 -142
- package/src/shared/tokens.ts +259 -259
- package/src/tui/chart/cache-chart.ts +237 -237
- package/src/tui/chart/color.ts +58 -58
- package/src/tui/index.tsx +111 -111
- package/src/tui/panel/cache.tsx +203 -203
- package/src/tui/panel/data.ts +105 -105
- package/src/tui/panel/index.tsx +176 -176
- package/src/tui/panel/summaries.tsx +192 -192
- package/src/tui/settings/dialogs.tsx +215 -215
- package/src/tui/settings/options.ts +238 -238
- package/src/tui/settings.tsx +418 -418
- package/src/tui/types.ts +4 -4
package/src/i18n/zh.ts
CHANGED
|
@@ -1,93 +1,93 @@
|
|
|
1
|
-
import type { Messages } from "./types.ts"
|
|
2
|
-
|
|
3
|
-
/** 中文文案。标签控制在 4 个字以内,侧栏窄也能放下。 */
|
|
4
|
-
export const zh: Messages = {
|
|
5
|
-
title: "上下文构成",
|
|
6
|
-
labels: {
|
|
7
|
-
system: "系统",
|
|
8
|
-
tools: "工具定义",
|
|
9
|
-
tool: "工具结果",
|
|
10
|
-
text: "文本",
|
|
11
|
-
recent: "最近保留",
|
|
12
|
-
summaries: "摘要",
|
|
13
|
-
media: "媒体",
|
|
14
|
-
},
|
|
15
|
-
approximate: "≈",
|
|
16
|
-
terminal: "上下文无法继续压缩,请开新会话或使用原生压缩",
|
|
17
|
-
cacheTitle: "缓存记录",
|
|
18
|
-
cacheChart: "折线图",
|
|
19
|
-
cacheLog: "日志",
|
|
20
|
-
cacheInput: "输入",
|
|
21
|
-
cacheOutput: "输出",
|
|
22
|
-
cacheCached: "缓存",
|
|
23
|
-
cacheHit: "命中",
|
|
24
|
-
summariesTitle: "摘要块",
|
|
25
|
-
noData: "—",
|
|
26
|
-
command: {
|
|
27
|
-
title: "压缩上下文设置",
|
|
28
|
-
description: "打开插件设置",
|
|
29
|
-
group: "插件",
|
|
30
|
-
},
|
|
31
|
-
settings: {
|
|
32
|
-
title: "压缩上下文插件设置",
|
|
33
|
-
show: "显示面板",
|
|
34
|
-
limit: "上下文上限",
|
|
35
|
-
limitAuto: "模型原生",
|
|
36
|
-
limitCustom: "自定义上限…",
|
|
37
|
-
limitHint: "填的是上限;实际窗口取「设置值」和「模型原生窗口」中较小的那个。纯数字或带 k/m 后缀",
|
|
38
|
-
limitInvalid: "请输入有效的 token 数",
|
|
39
|
-
limitPlaceholder: "200k",
|
|
40
|
-
limitPreview: (value) => `= ${value} tokens`,
|
|
41
|
-
limitCapped: (requested, actual) => `${requested}(模型上限 ${actual})`,
|
|
42
|
-
threshold: "压缩阈值",
|
|
43
|
-
thresholdHint: "输入 60 ~ 95 之间的整数(百分比)",
|
|
44
|
-
thresholdInvalid: "阈值必须在 60 ~ 95 之间",
|
|
45
|
-
thresholdPreview: (value) => `= ${value}%`,
|
|
46
|
-
nudgeGrowth: "压缩提醒间隔",
|
|
47
|
-
nudgeGrowthHint: "上下文每增长这么多 token 提醒模型可主动压缩;0 关闭",
|
|
48
|
-
nudgeGrowthInvalid: "请输入 0,或 1k ~ 200k",
|
|
49
|
-
summaryBlockPercent: "单条摘要上限",
|
|
50
|
-
summaryBlockPercentHint: "单条摘要最多占窗口的百分比;可输入 10% 或 20k",
|
|
51
|
-
summaryTotalPercent: "全部摘要上限",
|
|
52
|
-
summaryTotalPercentHint: "所有摘要加起来最多占窗口的百分比;可输入 50% 或 100k",
|
|
53
|
-
summaryPercentInvalid: "请输入 1% ~ 90%,或一个能换算成百分比的 token 数",
|
|
54
|
-
windowKnown: (value) => `当前窗口:${value}`,
|
|
55
|
-
windowUnknown: "当前窗口未知(先跑一次模型请求)",
|
|
56
|
-
summaryLanguage: "摘要语言",
|
|
57
|
-
summaryFormat: "摘要格式",
|
|
58
|
-
summaryFormatJson: "JSON(结构化)",
|
|
59
|
-
summaryFormatMarkdown: "Markdown(自然语言)",
|
|
60
|
-
summaryFormatBabel: "Babel(模型间高密度)",
|
|
61
|
-
autoCompress: "自动压缩",
|
|
62
|
-
enableCompressTool: "compress 工具",
|
|
63
|
-
enableDecompressTool: "decompress 工具",
|
|
64
|
-
showTimeline: "块头时间线",
|
|
65
|
-
showBlockTokens: "块头 token 估算",
|
|
66
|
-
showCacheChart: "显示缓存折线图",
|
|
67
|
-
showCacheLog: "显示缓存日志",
|
|
68
|
-
showSummaries: "显示摘要块",
|
|
69
|
-
categories: {
|
|
70
|
-
compress: "压缩",
|
|
71
|
-
summary: "摘要",
|
|
72
|
-
panel: "面板",
|
|
73
|
-
decompress: "解压",
|
|
74
|
-
interface: "界面",
|
|
75
|
-
},
|
|
76
|
-
decompressInlineMax: "解压内联上限",
|
|
77
|
-
decompressInlineMaxHint: "超过这个字符数就写成临时文件;输入纯数字或带 k/m 后缀",
|
|
78
|
-
decompressInlineMaxInvalid: "请输入 1k ~ 1m 之间的字符数",
|
|
79
|
-
decompressTempCap: "解压临时文件上限",
|
|
80
|
-
decompressTempCapHint: "最多保留多少个解压临时文件",
|
|
81
|
-
decompressTempCapInvalid: "请输入 1 ~ 1000 之间的整数",
|
|
82
|
-
decompressShowTokens: "解压返回 token 估算",
|
|
83
|
-
submit: "提交",
|
|
84
|
-
language: "语言",
|
|
85
|
-
auto: "自动",
|
|
86
|
-
on: "开",
|
|
87
|
-
off: "关",
|
|
88
|
-
},
|
|
89
|
-
languages: {
|
|
90
|
-
zh: "中文",
|
|
91
|
-
en: "English",
|
|
92
|
-
},
|
|
93
|
-
}
|
|
1
|
+
import type { Messages } from "./types.ts"
|
|
2
|
+
|
|
3
|
+
/** 中文文案。标签控制在 4 个字以内,侧栏窄也能放下。 */
|
|
4
|
+
export const zh: Messages = {
|
|
5
|
+
title: "上下文构成",
|
|
6
|
+
labels: {
|
|
7
|
+
system: "系统",
|
|
8
|
+
tools: "工具定义",
|
|
9
|
+
tool: "工具结果",
|
|
10
|
+
text: "文本",
|
|
11
|
+
recent: "最近保留",
|
|
12
|
+
summaries: "摘要",
|
|
13
|
+
media: "媒体",
|
|
14
|
+
},
|
|
15
|
+
approximate: "≈",
|
|
16
|
+
terminal: "上下文无法继续压缩,请开新会话或使用原生压缩",
|
|
17
|
+
cacheTitle: "缓存记录",
|
|
18
|
+
cacheChart: "折线图",
|
|
19
|
+
cacheLog: "日志",
|
|
20
|
+
cacheInput: "输入",
|
|
21
|
+
cacheOutput: "输出",
|
|
22
|
+
cacheCached: "缓存",
|
|
23
|
+
cacheHit: "命中",
|
|
24
|
+
summariesTitle: "摘要块",
|
|
25
|
+
noData: "—",
|
|
26
|
+
command: {
|
|
27
|
+
title: "压缩上下文设置",
|
|
28
|
+
description: "打开插件设置",
|
|
29
|
+
group: "插件",
|
|
30
|
+
},
|
|
31
|
+
settings: {
|
|
32
|
+
title: "压缩上下文插件设置",
|
|
33
|
+
show: "显示面板",
|
|
34
|
+
limit: "上下文上限",
|
|
35
|
+
limitAuto: "模型原生",
|
|
36
|
+
limitCustom: "自定义上限…",
|
|
37
|
+
limitHint: "填的是上限;实际窗口取「设置值」和「模型原生窗口」中较小的那个。纯数字或带 k/m 后缀",
|
|
38
|
+
limitInvalid: "请输入有效的 token 数",
|
|
39
|
+
limitPlaceholder: "200k",
|
|
40
|
+
limitPreview: (value) => `= ${value} tokens`,
|
|
41
|
+
limitCapped: (requested, actual) => `${requested}(模型上限 ${actual})`,
|
|
42
|
+
threshold: "压缩阈值",
|
|
43
|
+
thresholdHint: "输入 60 ~ 95 之间的整数(百分比)",
|
|
44
|
+
thresholdInvalid: "阈值必须在 60 ~ 95 之间",
|
|
45
|
+
thresholdPreview: (value) => `= ${value}%`,
|
|
46
|
+
nudgeGrowth: "压缩提醒间隔",
|
|
47
|
+
nudgeGrowthHint: "上下文每增长这么多 token 提醒模型可主动压缩;0 关闭",
|
|
48
|
+
nudgeGrowthInvalid: "请输入 0,或 1k ~ 200k",
|
|
49
|
+
summaryBlockPercent: "单条摘要上限",
|
|
50
|
+
summaryBlockPercentHint: "单条摘要最多占窗口的百分比;可输入 10% 或 20k",
|
|
51
|
+
summaryTotalPercent: "全部摘要上限",
|
|
52
|
+
summaryTotalPercentHint: "所有摘要加起来最多占窗口的百分比;可输入 50% 或 100k",
|
|
53
|
+
summaryPercentInvalid: "请输入 1% ~ 90%,或一个能换算成百分比的 token 数",
|
|
54
|
+
windowKnown: (value) => `当前窗口:${value}`,
|
|
55
|
+
windowUnknown: "当前窗口未知(先跑一次模型请求)",
|
|
56
|
+
summaryLanguage: "摘要语言",
|
|
57
|
+
summaryFormat: "摘要格式",
|
|
58
|
+
summaryFormatJson: "JSON(结构化)",
|
|
59
|
+
summaryFormatMarkdown: "Markdown(自然语言)",
|
|
60
|
+
summaryFormatBabel: "Babel(模型间高密度)",
|
|
61
|
+
autoCompress: "自动压缩",
|
|
62
|
+
enableCompressTool: "compress 工具",
|
|
63
|
+
enableDecompressTool: "decompress 工具",
|
|
64
|
+
showTimeline: "块头时间线",
|
|
65
|
+
showBlockTokens: "块头 token 估算",
|
|
66
|
+
showCacheChart: "显示缓存折线图",
|
|
67
|
+
showCacheLog: "显示缓存日志",
|
|
68
|
+
showSummaries: "显示摘要块",
|
|
69
|
+
categories: {
|
|
70
|
+
compress: "压缩",
|
|
71
|
+
summary: "摘要",
|
|
72
|
+
panel: "面板",
|
|
73
|
+
decompress: "解压",
|
|
74
|
+
interface: "界面",
|
|
75
|
+
},
|
|
76
|
+
decompressInlineMax: "解压内联上限",
|
|
77
|
+
decompressInlineMaxHint: "超过这个字符数就写成临时文件;输入纯数字或带 k/m 后缀",
|
|
78
|
+
decompressInlineMaxInvalid: "请输入 1k ~ 1m 之间的字符数",
|
|
79
|
+
decompressTempCap: "解压临时文件上限",
|
|
80
|
+
decompressTempCapHint: "最多保留多少个解压临时文件",
|
|
81
|
+
decompressTempCapInvalid: "请输入 1 ~ 1000 之间的整数",
|
|
82
|
+
decompressShowTokens: "解压返回 token 估算",
|
|
83
|
+
submit: "提交",
|
|
84
|
+
language: "语言",
|
|
85
|
+
auto: "自动",
|
|
86
|
+
on: "开",
|
|
87
|
+
off: "关",
|
|
88
|
+
},
|
|
89
|
+
languages: {
|
|
90
|
+
zh: "中文",
|
|
91
|
+
en: "English",
|
|
92
|
+
},
|
|
93
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,108 +1,108 @@
|
|
|
1
|
-
import { Plugin } from "@opencode/plugin"
|
|
2
|
-
|
|
3
|
-
import { maybeAutoCompress, maybeAutoCompressStep, maybeNudge } from "./compression/auto.ts"
|
|
4
|
-
import { recordCacheHistoryStep } from "./compression/cache-history.ts"
|
|
5
|
-
import { adoptNativeCheckpoint } from "./compression/adopt.ts"
|
|
6
|
-
import { handleCompaction } from "./compression/compaction.ts"
|
|
7
|
-
import { reconcileAll, startSessionEvents } from "./compression/events.ts"
|
|
8
|
-
import { registerSettingsRpc, type Disposable } from "./compression/settings-rpc.ts"
|
|
9
|
-
import { loadState } from "./compression/state.ts"
|
|
10
|
-
import { registerCompressTool } from "./compression/tool.ts"
|
|
11
|
-
import { registerDecompressTool } from "./compression/decompress-tool.ts"
|
|
12
|
-
import { createStats, mergeMetadata, shouldPublish, type ContextStats } from "./shared/stats.ts"
|
|
13
|
-
import { estimateCategories } from "./shared/tokens.ts"
|
|
14
|
-
|
|
15
|
-
export default Plugin.define({
|
|
16
|
-
id: "compressed-context",
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* 输入:OpenCode 注入的插件上下文 ctx。
|
|
20
|
-
* 输出:注册 compress 工具、设置 RPC、context / compaction 钩子与事件订阅。
|
|
21
|
-
* 预期:块链通过 compaction 落盘;失败不破坏历史。
|
|
22
|
-
*/
|
|
23
|
-
async setup(ctx) {
|
|
24
|
-
const published = new Map<string, ContextStats>()
|
|
25
|
-
const disposables: Disposable[] = []
|
|
26
|
-
|
|
27
|
-
/** 输入:sessionID;输出:无;预期:会话空闲/删除时清掉进程内统计缓存。 */
|
|
28
|
-
const forgetMemory = (sessionID: string): void => {
|
|
29
|
-
published.delete(sessionID)
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const publishStats = async (sessionID: string, stats: ContextStats): Promise<void> => {
|
|
33
|
-
const session = await ctx.session.get({ sessionID })
|
|
34
|
-
await ctx.session.update({
|
|
35
|
-
sessionID,
|
|
36
|
-
metadata: mergeMetadata(session.metadata, stats),
|
|
37
|
-
})
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
disposables.push(await registerCompressTool(ctx))
|
|
41
|
-
disposables.push(await registerDecompressTool(ctx))
|
|
42
|
-
disposables.push(await registerSettingsRpc(ctx))
|
|
43
|
-
const stopEvents = startSessionEvents(ctx, {
|
|
44
|
-
onSessionIdle: forgetMemory,
|
|
45
|
-
onSessionDeleted: forgetMemory,
|
|
46
|
-
onStepEnded: ({ sessionID, messageID, tokens }) =>
|
|
47
|
-
void (async () => {
|
|
48
|
-
await recordCacheHistoryStep(ctx, sessionID, { messageID, tokens })
|
|
49
|
-
await maybeAutoCompressStep({ ctx, sessionID, tokens })
|
|
50
|
-
})(),
|
|
51
|
-
})
|
|
52
|
-
void reconcileAll(ctx)
|
|
53
|
-
|
|
54
|
-
disposables.push(
|
|
55
|
-
await ctx.session.hook("context", async (event) => {
|
|
56
|
-
await adoptNativeCheckpoint(ctx, event.sessionID, event.messages)
|
|
57
|
-
|
|
58
|
-
await maybeNudge({
|
|
59
|
-
ctx,
|
|
60
|
-
sessionID: event.sessionID,
|
|
61
|
-
messages: event.messages,
|
|
62
|
-
system: event.system,
|
|
63
|
-
tools: event.tools,
|
|
64
|
-
model: event.model,
|
|
65
|
-
})
|
|
66
|
-
|
|
67
|
-
const stats = createStats(
|
|
68
|
-
estimateCategories({
|
|
69
|
-
system: event.system,
|
|
70
|
-
tools: event.tools,
|
|
71
|
-
messages: event.messages,
|
|
72
|
-
}),
|
|
73
|
-
Date.now(),
|
|
74
|
-
)
|
|
75
|
-
if (shouldPublish(published.get(event.sessionID), stats)) {
|
|
76
|
-
published.set(event.sessionID, stats)
|
|
77
|
-
void publishStats(event.sessionID, stats).catch(() => undefined)
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
await maybeAutoCompress({
|
|
81
|
-
ctx,
|
|
82
|
-
sessionID: event.sessionID,
|
|
83
|
-
messages: event.messages,
|
|
84
|
-
system: event.system,
|
|
85
|
-
tools: event.tools,
|
|
86
|
-
model: event.model,
|
|
87
|
-
})
|
|
88
|
-
}),
|
|
89
|
-
)
|
|
90
|
-
|
|
91
|
-
disposables.push(
|
|
92
|
-
await ctx.session.hook("compaction", (event) => handleCompaction(ctx, event)),
|
|
93
|
-
)
|
|
94
|
-
|
|
95
|
-
// 终止后拒绝一切新输入:把真实原因直接抛给宿主,TUI 会显示这条错误。
|
|
96
|
-
disposables.push(
|
|
97
|
-
await ctx.session.hook("prompt", async (event) => {
|
|
98
|
-
const state = await loadState(ctx.storage, event.sessionID)
|
|
99
|
-
if (state.terminal !== undefined) throw new Error(state.terminal)
|
|
100
|
-
}),
|
|
101
|
-
)
|
|
102
|
-
|
|
103
|
-
return () => {
|
|
104
|
-
stopEvents()
|
|
105
|
-
for (const disposable of disposables) void disposable.dispose()
|
|
106
|
-
}
|
|
107
|
-
},
|
|
108
|
-
})
|
|
1
|
+
import { Plugin } from "@opencode/plugin"
|
|
2
|
+
|
|
3
|
+
import { maybeAutoCompress, maybeAutoCompressStep, maybeNudge } from "./compression/auto.ts"
|
|
4
|
+
import { recordCacheHistoryStep } from "./compression/cache-history.ts"
|
|
5
|
+
import { adoptNativeCheckpoint } from "./compression/adopt.ts"
|
|
6
|
+
import { handleCompaction } from "./compression/compaction.ts"
|
|
7
|
+
import { reconcileAll, startSessionEvents } from "./compression/events.ts"
|
|
8
|
+
import { registerSettingsRpc, type Disposable } from "./compression/settings-rpc.ts"
|
|
9
|
+
import { loadState } from "./compression/state.ts"
|
|
10
|
+
import { registerCompressTool } from "./compression/tool.ts"
|
|
11
|
+
import { registerDecompressTool } from "./compression/decompress-tool.ts"
|
|
12
|
+
import { createStats, mergeMetadata, shouldPublish, type ContextStats } from "./shared/stats.ts"
|
|
13
|
+
import { estimateCategories } from "./shared/tokens.ts"
|
|
14
|
+
|
|
15
|
+
export default Plugin.define({
|
|
16
|
+
id: "compressed-context",
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* 输入:OpenCode 注入的插件上下文 ctx。
|
|
20
|
+
* 输出:注册 compress 工具、设置 RPC、context / compaction 钩子与事件订阅。
|
|
21
|
+
* 预期:块链通过 compaction 落盘;失败不破坏历史。
|
|
22
|
+
*/
|
|
23
|
+
async setup(ctx) {
|
|
24
|
+
const published = new Map<string, ContextStats>()
|
|
25
|
+
const disposables: Disposable[] = []
|
|
26
|
+
|
|
27
|
+
/** 输入:sessionID;输出:无;预期:会话空闲/删除时清掉进程内统计缓存。 */
|
|
28
|
+
const forgetMemory = (sessionID: string): void => {
|
|
29
|
+
published.delete(sessionID)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const publishStats = async (sessionID: string, stats: ContextStats): Promise<void> => {
|
|
33
|
+
const session = await ctx.session.get({ sessionID })
|
|
34
|
+
await ctx.session.update({
|
|
35
|
+
sessionID,
|
|
36
|
+
metadata: mergeMetadata(session.metadata, stats),
|
|
37
|
+
})
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
disposables.push(await registerCompressTool(ctx))
|
|
41
|
+
disposables.push(await registerDecompressTool(ctx))
|
|
42
|
+
disposables.push(await registerSettingsRpc(ctx))
|
|
43
|
+
const stopEvents = startSessionEvents(ctx, {
|
|
44
|
+
onSessionIdle: forgetMemory,
|
|
45
|
+
onSessionDeleted: forgetMemory,
|
|
46
|
+
onStepEnded: ({ sessionID, messageID, tokens }) =>
|
|
47
|
+
void (async () => {
|
|
48
|
+
await recordCacheHistoryStep(ctx, sessionID, { messageID, tokens })
|
|
49
|
+
await maybeAutoCompressStep({ ctx, sessionID, tokens })
|
|
50
|
+
})(),
|
|
51
|
+
})
|
|
52
|
+
void reconcileAll(ctx)
|
|
53
|
+
|
|
54
|
+
disposables.push(
|
|
55
|
+
await ctx.session.hook("context", async (event) => {
|
|
56
|
+
await adoptNativeCheckpoint(ctx, event.sessionID, event.messages)
|
|
57
|
+
|
|
58
|
+
await maybeNudge({
|
|
59
|
+
ctx,
|
|
60
|
+
sessionID: event.sessionID,
|
|
61
|
+
messages: event.messages,
|
|
62
|
+
system: event.system,
|
|
63
|
+
tools: event.tools,
|
|
64
|
+
model: event.model,
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
const stats = createStats(
|
|
68
|
+
estimateCategories({
|
|
69
|
+
system: event.system,
|
|
70
|
+
tools: event.tools,
|
|
71
|
+
messages: event.messages,
|
|
72
|
+
}),
|
|
73
|
+
Date.now(),
|
|
74
|
+
)
|
|
75
|
+
if (shouldPublish(published.get(event.sessionID), stats)) {
|
|
76
|
+
published.set(event.sessionID, stats)
|
|
77
|
+
void publishStats(event.sessionID, stats).catch(() => undefined)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
await maybeAutoCompress({
|
|
81
|
+
ctx,
|
|
82
|
+
sessionID: event.sessionID,
|
|
83
|
+
messages: event.messages,
|
|
84
|
+
system: event.system,
|
|
85
|
+
tools: event.tools,
|
|
86
|
+
model: event.model,
|
|
87
|
+
})
|
|
88
|
+
}),
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
disposables.push(
|
|
92
|
+
await ctx.session.hook("compaction", (event) => handleCompaction(ctx, event)),
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
// 终止后拒绝一切新输入:把真实原因直接抛给宿主,TUI 会显示这条错误。
|
|
96
|
+
disposables.push(
|
|
97
|
+
await ctx.session.hook("prompt", async (event) => {
|
|
98
|
+
const state = await loadState(ctx.storage, event.sessionID)
|
|
99
|
+
if (state.terminal !== undefined) throw new Error(state.terminal)
|
|
100
|
+
}),
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
return () => {
|
|
104
|
+
stopEvents()
|
|
105
|
+
for (const disposable of disposables) void disposable.dispose()
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
})
|
package/src/shared/blocks.ts
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 摘要块的跨进程 DTO。
|
|
3
|
-
*
|
|
4
|
-
* 服务端把 active 链渲染成 body,TUI 只负责展示。
|
|
5
|
-
*/
|
|
6
|
-
export interface SummaryBlock {
|
|
7
|
-
readonly id: string
|
|
8
|
-
readonly tier: 1 | 2 | 3
|
|
9
|
-
/** 摘要格式;Babel 正文不能按 Markdown 渲染。 */
|
|
10
|
-
readonly format: "json" | "markdown" | "babel"
|
|
11
|
-
readonly title: string
|
|
12
|
-
readonly at: number
|
|
13
|
-
readonly tokensBefore: number
|
|
14
|
-
readonly tokensAfter: number
|
|
15
|
-
readonly sourceBlockIds?: readonly string[]
|
|
16
|
-
readonly body: string
|
|
17
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* 摘要块的跨进程 DTO。
|
|
3
|
+
*
|
|
4
|
+
* 服务端把 active 链渲染成 body,TUI 只负责展示。
|
|
5
|
+
*/
|
|
6
|
+
export interface SummaryBlock {
|
|
7
|
+
readonly id: string
|
|
8
|
+
readonly tier: 1 | 2 | 3
|
|
9
|
+
/** 摘要格式;Babel 正文不能按 Markdown 渲染。 */
|
|
10
|
+
readonly format: "json" | "markdown" | "babel"
|
|
11
|
+
readonly title: string
|
|
12
|
+
readonly at: number
|
|
13
|
+
readonly tokensBefore: number
|
|
14
|
+
readonly tokensAfter: number
|
|
15
|
+
readonly sourceBlockIds?: readonly string[]
|
|
16
|
+
readonly body: string
|
|
17
|
+
}
|