newmark-agent 0.3.5 → 0.3.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.
@@ -1,43 +1,43 @@
1
- {
2
- "name": "Electron-Debug-Release",
3
- "description": "TypeScript Electron project debug pipeline: typecheck → build → lint → IPC consistency → UI sanity → release",
4
- "components": [
5
- {
6
- "id": 0,
7
- "type": "dialog",
8
- "mode": "build",
9
- "prompt": "Debug Step 1: TypeScript Compilation Check\nRun `npx tsc --noEmit` in the DESKTOP/ directory.\n- If it fails, collect ALL errors, categorize by file, and fix each one.\n- Ensure strict mode passes (noImplicitAny, strictNullChecks, etc)."
10
- },
11
- {
12
- "id": 1,
13
- "type": "dialog",
14
- "mode": "build",
15
- "prompt": "Debug Step 2: Build + Lint\n1. Run `npm run build` and verify it succeeds.\n2. Run `npm run lint` and fix any warnings/errors.\n3. Ensure `dist/main.js`, `dist/preload.js`, `dist/ui/index.html` all exist in dist/"
16
- },
17
- {
18
- "id": 2,
19
- "type": "dialog",
20
- "mode": "build",
21
- "prompt": "Debug Step 3: IPC Handler Consistency Check\nRead `src/preload.ts` and `src/main.ts`. Verify that:\n- Every `ipcRenderer.invoke('agent:xxx', ...)` in preload.ts has a matching `ipcMain.handle('agent:xxx', ...)` in main.ts\n- The async function signatures match (number of parameters)\n- Every `ipcMain.handle` is used (no orphaned handlers)\n- Report any mismatches and fix them."
22
- },
23
- {
24
- "id": 3,
25
- "type": "dialog",
26
- "mode": "build",
27
- "prompt": "Debug Step 4: index.html Sanity Check\nRead `src/ui/index.html` and check:\n- All `onclick=\"window.xxx(...)\"` references have corresponding `window.xxx = function(...)` definitions\n- No duplicate function declarations\n- No syntax errors (orphaned braces, missing catch/finally)\n- All `api.xxx()` calls match preload.ts exposed methods\n- Report any issues and fix them."
28
- },
29
- {
30
- "id": 4,
31
- "type": "logic",
32
- "prompt": "Are all Debug Steps 0-4 clean? No errors, no warnings, no mismatches.",
33
- "goto_true": 5,
34
- "goto_false": 0
35
- },
36
- {
37
- "id": 5,
38
- "type": "dialog",
39
- "mode": "build",
40
- "prompt": "Release Step: Build portable distribution\nRun `npx tsc --noEmit` to confirm clean, then `npm run build`. Then run:\n```\nnpx electron-builder --win --config electron-builder.config.ts --x64 2>&1\n```\nCollect the output artifact path. Verify the .exe file exists and its size is reasonable (>50MB)."
41
- }
42
- ]
43
- }
1
+ {
2
+ "name": "Electron-Debug-Release",
3
+ "description": "TypeScript Electron project debug pipeline: typecheck → build → lint → IPC consistency → UI sanity → release",
4
+ "components": [
5
+ {
6
+ "id": 0,
7
+ "type": "dialog",
8
+ "mode": "build",
9
+ "prompt": "Debug Step 1: TypeScript Compilation Check\nRun `npx tsc --noEmit` in the DESKTOP/ directory.\n- If it fails, collect ALL errors, categorize by file, and fix each one.\n- Ensure strict mode passes (noImplicitAny, strictNullChecks, etc)."
10
+ },
11
+ {
12
+ "id": 1,
13
+ "type": "dialog",
14
+ "mode": "build",
15
+ "prompt": "Debug Step 2: Build + Lint\n1. Run `npm run build` and verify it succeeds.\n2. Run `npm run lint` and fix any warnings/errors.\n3. Ensure `dist/main.js`, `dist/preload.js`, `dist/ui/index.html` all exist in dist/"
16
+ },
17
+ {
18
+ "id": 2,
19
+ "type": "dialog",
20
+ "mode": "build",
21
+ "prompt": "Debug Step 3: IPC Handler Consistency Check\nRead `src/preload.ts` and `src/main.ts`. Verify that:\n- Every `ipcRenderer.invoke('agent:xxx', ...)` in preload.ts has a matching `ipcMain.handle('agent:xxx', ...)` in main.ts\n- The async function signatures match (number of parameters)\n- Every `ipcMain.handle` is used (no orphaned handlers)\n- Report any mismatches and fix them."
22
+ },
23
+ {
24
+ "id": 3,
25
+ "type": "dialog",
26
+ "mode": "build",
27
+ "prompt": "Debug Step 4: index.html Sanity Check\nRead `src/ui/index.html` and check:\n- All `onclick=\"window.xxx(...)\"` references have corresponding `window.xxx = function(...)` definitions\n- No duplicate function declarations\n- No syntax errors (orphaned braces, missing catch/finally)\n- All `api.xxx()` calls match preload.ts exposed methods\n- Report any issues and fix them."
28
+ },
29
+ {
30
+ "id": 4,
31
+ "type": "logic",
32
+ "prompt": "Are all Debug Steps 0-4 clean? No errors, no warnings, no mismatches.",
33
+ "goto_true": 5,
34
+ "goto_false": 0
35
+ },
36
+ {
37
+ "id": 5,
38
+ "type": "dialog",
39
+ "mode": "build",
40
+ "prompt": "Release Step: Build portable distribution\nRun `npx tsc --noEmit` to confirm clean, then `npm run build`. Then run:\n```\nnpx electron-builder --win --config electron-builder.config.ts --x64 2>&1\n```\nCollect the output artifact path. Verify the .exe file exists and its size is reasonable (>50MB)."
41
+ }
42
+ ]
43
+ }
package/Flow/Flow.md CHANGED
@@ -1,9 +1,9 @@
1
- # Newmark Flow Format Guide
2
-
3
- A Flow workflow is saved as name.Flow.json in the Flow/ folder.
4
-
5
- ## Component Types
6
- ### dialog - id, type:"dialog", mode:"build"/"plan"/"goal", prompt (use {#prompt#} placeholder)
7
- ### logic - id, type:"logic", prompt, goto_true, goto_false
8
-
1
+ # Newmark Flow Format Guide
2
+
3
+ A Flow workflow is saved as name.Flow.json in the Flow/ folder.
4
+
5
+ ## Component Types
6
+ ### dialog - id, type:"dialog", mode:"build"/"plan"/"goal", prompt (use {#prompt#} placeholder)
7
+ ### logic - id, type:"logic", prompt, goto_true, goto_false
8
+
9
9
  Components execute in order unless logic redirects.
@@ -1,96 +1,96 @@
1
- {
2
- "name": "UI-Feature-Integration",
3
- "description": "Complete all Design.txt UI features on top of working IPC+chat foundation",
4
- "components": [
5
- {
6
- "id": 0,
7
- "type": "dialog",
8
- "mode": "build",
9
- "prompt": "当前状态:Electron IPC、preload、agent初始化、基本聊天输入/发送均已正常工作。精简版UI已运行,下一步需要将完整UI功能逐步集成回来。请读取 DESKTOP/src/ui/index.html 和 Design.txt 了解现状和目标。第一步:恢复原始玻璃拟态设计系统。将原始 index.html 中的CSS设计系统(玻璃拟态三层深度、贝塞尔圆角、GPU加速、SF字体栈、动态彩条跑马灯动画)合并到当前精简版UI中,同时保持所有功能(IPC通信、事件绑定方式)正常工作。注意:所有 onclick 必须使用 window.xxx 绑定,const 不创建window属性。完成后运行 npm run build 并启动测试。"
10
- },
11
- {
12
- "id": 1,
13
- "type": "dialog",
14
- "mode": "build",
15
- "prompt": "第二步:恢复可调节面板系统。实现左侧栏(#left)、右侧栏(#right)、底部栏(#bottom)的可伸缩面板,带拖拽手柄(mousedown/mousemove/mouseup),最小宽度/高度约束,折叠/展开切换按钮。左侧栏折叠时只显示图标,右下栏不显示时隐藏。阅读 Design.txt §12 了解右侧栏标签页(文件树、编辑器、MD阅读器、子代理、浏览器)和底部终端。同时保留当前所有功能正常。"
16
- },
17
- {
18
- "id": 2,
19
- "type": "dialog",
20
- "mode": "build",
21
- "prompt": "第三步:恢复顶部自定义标题栏。实现无OS窗口边框的标题栏(#topbar),左侧显示Newmark标题(agent运行时字体动态彩色闪动),右侧最小化/最大化/关闭按钮。窗口拖拽通过 -webkit-app-region:drag 实现。阅读 Design.txt §10。注意:最大化/最小化/关闭按钮的 onclick 使用 api.minimize/maximize/close。完成后集成左侧栏的插件/自动化/工作流/设置图标按钮,点击打开独立子窗口(.sub-win),子窗口可拖动、可关闭,点击外部关闭弹出列表。阅读 Design.txt §11。"
22
- },
23
- {
24
- "id": 3,
25
- "type": "dialog",
26
- "mode": "build",
27
- "prompt": "第四步:恢复完整聊天区功能。包括:(1) 消息气泡样式(用户蓝色右对齐、助手灰色左对齐),(2) 消息附带mode/model标签(hover显示),(3) 正在运行时的灰白/灰黑脉冲动画,(4) Shell输出块(默认折叠,点击展开),(5) 文件变更差异块(绿增红减,默认折叠,点击展开),(6) 选项反馈显示。阅读 Design.txt §13。同时实现 Guide/Next 输入模式切换(输入框左下角),Ctrl+Enter切换相反模式。"
28
- },
29
- {
30
- "id": 4,
31
- "type": "dialog",
32
- "mode": "build",
33
- "prompt": "第五步:实现 Goal 模式UI。在输入框上方添加 Goal 条(仅Goal模式显示):左顶格显示目标文本,右顶格编辑+暂停/继续按钮,上边两角贝塞尔圆角。参考 Design.txt §14。实现目标清单(Todo List):可折叠/展开,最多8行滚动,完成项变淡+删除线,用户/agent可切换完成状态。实现回到底部向下按钮(当聊天未在最底部时显示)。全存在时顺序:回到底部、清单、Goal、输入框。"
34
- },
35
- {
36
- "id": 5,
37
- "type": "dialog",
38
- "mode": "build",
39
- "prompt": "第六步:实现设置窗口。独立子窗口,居中显示,非可调大小可拖动。三标签页:(1) 通用 - 暗色模式(深色/浅色/跟随系统)、毛玻璃模糊程度、对话风格、反馈等级、默认输入模式、关闭行为等;(2) 模型与供应商 - 添加供应商(名称+API端点+API密钥)、添加模型(上下文大小、视觉/思考开关、描述)、三维评估(开销/性能/速度)、模型自动切换开关与倾向、模糊注入按钮;(3) 归档管理 - 列出归档、加载归档、删除归档、归档当前会话。所有设置绑定 config.json。阅读 Design.txt §16。"
40
- },
41
- {
42
- "id": 6,
43
- "type": "dialog",
44
- "mode": "build",
45
- "prompt": "第七步:实现文件树管理器。右侧栏默认显示文件树,列出当前工作区文件。点击文件夹展开/折叠,点击文件:.md文件在MD阅读器打开,.txt/.json/.tex等在编辑器打开。文件树支持面包屑导航。阅读 Design.txt §12。实现 MD阅读器(渲染markdown为HTML)、编辑器(显示文件内容,简单文本编辑功能)、内置浏览器(输入URL导航,前进/后退历史)。均在右侧栏标签页切换。"
46
- },
47
- {
48
- "id": 7,
49
- "type": "dialog",
50
- "mode": "build",
51
- "prompt": "第八步:实现终端面板。底部栏显示终端,可选择 PowerShell/Bash/CMD。输入命令执行,显示输出。通过 api.executeBash() IPC 调用。Shell 输出块默认折叠,点击展开。阅读 Design.txt §12。"
52
- },
53
- {
54
- "id": 8,
55
- "type": "dialog",
56
- "mode": "build",
57
- "prompt": "第九步:实现动态跑马灯/彩条边框系统。搜索学习Apple AI风格的动态渐变边框效果。所有活动元素(工作中对话、提交按钮、设置中校验按钮、工作区缩略图)在活跃状态时显示动态彩色跑马灯边框。颜色在设置中通过调色盘可视化调节(设置颜色数量,再设置每个颜色)。阅读 Design.txt §15。参考CSS动画方案:用伪元素+conic-gradient+mask实现动态旋转边框。"
58
- },
59
- {
60
- "id": 9,
61
- "type": "dialog",
62
- "mode": "build",
63
- "prompt": "第十步:实现二级左侧边栏。单击工作区缩略图时展开二级左侧边栏:顶部显示工作区设置按钮和新对话按钮,下部显示对话列表(每行显示对话大纲摘要,右侧归档按钮)。运行中的对话边框动态跑马灯。阅读 Design.txt §11。"
64
- },
65
- {
66
- "id": 10,
67
- "type": "dialog",
68
- "mode": "build",
69
- "prompt": "第十一步:实现 Subagent 面板。右侧栏 subagent 标签页显示活跃子代理列表,点击查看对话历史(只读)。agent 可通过 task 工具创建 subagent,通过 get.subagent() 获取结果。阅读 Design.txt §26。"
70
- },
71
- {
72
- "id": 11,
73
- "type": "dialog",
74
- "mode": "build",
75
- "prompt": "第十二步:实现自动化窗口。独立子窗口,固定大小居中。3-4行输入框,下方模型选择器和条件选择器(单次/循环间隔/起止时间)。agent 和用户都可创建自动化任务。阅读 Design.txt §24。"
76
- },
77
- {
78
- "id": 12,
79
- "type": "dialog",
80
- "mode": "build",
81
- "prompt": "第十三步:实现工作流编辑器。左侧栏工作流按钮打开独立窗口。目录树显示 Flow/ 目录下的所有 .Flow.json 文件(去除后缀)。展示组件树:展开显示编码+类型(0 Build, 1 Logic等),再次展开可编辑(对话组件:mode+prompt;逻辑组件:prompt+goto1+goto2)。所有输入框贝塞尔圆角。新建工作流按钮始终在第一位。阅读 Design.txt §29。"
82
- },
83
- {
84
- "id": 13,
85
- "type": "dialog",
86
- "mode": "build",
87
- "prompt": "第十四步:实现归档功能。学习现有实现(Hermes/Codex/OpenCode),实现对话归档到工作区存储,可恢复。实现上下文压缩:接近token限制时调用压缩模型总结对话保留关键信息。阅读 Design.txt §30。"
88
- },
89
- {
90
- "id": 14,
91
- "type": "dialog",
92
- "mode": "build",
93
- "prompt": "第十五步:最终整合与完整测试。确保所有onclick使用 window.xxx 绑定,所有功能在IPC和HTTP fallback模式下均可工作,暗色/亮色模式切换正常,各面板独立折叠/展开/缩放,所有设置读写 config.json,Goal 模式无限制循环,Flow 工作流正确执行,归档/恢复完整。运行 npm run build && npm run start:cli 测试CLI,再启动 Electron 测试UI。对照 Design.txt 逐一验证。"
94
- }
95
- ]
96
- }
1
+ {
2
+ "name": "UI-Feature-Integration",
3
+ "description": "Complete all Design.txt UI features on top of working IPC+chat foundation",
4
+ "components": [
5
+ {
6
+ "id": 0,
7
+ "type": "dialog",
8
+ "mode": "build",
9
+ "prompt": "当前状态:Electron IPC、preload、agent初始化、基本聊天输入/发送均已正常工作。精简版UI已运行,下一步需要将完整UI功能逐步集成回来。请读取 DESKTOP/src/ui/index.html 和 Design.txt 了解现状和目标。第一步:恢复原始玻璃拟态设计系统。将原始 index.html 中的CSS设计系统(玻璃拟态三层深度、贝塞尔圆角、GPU加速、SF字体栈、动态彩条跑马灯动画)合并到当前精简版UI中,同时保持所有功能(IPC通信、事件绑定方式)正常工作。注意:所有 onclick 必须使用 window.xxx 绑定,const 不创建window属性。完成后运行 npm run build 并启动测试。"
10
+ },
11
+ {
12
+ "id": 1,
13
+ "type": "dialog",
14
+ "mode": "build",
15
+ "prompt": "第二步:恢复可调节面板系统。实现左侧栏(#left)、右侧栏(#right)、底部栏(#bottom)的可伸缩面板,带拖拽手柄(mousedown/mousemove/mouseup),最小宽度/高度约束,折叠/展开切换按钮。左侧栏折叠时只显示图标,右下栏不显示时隐藏。阅读 Design.txt §12 了解右侧栏标签页(文件树、编辑器、MD阅读器、子代理、浏览器)和底部终端。同时保留当前所有功能正常。"
16
+ },
17
+ {
18
+ "id": 2,
19
+ "type": "dialog",
20
+ "mode": "build",
21
+ "prompt": "第三步:恢复顶部自定义标题栏。实现无OS窗口边框的标题栏(#topbar),左侧显示Newmark标题(agent运行时字体动态彩色闪动),右侧最小化/最大化/关闭按钮。窗口拖拽通过 -webkit-app-region:drag 实现。阅读 Design.txt §10。注意:最大化/最小化/关闭按钮的 onclick 使用 api.minimize/maximize/close。完成后集成左侧栏的插件/自动化/工作流/设置图标按钮,点击打开独立子窗口(.sub-win),子窗口可拖动、可关闭,点击外部关闭弹出列表。阅读 Design.txt §11。"
22
+ },
23
+ {
24
+ "id": 3,
25
+ "type": "dialog",
26
+ "mode": "build",
27
+ "prompt": "第四步:恢复完整聊天区功能。包括:(1) 消息气泡样式(用户蓝色右对齐、助手灰色左对齐),(2) 消息附带mode/model标签(hover显示),(3) 正在运行时的灰白/灰黑脉冲动画,(4) Shell输出块(默认折叠,点击展开),(5) 文件变更差异块(绿增红减,默认折叠,点击展开),(6) 选项反馈显示。阅读 Design.txt §13。同时实现 Guide/Next 输入模式切换(输入框左下角),Ctrl+Enter切换相反模式。"
28
+ },
29
+ {
30
+ "id": 4,
31
+ "type": "dialog",
32
+ "mode": "build",
33
+ "prompt": "第五步:实现 Goal 模式UI。在输入框上方添加 Goal 条(仅Goal模式显示):左顶格显示目标文本,右顶格编辑+暂停/继续按钮,上边两角贝塞尔圆角。参考 Design.txt §14。实现目标清单(Todo List):可折叠/展开,最多8行滚动,完成项变淡+删除线,用户/agent可切换完成状态。实现回到底部向下按钮(当聊天未在最底部时显示)。全存在时顺序:回到底部、清单、Goal、输入框。"
34
+ },
35
+ {
36
+ "id": 5,
37
+ "type": "dialog",
38
+ "mode": "build",
39
+ "prompt": "第六步:实现设置窗口。独立子窗口,居中显示,非可调大小可拖动。三标签页:(1) 通用 - 暗色模式(深色/浅色/跟随系统)、毛玻璃模糊程度、对话风格、反馈等级、默认输入模式、关闭行为等;(2) 模型与供应商 - 添加供应商(名称+API端点+API密钥)、添加模型(上下文大小、视觉/思考开关、描述)、三维评估(开销/性能/速度)、模型自动切换开关与倾向、模糊注入按钮;(3) 归档管理 - 列出归档、加载归档、删除归档、归档当前会话。所有设置绑定 config.json。阅读 Design.txt §16。"
40
+ },
41
+ {
42
+ "id": 6,
43
+ "type": "dialog",
44
+ "mode": "build",
45
+ "prompt": "第七步:实现文件树管理器。右侧栏默认显示文件树,列出当前工作区文件。点击文件夹展开/折叠,点击文件:.md文件在MD阅读器打开,.txt/.json/.tex等在编辑器打开。文件树支持面包屑导航。阅读 Design.txt §12。实现 MD阅读器(渲染markdown为HTML)、编辑器(显示文件内容,简单文本编辑功能)、内置浏览器(输入URL导航,前进/后退历史)。均在右侧栏标签页切换。"
46
+ },
47
+ {
48
+ "id": 7,
49
+ "type": "dialog",
50
+ "mode": "build",
51
+ "prompt": "第八步:实现终端面板。底部栏显示终端,可选择 PowerShell/Bash/CMD。输入命令执行,显示输出。通过 api.executeBash() IPC 调用。Shell 输出块默认折叠,点击展开。阅读 Design.txt §12。"
52
+ },
53
+ {
54
+ "id": 8,
55
+ "type": "dialog",
56
+ "mode": "build",
57
+ "prompt": "第九步:实现动态跑马灯/彩条边框系统。搜索学习Apple AI风格的动态渐变边框效果。所有活动元素(工作中对话、提交按钮、设置中校验按钮、工作区缩略图)在活跃状态时显示动态彩色跑马灯边框。颜色在设置中通过调色盘可视化调节(设置颜色数量,再设置每个颜色)。阅读 Design.txt §15。参考CSS动画方案:用伪元素+conic-gradient+mask实现动态旋转边框。"
58
+ },
59
+ {
60
+ "id": 9,
61
+ "type": "dialog",
62
+ "mode": "build",
63
+ "prompt": "第十步:实现二级左侧边栏。单击工作区缩略图时展开二级左侧边栏:顶部显示工作区设置按钮和新对话按钮,下部显示对话列表(每行显示对话大纲摘要,右侧归档按钮)。运行中的对话边框动态跑马灯。阅读 Design.txt §11。"
64
+ },
65
+ {
66
+ "id": 10,
67
+ "type": "dialog",
68
+ "mode": "build",
69
+ "prompt": "第十一步:实现 Subagent 面板。右侧栏 subagent 标签页显示活跃子代理列表,点击查看对话历史(只读)。agent 可通过 task 工具创建 subagent,通过 get.subagent() 获取结果。阅读 Design.txt §26。"
70
+ },
71
+ {
72
+ "id": 11,
73
+ "type": "dialog",
74
+ "mode": "build",
75
+ "prompt": "第十二步:实现自动化窗口。独立子窗口,固定大小居中。3-4行输入框,下方模型选择器和条件选择器(单次/循环间隔/起止时间)。agent 和用户都可创建自动化任务。阅读 Design.txt §24。"
76
+ },
77
+ {
78
+ "id": 12,
79
+ "type": "dialog",
80
+ "mode": "build",
81
+ "prompt": "第十三步:实现工作流编辑器。左侧栏工作流按钮打开独立窗口。目录树显示 Flow/ 目录下的所有 .Flow.json 文件(去除后缀)。展示组件树:展开显示编码+类型(0 Build, 1 Logic等),再次展开可编辑(对话组件:mode+prompt;逻辑组件:prompt+goto1+goto2)。所有输入框贝塞尔圆角。新建工作流按钮始终在第一位。阅读 Design.txt §29。"
82
+ },
83
+ {
84
+ "id": 13,
85
+ "type": "dialog",
86
+ "mode": "build",
87
+ "prompt": "第十四步:实现归档功能。学习现有实现(Hermes/Codex/OpenCode),实现对话归档到工作区存储,可恢复。实现上下文压缩:接近token限制时调用压缩模型总结对话保留关键信息。阅读 Design.txt §30。"
88
+ },
89
+ {
90
+ "id": 14,
91
+ "type": "dialog",
92
+ "mode": "build",
93
+ "prompt": "第十五步:最终整合与完整测试。确保所有onclick使用 window.xxx 绑定,所有功能在IPC和HTTP fallback模式下均可工作,暗色/亮色模式切换正常,各面板独立折叠/展开/缩放,所有设置读写 config.json,Goal 模式无限制循环,Flow 工作流正确执行,归档/恢复完整。运行 npm run build && npm run start:cli 测试CLI,再启动 Electron 测试UI。对照 Design.txt 逐一验证。"
94
+ }
95
+ ]
96
+ }
@@ -327011,6 +327011,8 @@ var NATIVE_TOOL_CATALOG = [
327011
327011
  { name: "subagent_close", label: "Subagent close", description: "Close a same-conversation peer agent.", category: "agent", defaultEnabled: true, protected: true, availability: "mode-scoped" },
327012
327012
  { name: "linked_plan", label: "Linked plan", description: "Read or conservatively update the conversation-linked Markdown plan.", category: "agent", defaultEnabled: true, protected: true, availability: "mode-scoped" },
327013
327013
  { name: "build_history_query", label: "Build history query", description: "Read concrete public work details for one historical Build Block.", category: "agent", defaultEnabled: true, protected: true, availability: "mode-scoped" },
327014
+ { name: "context_compress", label: "Context compress", description: "Actively compress the LLM context history, leaving the displayed conversation history unchanged.", category: "agent", defaultEnabled: true, protected: true, availability: "mode-scoped" },
327015
+ { name: "context_history_manage", label: "Context history manage", description: "List, remove, or summarize entries in the LLM context history without touching the displayed conversation history.", category: "agent", defaultEnabled: true, protected: true, availability: "mode-scoped" },
327014
327016
  { name: "question", label: "Ask question", description: "Ask the user for structured option feedback.", category: "agent", defaultEnabled: true, protected: true, availability: "mode-scoped" },
327015
327017
  { name: "skill_download", label: "Skill download", description: "Download and install a skill.", category: "agent", defaultEnabled: true },
327016
327018
  { name: "skill", label: "Skill", description: "Search enabled skill metadata or load one skill body on demand.", category: "agent", defaultEnabled: true, protected: true, availability: "mode-scoped" },
@@ -334501,6 +334503,8 @@ var MODE_SCOPED_TOOLS = /* @__PURE__ */ new Set([
334501
334503
  "pdf_read",
334502
334504
  "linked_plan",
334503
334505
  "build_history_query",
334506
+ "context_compress",
334507
+ "context_history_manage",
334504
334508
  "question",
334505
334509
  "task",
334506
334510
  "subagent_list",
@@ -335522,14 +335526,21 @@ var ToolExecutor = class {
335522
335526
  remote_root: { type: "string" },
335523
335527
  remote_path: { type: "string" }
335524
335528
  }, ["action"]),
335525
- t3("task", "Create a same-conversation peer agent and return immediately. The peer has a nature slug, short id, and canonical UUID-qualified name. Pass model to select an exact configured model deployment (deployment:providerId:modelId or an unambiguous provider/model name). When model is omitted, the peer inherits the parent Agent's currently resolved model deployment. Plan mode peers are forced to Plan.", { nature: { type: "string" }, name: { type: "string", description: "Legacy alias for nature." }, prompt: { type: "string" }, preset: { type: "string" }, agent: { type: "string" }, model: { type: "string", description: "Optional exact model deployment. Omit to inherit the parent Agent resolved model." }, mode: { type: "string" }, input_mode: { type: "string" }, flow: { type: "string" } }, ["prompt"]),
335526
- t3("subagent_list", "List flat same-conversation peer agents, optionally filtered by status.", { status: { type: "string", enum: ["idle", "queued", "working", "completed", "error", "closed"] } }, []),
335527
- t3("subagent_read", "Read one same-conversation peer status, queue/mailbox summary, latest bounded feedback, and result. Available for running, queued, completed, error, and closed peers.", { id: { type: "string" }, name: { type: "string" }, max_chars: { type: "number", description: "Bounded result size from 2000 to 32000 characters." } }, []),
335528
- t3("subagent_send", "Persist a mailbox message to a same-conversation peer agent.", { id: { type: "string" }, name: { type: "string" }, message: { type: "string" }, prompt: { type: "string", description: "Legacy alias for message." }, kind: { type: "string", enum: ["directive", "question", "result", "handoff"] }, reply_to: { type: "string" }, correlation_id: { type: "string" } }, []),
335529
- t3("subagent_result", "Return the persisted transcript, mailbox summary, status, and latest result for a peer agent.", { id: { type: "string" }, name: { type: "string" } }, []),
335530
- t3("subagent_close", "Close a same-conversation peer. Root can close any peer; a peer can close only itself.", { id: { type: "string" }, name: { type: "string" } }, []),
335529
+ t3("task", "Create a same-conversation peer agent and return immediately. The peer has a stable human-readable name, a short id, and a canonical UUID-qualified identity. The peer name is decoupled from its id: pass name for readable references and id for exact targeting. Pass model to select an exact configured model deployment (deployment:providerId:modelId or an unambiguous provider/model name). When model is omitted, the peer inherits the parent Agent's currently resolved model deployment. Plan mode peers are forced to Plan.", { nature: { type: "string" }, name: { type: "string", description: "Legacy alias for nature." }, prompt: { type: "string" }, preset: { type: "string" }, agent: { type: "string" }, model: { type: "string", description: "Optional exact model deployment. Omit to inherit the parent Agent resolved model." }, mode: { type: "string" }, input_mode: { type: "string" }, flow: { type: "string" } }, ["prompt"]),
335530
+ t3("subagent_list", "List flat same-conversation peer agents, optionally filtered by status. Each entry exposes both the stable name and the exact id; use the id for any subsequent targeting.", { status: { type: "string", enum: ["idle", "queued", "working", "completed", "error", "closed"] } }, []),
335531
+ t3("subagent_read", "Read one same-conversation peer status, queue/mailbox summary, latest bounded feedback, and result. Available for running, queued, completed, error, and closed peers. Pass the exact id returned by subagent_list, or a name for convenience lookup.", { id: { type: "string", description: "Exact peer id from subagent_list." }, name: { type: "string", description: "Convenience peer name; ambiguous names resolve to the first match." }, max_chars: { type: "number", description: "Bounded result size from 2000 to 32000 characters." } }, []),
335532
+ t3("subagent_send", "Persist a mailbox message to a same-conversation peer agent. Target by exact id (preferred) or name.", { id: { type: "string", description: "Exact peer id from subagent_list." }, name: { type: "string", description: "Convenience peer name." }, message: { type: "string" }, prompt: { type: "string", description: "Legacy alias for message." }, kind: { type: "string", enum: ["directive", "question", "result", "handoff"] }, reply_to: { type: "string" }, correlation_id: { type: "string" } }, []),
335533
+ t3("subagent_result", "Return the persisted transcript, mailbox summary, status, and latest result for a peer agent. Target by exact id (preferred) or name.", { id: { type: "string", description: "Exact peer id from subagent_list." }, name: { type: "string", description: "Convenience peer name." } }, []),
335534
+ t3("subagent_close", "Close a same-conversation peer. Root can close any peer; a peer can close only itself. Target by exact id (preferred) or name.", { id: { type: "string", description: "Exact peer id from subagent_list." }, name: { type: "string", description: "Convenience peer name." } }, []),
335531
335535
  t3("linked_plan", "Read or update the current conversation linked Markdown plan. Update requires the current expected_revision.", { action: { type: "string", enum: ["get", "update"] }, markdown: { type: "string" }, expected_revision: { type: "number" } }, ["action"]),
335532
335536
  t3("build_history_query", "Read the concrete public work details of one historical Build Block. The prompt already exposes user input, final summary, and completion status; call this read-only tool only when the user asks what specifically happened. Select by newest-to-oldest history_index, or by run_id returned from an earlier query.", { history_index: { type: "number", minimum: 1, description: "1-based historical Build Block index from the request ledger; 1 is the newest previous task." }, run_id: { type: "string", description: "Exact run id returned by an earlier build_history_query result." }, max_events: { type: "number", minimum: 1, maximum: 200, description: "Maximum trailing public work events; defaults to 80." } }, []),
335537
+ t3("context_compress", "Actively compress the LLM context history for this conversation. This collapses older history entries into a concise summary while preserving the recent tail, which reduces context tokens and cost. IMPORTANT: it affects only the LLM context (what the model sees); the displayed conversation history shown to the user is never altered. Call this when the conversation is long, token pressure is high, or you judge that older turns are no longer needed in full. Idempotent and safe: repeated calls produce incremental summaries.", { keep_recent: { type: "number", minimum: 2, maximum: 60, description: "Recent message count to keep uncompressed at the tail. Defaults to the configured keep_recent_messages." }, force: { type: "boolean", description: "Compress even if the context is not yet over the automatic threshold. Defaults to false." } }, []),
335538
+ t3("context_history_manage", "Manage the LLM context history for this conversation without affecting the displayed conversation history. This is the active context-management surface. Actions: list returns a bounded index of context entries (position, role, name, length, first-line preview); remove deletes the entry at a given position; summarize replaces a contiguous range of context entries with a concise local summary entry. The displayed conversation history (what the user sees) is never modified by any action.", {
335539
+ action: { type: "string", enum: ["list", "remove", "summarize"], description: "list: index context entries. remove: delete the entry at position. summarize: fold entries [from, to] into one summary entry." },
335540
+ position: { type: "number", minimum: 0, description: "0-based context entry index for remove, or the start of the range for summarize." },
335541
+ to: { type: "number", minimum: 0, description: "0-based inclusive end of the range for summarize. Defaults to position." },
335542
+ limit: { type: "number", minimum: 5, maximum: 400, description: "Maximum context entries to list; defaults to 200." }
335543
+ }, ["action"]),
335533
335544
  t3("question", "Ask user a multiple-choice question", { questions: { type: "array" } }, ["questions"]),
335534
335545
  t3("skill_download", "Download a skill", { name: { type: "string" }, source: { type: "string" } }, ["name", "source"]),
335535
335546
  t3("skill", "Search enabled skill metadata or load one exact skill body on demand. Use query when unsure, then name to load the selected skill.", { query: { type: "string", maxLength: 200 }, name: { type: "string", maxLength: 200 } }, []),
@@ -337615,7 +337626,7 @@ var SubagentManager = class {
337615
337626
  natureSlug: slug,
337616
337627
  displayName,
337617
337628
  qualifiedName,
337618
- name: qualifiedName,
337629
+ name: slug,
337619
337630
  conversationId: this.conversationId,
337620
337631
  createdByAgentId,
337621
337632
  prompt,
@@ -337626,7 +337637,7 @@ var SubagentManager = class {
337626
337637
  flowName: flowName || void 0,
337627
337638
  flowPc: Math.max(0, Math.floor(Number(flowPc) || 0)),
337628
337639
  status: "queued",
337629
- messages: [{ role: "system", content: `Peer agent '${qualifiedName}': ${prompt}` }, { role: "user", content: prompt, hidden_user_input: true }],
337640
+ messages: [{ role: "system", content: `Peer agent '${slug}' (${id}): ${prompt}` }, { role: "user", content: prompt, hidden_user_input: true }],
337630
337641
  result: null,
337631
337642
  createdAt: stamp,
337632
337643
  updatedAt: stamp
@@ -337636,7 +337647,10 @@ var SubagentManager = class {
337636
337647
  return id;
337637
337648
  }
337638
337649
  get(id) {
337639
- return this.subs.get(id) || [...this.subs.values()].find((item) => item.name === id || item.qualifiedName === id || item.displayName === id || item.shortId === id || item.natureSlug === natureSlug(id));
337650
+ if (this.subs.has(id)) return this.subs.get(id);
337651
+ const exact = [...this.subs.values()].find((item) => item.id === id || item.qualifiedName === id);
337652
+ if (exact) return exact;
337653
+ return [...this.subs.values()].find((item) => item.name === id || item.displayName === id || item.shortId === id || item.natureSlug === natureSlug(id));
337640
337654
  }
337641
337655
  send(id, prompt) {
337642
337656
  const target = this.get(id);
@@ -337784,6 +337798,7 @@ var SubagentManager = class {
337784
337798
  natureSlug: record.natureSlug,
337785
337799
  displayName: record.displayName,
337786
337800
  qualifiedName: record.qualifiedName,
337801
+ name: record.name,
337787
337802
  createdByAgentId: record.createdByAgentId,
337788
337803
  status: record.status,
337789
337804
  active: record.status !== "closed",
@@ -340412,6 +340427,8 @@ async function executeNewmarkTool(agent, name50, args, inputSchema, signal) {
340412
340427
  if (name50 === "subagent_close") return agent.handleSubagentCloseEnvelope(args).output;
340413
340428
  if (name50 === "linked_plan") return agent.handleLinkedPlanTool(args);
340414
340429
  if (name50 === "build_history_query") return agent.handleBuildHistoryQuery(args);
340430
+ if (name50 === "context_compress") return (await agent.handleContextCompress(args, signal)).output;
340431
+ if (name50 === "context_history_manage") return agent.handleContextHistoryManage(args).output;
340415
340432
  if (name50 === "question") {
340416
340433
  if (agent.config.getStr("agent", "option_feedback") === "fully_autonomous") return "[question] Disabled by fully_autonomous option feedback.";
340417
340434
  if (!agent.handleQuestion(args)) return "[Question rejected: at least one question with two labeled options is required.]";
@@ -346148,6 +346165,132 @@ Review this persisted peer result and summarize or continue the parent task as n
346148
346165
  truncatedActivities: Math.max(0, publicEvents.length - activities.length)
346149
346166
  });
346150
346167
  }
346168
+ async handleContextCompress(args, signal) {
346169
+ let input = {};
346170
+ try {
346171
+ input = JSON.parse(args || "{}");
346172
+ } catch {
346173
+ }
346174
+ if (this.history.length <= 1) return { ok: false, output: "[context_compress] No context to compress.", error: "No context to compress." };
346175
+ const previousKeepLast = this.config.getNum("context", "keep_recent_messages");
346176
+ const keepRecent = Math.max(2, Math.min(60, Math.floor(Number(input.keep_recent) || previousKeepLast || 10)));
346177
+ const force = Boolean(input.force);
346178
+ try {
346179
+ this.config.set("context", "keep_recent_messages", keepRecent);
346180
+ const msgs = this.history.map((message) => ({ ...message }));
346181
+ const provider = this.engineModel();
346182
+ await this.maybeCompress(msgs, provider, signal, this.activeModelName(), force);
346183
+ if (this.history.length <= 1) return { ok: false, output: "[context_compress] Compression skipped: context unchanged.", error: "Compression skipped." };
346184
+ return {
346185
+ ok: true,
346186
+ output: JSON.stringify({
346187
+ ok: true,
346188
+ compressed: true,
346189
+ at: this.lastCompression?.at,
346190
+ originalMessages: this.lastCompression?.originalMessages,
346191
+ compressedMessages: this.lastCompression?.compressedMessages,
346192
+ originalChars: this.lastCompression?.originalChars,
346193
+ compressedChars: this.lastCompression?.compressedChars,
346194
+ estimatedTokens: this.lastCompression?.compressedTokens,
346195
+ summary: this.lastCompression?.summary?.slice(0, 2e3),
346196
+ model: this.lastCompression?.model,
346197
+ fallback: this.lastCompression?.fallback,
346198
+ displayHistory: { untouched: true, messageCount: this.chatMessages.length }
346199
+ }, null, 2),
346200
+ metadata: { kind: "context-compress" }
346201
+ };
346202
+ } finally {
346203
+ this.config.set("context", "keep_recent_messages", previousKeepLast);
346204
+ }
346205
+ }
346206
+ handleContextHistoryManage(args) {
346207
+ let input = {};
346208
+ try {
346209
+ input = JSON.parse(args || "{}");
346210
+ } catch {
346211
+ }
346212
+ const action = String(input.action || "").trim();
346213
+ if (!action) return { ok: false, output: "[context_history_manage] action is required (list|remove|summarize).", error: "action is required." };
346214
+ if (action === "list") {
346215
+ const limit = Math.max(5, Math.min(400, Math.floor(Number(input.limit || 200))));
346216
+ const entries = this.history.slice(0, limit).map((message, index) => ({
346217
+ position: index,
346218
+ role: String(message.role || ""),
346219
+ name: String(message.name || ""),
346220
+ chars: typeof message.content === "string" ? message.content.length : JSON.stringify(message.content || "").length,
346221
+ preview: this.compressionHistoryContent(message.content || "").slice(0, 160)
346222
+ }));
346223
+ return {
346224
+ ok: true,
346225
+ output: JSON.stringify({
346226
+ ok: true,
346227
+ action: "list",
346228
+ entryCount: this.history.length,
346229
+ listed: entries.length,
346230
+ entries,
346231
+ displayHistory: { untouched: true, messageCount: this.chatMessages.length }
346232
+ }, null, 2),
346233
+ metadata: { kind: "context-history-list" }
346234
+ };
346235
+ }
346236
+ if (action === "remove") {
346237
+ const position = Math.floor(Number(input.position));
346238
+ if (!Number.isFinite(position) || position < 0 || position >= this.history.length) {
346239
+ return { ok: false, output: `[context_history_manage] remove position ${position} out of range (0..${this.history.length - 1}).`, error: "remove position out of range." };
346240
+ }
346241
+ const removed = this.history.splice(position, 1)[0];
346242
+ this.saveWorkspaceConversationState(true);
346243
+ return {
346244
+ ok: true,
346245
+ output: JSON.stringify({
346246
+ ok: true,
346247
+ action: "remove",
346248
+ removedPosition: position,
346249
+ removedRole: String(removed?.role || ""),
346250
+ remaining: this.history.length,
346251
+ displayHistory: { untouched: true, messageCount: this.chatMessages.length }
346252
+ }, null, 2),
346253
+ metadata: { kind: "context-history-remove" }
346254
+ };
346255
+ }
346256
+ if (action === "summarize") {
346257
+ const from = Math.max(0, Math.floor(Number(input.position || 0)));
346258
+ const toRaw = Math.floor(Number(input.to ?? input.position));
346259
+ const to = Number.isFinite(toRaw) ? Math.min(this.history.length - 1, Math.max(from, toRaw)) : from;
346260
+ if (from >= this.history.length) return { ok: false, output: `[context_history_manage] summarize position ${from} out of range (0..${this.history.length - 1}).`, error: "summarize position out of range." };
346261
+ if (to - from < 1) return { ok: false, output: "[context_history_manage] summarize requires at least two entries in range.", error: "summarize requires a range of at least two entries." };
346262
+ const segment = this.history.slice(from, to + 1);
346263
+ const chars = segment.reduce((sum, message) => sum + (typeof message.content === "string" ? message.content.length : JSON.stringify(message.content || "").length), 0);
346264
+ const summary = this.localCompressionSummary(
346265
+ `Workspace: ${this.workspace.current?.path || this.rootPath}
346266
+ Mode: ${this.modeName()}`,
346267
+ segment.map((message, i4) => `#${i4 + 1} [${String(message.role || "unknown")}${message.name ? ` ${String(message.name)}` : ""}]
346268
+ ${this.compressionHistoryContent(message.content || "")}`).join("\n\n").slice(0, 2e4),
346269
+ segment.length,
346270
+ chars
346271
+ );
346272
+ const replacement = { role: "system", content: `[Context History Summary]
346273
+ ${summary}` };
346274
+ this.history.splice(from, to - from + 1, replacement);
346275
+ this.saveWorkspaceConversationState(true);
346276
+ return {
346277
+ ok: true,
346278
+ output: JSON.stringify({
346279
+ ok: true,
346280
+ action: "summarize",
346281
+ foldedFrom: from,
346282
+ foldedTo: to,
346283
+ foldedEntries: to - from + 1,
346284
+ foldedChars: chars,
346285
+ remaining: this.history.length,
346286
+ summary: summary.slice(0, 2e3),
346287
+ displayHistory: { untouched: true, messageCount: this.chatMessages.length }
346288
+ }, null, 2),
346289
+ metadata: { kind: "context-history-summarize" }
346290
+ };
346291
+ }
346292
+ return { ok: false, output: `[context_history_manage] Unknown action: ${action}`, error: `Unknown action: ${action}` };
346293
+ }
346151
346294
  recordContextCompressionStep() {
346152
346295
  const runId = this.currentWorkRunId();
346153
346296
  if (!runId) return;
@@ -348015,7 +348158,7 @@ ${settled?.result || settled?.error || ""}`.trim();
348015
348158
  const transcript = sa.messages.map((m2) => `[${m2.role}] ${m2.content}`).join("\n");
348016
348159
  return this.subagents.toToolResult(
348017
348160
  sa.id,
348018
- `get.subagent("${sa.name}")
348161
+ `get.subagent("${sa.name}", id="${sa.id}")
348019
348162
  Status: ${sa.status}
348020
348163
  Model: ${sa.model}
348021
348164
  Mode: ${sa.agentMode}
@@ -348807,7 +348950,7 @@ Falling back to built-in engine.` }];
348807
348950
  if (!this.config.getBool("context", "auto_compress")) return;
348808
348951
  const total = msgs.reduce((sum, m2) => sum + (typeof m2.content === "string" ? m2.content.length : JSON.stringify(m2.content || "").length), 0);
348809
348952
  const budget = this.compressionBudget(msgs);
348810
- if (budget.estimatedTokens < budget.triggerTokens) return;
348953
+ if (budget.estimatedTokens < budget.triggerTokens && !force) return;
348811
348954
  if (!force && this.lastCompression && String(msgs[0]?.content || "").includes(this.lastCompression.summary)) {
348812
348955
  const baselineChars = Math.max(0, Number(this.lastCompression.compressedChars || 0));
348813
348956
  const baselineTokens = Math.max(0, Number(this.lastCompression.compressedTokens || 0));
@@ -590,6 +590,8 @@ export declare class Agent {
590
590
  endedAt?: string;
591
591
  }>;
592
592
  handleBuildHistoryQuery(args: string): string;
593
+ handleContextCompress(args: string, signal?: AbortSignal): Promise<NewmarkToolResult>;
594
+ handleContextHistoryManage(args: string): NewmarkToolResult;
593
595
  recordContextCompressionStep(): void;
594
596
  compressionContinuationPrompt(): string;
595
597
  mirrorConversationStateFrom(id: string, source: Pick<Agent, 'chatMessages' | 'history' | 'conversationPlan'> & Partial<Pick<Agent, 'linkedPlan' | 'subagents' | 'workRuns' | 'continuations'>> & {