dsh-ptc-plus 0.2.4 → 0.3.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/README.en.md +171 -0
- package/README.md +79 -69
- package/assets/ptc-plus-repair-en.png +0 -0
- package/assets/ptc-plus-settings-en.png +0 -0
- package/assets/ptc-plus-settings-zh.png +0 -0
- package/client.js +1134 -144
- package/docs/adr/0019-plugin-settings-and-kill-switch.md +19 -4
- package/docs/adr/0020-optional-cordis-tools-in-ptc-mode.md +2 -2
- package/docs/adr/0022-stage-npm-releases-with-oidc.md +2 -2
- package/docs/architecture.md +10 -9
- package/docs/client-ui.md +29 -11
- package/docs/installation.md +11 -3
- package/docs/runtime-reference.md +17 -11
- package/docs/value-wire.md +1 -1
- package/index.js +30 -1
- package/internal/cell-analysis.js +20 -3
- package/internal/cell-rewriter.js +36 -2
- package/internal/config-spec.js +182 -117
- package/internal/direct-surface-owner.js +56 -5
- package/internal/edit-transport-owner.js +10 -1
- package/internal/failure-reporting.js +15 -0
- package/internal/rejected-cell-editor.js +21 -12
- package/internal/repl-memory-projection.js +277 -0
- package/internal/run-code-description.js +34 -0
- package/internal/runtime-bridge-owner.js +63 -15
- package/internal/runtime-config.js +2 -0
- package/internal/session-cell-executor.js +14 -4
- package/internal/session-events.js +7 -0
- package/internal/session-journal.js +3 -2
- package/internal/session-log-view.js +2 -1
- package/internal/session-runtime.js +19 -2
- package/internal/session-state.js +83 -4
- package/package.json +4 -3
- package/src/client-activity.js +472 -0
- package/src/client.js +456 -20
- package/README.zh.md +0 -161
- /package/assets/{ptc-plus-repair.png → ptc-plus-repair-zh.png} +0 -0
package/internal/config-spec.js
CHANGED
|
@@ -20,14 +20,95 @@ export const CONFIG_FIELDS = Object.freeze([
|
|
|
20
20
|
description: '',
|
|
21
21
|
descriptionEn: '',
|
|
22
22
|
},
|
|
23
|
+
{
|
|
24
|
+
key: 'enhancedToolView',
|
|
25
|
+
type: 'boolean',
|
|
26
|
+
default: true,
|
|
27
|
+
label: '使用 PTC Plus 增强工具卡片',
|
|
28
|
+
labelEn: 'Use enhanced PTC Plus tool cards',
|
|
29
|
+
description: '开启时使用增强工具卡片;关闭后使用 DSH 原生工具卡片。',
|
|
30
|
+
descriptionEn: 'Uses enhanced tool cards when enabled and DSH native tool cards when disabled.',
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
key: 'autoDescribeRunCode',
|
|
34
|
+
type: 'boolean',
|
|
35
|
+
default: true,
|
|
36
|
+
label: '允许执行缺少摘要的 run_code',
|
|
37
|
+
labelEn: 'Allow run_code execution without a summary',
|
|
38
|
+
description: '允许 run_code 缺少外层 description;关闭后恢复 DSH 校验。模型请求和原始调用参数保持不变。',
|
|
39
|
+
descriptionEn: 'Allows run_code to omit its outer description; disabling restores DSH validation. Model requests and original call arguments remain unchanged.',
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
key: 'canonicalizeToolCalls',
|
|
43
|
+
type: 'boolean',
|
|
44
|
+
default: true,
|
|
45
|
+
label: '修复可识别的顶层 native 工具误调用',
|
|
46
|
+
labelEn: 'Repair recognizable top-level native tool mis-calls',
|
|
47
|
+
description: '仅当当前 schema 能唯一确认目标工具且参数有效时,才把顶层 native 工具误调用修复为对应的 run_code 调用。',
|
|
48
|
+
descriptionEn: 'Repairs a top-level native tool mis-call as the corresponding run_code call only when the current schema uniquely identifies the tool and validates its arguments.',
|
|
49
|
+
},
|
|
23
50
|
{
|
|
24
51
|
key: 'cordisToolsEnabled',
|
|
25
52
|
type: 'boolean',
|
|
26
53
|
default: false,
|
|
27
|
-
label: '在 PTC
|
|
28
|
-
labelEn: 'Enable Cordis tools in PTC mode',
|
|
29
|
-
description: '
|
|
30
|
-
descriptionEn: '
|
|
54
|
+
label: '在 PTC 模式中启用官方 Cordis 工具',
|
|
55
|
+
labelEn: 'Enable official Cordis tools in PTC mode',
|
|
56
|
+
description: '开启后,PTC agent 可使用官方 Cordis 工具、配套指引和开发 Skill;关闭后移除这些能力。Cordis 工具以 DSH 进程权限运行。',
|
|
57
|
+
descriptionEn: 'When enabled, PTC agents can use the official Cordis tools, guidance, and development Skill; disabling removes them. Cordis tools run with the DSH process permissions.',
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
key: 'looseTopLevelRedeclarations',
|
|
61
|
+
type: 'boolean',
|
|
62
|
+
default: true,
|
|
63
|
+
label: '允许顶层变量重声明',
|
|
64
|
+
labelEn: 'Allow top-level variable redeclarations',
|
|
65
|
+
description: '允许顶层 const 或 let 声明替换已有变量;关闭后,重声明会在执行前被拒绝。',
|
|
66
|
+
descriptionEn: 'Allows top-level const or let declarations to replace existing variables; disabling rejects redeclarations before execution.',
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
key: 'autoRewriteImports',
|
|
70
|
+
type: 'boolean',
|
|
71
|
+
default: true,
|
|
72
|
+
label: '支持静态 import 声明',
|
|
73
|
+
labelEn: 'Support static import declarations',
|
|
74
|
+
description: '允许在 run_code 中使用静态 import,并保留模块解析和只读 binding 语义。',
|
|
75
|
+
descriptionEn: 'Allows static import declarations in run_code while preserving module resolution and read-only binding semantics.',
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
key: 'autoStripExports',
|
|
79
|
+
type: 'boolean',
|
|
80
|
+
default: true,
|
|
81
|
+
label: '支持顶层 export 修饰符',
|
|
82
|
+
labelEn: 'Support top-level export modifiers',
|
|
83
|
+
description: '允许在 run_code 中使用顶层 export,并保留对应的本地声明或模块副作用。',
|
|
84
|
+
descriptionEn: 'Allows top-level export syntax in run_code while preserving the corresponding local declaration or module side effect.',
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
key: 'autoSplitRedeclarations',
|
|
88
|
+
type: 'boolean',
|
|
89
|
+
default: true,
|
|
90
|
+
label: '支持混合解构重声明',
|
|
91
|
+
labelEn: 'Support mixed destructuring redeclarations',
|
|
92
|
+
description: '允许顶层解构声明同时包含新变量和已有变量。',
|
|
93
|
+
descriptionEn: 'Allows top-level destructuring declarations to contain both new and existing variables.',
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
key: 'durableReplay',
|
|
97
|
+
type: 'boolean',
|
|
98
|
+
default: true,
|
|
99
|
+
label: '启用持久 REPL 恢复',
|
|
100
|
+
labelEn: 'Enable durable REPL recovery',
|
|
101
|
+
description: 'worker 重启后从 session journal 重建可恢复的 REPL 状态。',
|
|
102
|
+
descriptionEn: 'Rebuilds recoverable REPL state from the session journal after a worker restart.',
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
key: 'tipsEnabled',
|
|
106
|
+
type: 'boolean',
|
|
107
|
+
default: true,
|
|
108
|
+
label: '启用失败恢复提示',
|
|
109
|
+
labelEn: 'Enable failure recovery tips',
|
|
110
|
+
description: '在符合条件的失败后显示有冷却间隔的恢复提示。',
|
|
111
|
+
descriptionEn: 'Shows recovery tips with a cooldown after qualifying failures.',
|
|
31
112
|
},
|
|
32
113
|
{
|
|
33
114
|
key: 'computeMs',
|
|
@@ -35,10 +116,10 @@ export const CONFIG_FIELDS = Object.freeze([
|
|
|
35
116
|
default: 60_000,
|
|
36
117
|
min: 1,
|
|
37
118
|
max: Number.MAX_SAFE_INTEGER,
|
|
38
|
-
label: '单 cell
|
|
39
|
-
labelEn: '
|
|
40
|
-
description: '
|
|
41
|
-
descriptionEn: '
|
|
119
|
+
label: '单 cell CPU 时间上限 (ms)',
|
|
120
|
+
labelEn: 'CPU time limit per cell (ms)',
|
|
121
|
+
description: '同步计算超过该上限时中断当前 cell。',
|
|
122
|
+
descriptionEn: 'Interrupts the current cell when synchronous computation exceeds this limit.',
|
|
42
123
|
},
|
|
43
124
|
{
|
|
44
125
|
key: 'maxWallMs',
|
|
@@ -46,32 +127,43 @@ export const CONFIG_FIELDS = Object.freeze([
|
|
|
46
127
|
default: 600_000,
|
|
47
128
|
min: 1,
|
|
48
129
|
max: MAX_TIMER_DELAY_MS,
|
|
49
|
-
label: '单 cell
|
|
50
|
-
labelEn: '
|
|
51
|
-
description: '
|
|
52
|
-
descriptionEn: '
|
|
130
|
+
label: '单 cell 总耗时上限 (ms)',
|
|
131
|
+
labelEn: 'Elapsed time limit per cell (ms)',
|
|
132
|
+
description: '限制完整 cell 执行的耗时,包括异步等待。',
|
|
133
|
+
descriptionEn: 'Limits the complete cell execution time, including asynchronous waits.',
|
|
53
134
|
},
|
|
54
135
|
{
|
|
55
|
-
key: '
|
|
136
|
+
key: 'maxOldGenerationSizeMb',
|
|
56
137
|
type: 'integer',
|
|
57
|
-
default:
|
|
138
|
+
default: 512,
|
|
58
139
|
min: 1,
|
|
59
140
|
max: Number.MAX_SAFE_INTEGER,
|
|
60
|
-
label: '
|
|
61
|
-
labelEn: '
|
|
62
|
-
description: '
|
|
63
|
-
descriptionEn: '
|
|
141
|
+
label: '每个 worker 旧生代内存上限 (MiB)',
|
|
142
|
+
labelEn: 'Old-generation memory limit per worker (MiB)',
|
|
143
|
+
description: '限制每个 worker 的 V8 旧生代;活动 worker 存在时不能修改。',
|
|
144
|
+
descriptionEn: 'Limits the V8 old generation for each worker; this setting cannot change while a worker is active.',
|
|
64
145
|
},
|
|
65
146
|
{
|
|
66
|
-
key: '
|
|
147
|
+
key: 'maxNestedRunCodeDepth',
|
|
67
148
|
type: 'integer',
|
|
68
|
-
default:
|
|
149
|
+
default: 8,
|
|
150
|
+
min: 1,
|
|
151
|
+
max: Number.MAX_SAFE_INTEGER,
|
|
152
|
+
label: 'code.run 嵌套层数上限',
|
|
153
|
+
labelEn: 'code.run nesting depth limit',
|
|
154
|
+
description: '限制单个顶层 cell 中 code.run 的最大嵌套层数。',
|
|
155
|
+
descriptionEn: 'Limits the maximum code.run nesting depth within one top-level cell.',
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
key: 'maxOutputBytes',
|
|
159
|
+
type: 'integer',
|
|
160
|
+
default: 64 * 1024 * 1024,
|
|
69
161
|
min: 1,
|
|
70
162
|
max: Number.MAX_SAFE_INTEGER,
|
|
71
|
-
label: '
|
|
72
|
-
labelEn: '
|
|
73
|
-
description: '
|
|
74
|
-
descriptionEn: '
|
|
163
|
+
label: '单 cell 输出上限 (bytes)',
|
|
164
|
+
labelEn: 'Output limit per cell (bytes)',
|
|
165
|
+
description: '限制单个 cell 的日志和返回结果的合计大小。',
|
|
166
|
+
descriptionEn: 'Limits the combined size of one cell\'s logs and returned result.',
|
|
75
167
|
},
|
|
76
168
|
{
|
|
77
169
|
key: 'maxValueNodes',
|
|
@@ -79,10 +171,10 @@ export const CONFIG_FIELDS = Object.freeze([
|
|
|
79
171
|
default: 100_000,
|
|
80
172
|
min: 1,
|
|
81
173
|
max: Number.MAX_SAFE_INTEGER,
|
|
82
|
-
label: '
|
|
83
|
-
labelEn: '
|
|
84
|
-
description: '
|
|
85
|
-
descriptionEn: '
|
|
174
|
+
label: '返回值节点数上限',
|
|
175
|
+
labelEn: 'Returned-value node limit',
|
|
176
|
+
description: '限制单次返回值的 Value Graph 节点数。',
|
|
177
|
+
descriptionEn: 'Limits the Value Graph node count for one returned value.',
|
|
86
178
|
},
|
|
87
179
|
{
|
|
88
180
|
key: 'maxValueEdges',
|
|
@@ -90,10 +182,10 @@ export const CONFIG_FIELDS = Object.freeze([
|
|
|
90
182
|
default: 1_000_000,
|
|
91
183
|
min: 1,
|
|
92
184
|
max: Number.MAX_SAFE_INTEGER,
|
|
93
|
-
label: '
|
|
94
|
-
labelEn: '
|
|
95
|
-
description: '
|
|
96
|
-
descriptionEn: '
|
|
185
|
+
label: '返回值引用边数上限',
|
|
186
|
+
labelEn: 'Returned-value reference-edge limit',
|
|
187
|
+
description: '限制单次返回值的 Value Graph 引用边数。',
|
|
188
|
+
descriptionEn: 'Limits the Value Graph reference-edge count for one returned value.',
|
|
97
189
|
},
|
|
98
190
|
{
|
|
99
191
|
key: 'maxValueArrayLength',
|
|
@@ -101,10 +193,10 @@ export const CONFIG_FIELDS = Object.freeze([
|
|
|
101
193
|
default: 1_000_000,
|
|
102
194
|
min: 1,
|
|
103
195
|
max: Number.MAX_SAFE_INTEGER,
|
|
104
|
-
label: '
|
|
105
|
-
labelEn: '
|
|
106
|
-
description: '
|
|
107
|
-
descriptionEn: '
|
|
196
|
+
label: '返回数组长度上限',
|
|
197
|
+
labelEn: 'Returned-array length limit',
|
|
198
|
+
description: '限制返回数组的最大声明长度。',
|
|
199
|
+
descriptionEn: 'Limits the maximum declared length of a returned array.',
|
|
108
200
|
},
|
|
109
201
|
{
|
|
110
202
|
key: 'maxValueBigIntDigits',
|
|
@@ -112,84 +204,10 @@ export const CONFIG_FIELDS = Object.freeze([
|
|
|
112
204
|
default: 100_000,
|
|
113
205
|
min: 1,
|
|
114
206
|
max: Number.MAX_SAFE_INTEGER,
|
|
115
|
-
label: 'BigInt
|
|
116
|
-
labelEn: '
|
|
207
|
+
label: '返回值 BigInt 十进制位数上限',
|
|
208
|
+
labelEn: 'Returned-value BigInt decimal-digit limit',
|
|
117
209
|
description: '限制返回值中 BigInt 的十进制位数。',
|
|
118
|
-
descriptionEn: '
|
|
119
|
-
},
|
|
120
|
-
{
|
|
121
|
-
key: 'maxNestedRunCodeDepth',
|
|
122
|
-
type: 'integer',
|
|
123
|
-
default: 8,
|
|
124
|
-
min: 1,
|
|
125
|
-
max: Number.MAX_SAFE_INTEGER,
|
|
126
|
-
label: 'code.run 最大递归深度',
|
|
127
|
-
labelEn: 'Max code.run recursion depth',
|
|
128
|
-
description: '限制 code.run 的嵌套层数。',
|
|
129
|
-
descriptionEn: 'Caps how deeply code.run may nest.',
|
|
130
|
-
},
|
|
131
|
-
{
|
|
132
|
-
key: 'canonicalizeToolCalls',
|
|
133
|
-
type: 'boolean',
|
|
134
|
-
default: true,
|
|
135
|
-
label: '规范顶层 native 误调',
|
|
136
|
-
labelEn: 'Canonicalize top-level native mis-calls',
|
|
137
|
-
description: '修正可以明确识别的顶层 native 误调。',
|
|
138
|
-
descriptionEn: 'Repairs top-level native mis-calls that can be identified unambiguously.',
|
|
139
|
-
},
|
|
140
|
-
{
|
|
141
|
-
key: 'looseTopLevelRedeclarations',
|
|
142
|
-
type: 'boolean',
|
|
143
|
-
default: true,
|
|
144
|
-
label: '宽松顶层重声明',
|
|
145
|
-
labelEn: 'Loose top-level redeclarations',
|
|
146
|
-
description: '允许顶层 const/let 重声明已有变量。',
|
|
147
|
-
descriptionEn: 'Allows top-level const/let to redeclare existing variables.',
|
|
148
|
-
},
|
|
149
|
-
{
|
|
150
|
-
key: 'durableReplay',
|
|
151
|
-
type: 'boolean',
|
|
152
|
-
default: true,
|
|
153
|
-
label: '持久重放',
|
|
154
|
-
labelEn: 'Durable replay',
|
|
155
|
-
description: 'worker 重启后恢复可以重建的 REPL 状态。',
|
|
156
|
-
descriptionEn: 'Rebuilds recoverable REPL state after a worker restart.',
|
|
157
|
-
},
|
|
158
|
-
{
|
|
159
|
-
key: 'autoRewriteImports',
|
|
160
|
-
type: 'boolean',
|
|
161
|
-
default: true,
|
|
162
|
-
label: '自动改写 import',
|
|
163
|
-
labelEn: 'Auto-rewrite import',
|
|
164
|
-
description: '允许在 run_code 中使用静态 import。',
|
|
165
|
-
descriptionEn: 'Allows static import declarations inside run_code.',
|
|
166
|
-
},
|
|
167
|
-
{
|
|
168
|
-
key: 'autoStripExports',
|
|
169
|
-
type: 'boolean',
|
|
170
|
-
default: true,
|
|
171
|
-
label: '自动剥离 export',
|
|
172
|
-
labelEn: 'Auto-strip export',
|
|
173
|
-
description: '允许在 run_code 中使用顶层 export。',
|
|
174
|
-
descriptionEn: 'Allows top-level export modifiers inside run_code.',
|
|
175
|
-
},
|
|
176
|
-
{
|
|
177
|
-
key: 'autoSplitRedeclarations',
|
|
178
|
-
type: 'boolean',
|
|
179
|
-
default: true,
|
|
180
|
-
label: '自动拆分混合重声明',
|
|
181
|
-
labelEn: 'Auto-split mixed redeclarations',
|
|
182
|
-
description: '允许顶层解构声明同时包含新旧变量。',
|
|
183
|
-
descriptionEn: 'Allows top-level destructuring declarations that mix new and existing variables.',
|
|
184
|
-
},
|
|
185
|
-
{
|
|
186
|
-
key: 'tipsEnabled',
|
|
187
|
-
type: 'boolean',
|
|
188
|
-
default: true,
|
|
189
|
-
label: '启用恢复提示',
|
|
190
|
-
labelEn: 'Enable recovery tips',
|
|
191
|
-
description: '在符合条件的失败后显示恢复提示。',
|
|
192
|
-
descriptionEn: 'Shows recovery tips after qualifying failures.',
|
|
210
|
+
descriptionEn: 'Limits the decimal-digit count of BigInt values in one returned value.',
|
|
193
211
|
},
|
|
194
212
|
{
|
|
195
213
|
key: 'tipCooldownMessages',
|
|
@@ -197,8 +215,8 @@ export const CONFIG_FIELDS = Object.freeze([
|
|
|
197
215
|
default: 3,
|
|
198
216
|
min: 1,
|
|
199
217
|
max: Number.MAX_SAFE_INTEGER,
|
|
200
|
-
label: '
|
|
201
|
-
labelEn: '
|
|
218
|
+
label: '同类恢复提示间隔 (messages)',
|
|
219
|
+
labelEn: 'Same-kind recovery tip interval (messages)',
|
|
202
220
|
description: '同类恢复提示之间的最小间隔。',
|
|
203
221
|
descriptionEn: 'The minimum gap between recovery tips of the same kind.',
|
|
204
222
|
},
|
|
@@ -208,13 +226,60 @@ export const CONFIG_FIELDS = Object.freeze([
|
|
|
208
226
|
default: 2,
|
|
209
227
|
min: 1,
|
|
210
228
|
max: Number.MAX_SAFE_INTEGER,
|
|
211
|
-
label: '
|
|
212
|
-
labelEn: '
|
|
229
|
+
label: '详细恢复提示阈值 (failures)',
|
|
230
|
+
labelEn: 'Detailed recovery tip threshold (failures)',
|
|
213
231
|
description: '连续失败达到此次数后显示更详细的恢复提示。',
|
|
214
232
|
descriptionEn: 'After this many consecutive failures, a more detailed recovery tip is shown.',
|
|
215
233
|
},
|
|
216
234
|
])
|
|
217
235
|
|
|
236
|
+
/** Presentation groups keep high-attention decisions separate from advanced policy and limits. */
|
|
237
|
+
export const CONFIG_GROUPS = Object.freeze([
|
|
238
|
+
{
|
|
239
|
+
key: 'core',
|
|
240
|
+
label: '常用与兼容性',
|
|
241
|
+
labelEn: 'Common and compatibility',
|
|
242
|
+
fields: Object.freeze(['enabled', 'enhancedToolView', 'autoDescribeRunCode', 'canonicalizeToolCalls']),
|
|
243
|
+
},
|
|
244
|
+
{
|
|
245
|
+
key: 'optional',
|
|
246
|
+
label: '可选能力',
|
|
247
|
+
labelEn: 'Optional capabilities',
|
|
248
|
+
fields: Object.freeze(['cordisToolsEnabled']),
|
|
249
|
+
},
|
|
250
|
+
{
|
|
251
|
+
key: 'advanced',
|
|
252
|
+
label: '高级行为',
|
|
253
|
+
labelEn: 'Advanced behavior',
|
|
254
|
+
fields: Object.freeze([
|
|
255
|
+
'looseTopLevelRedeclarations',
|
|
256
|
+
'autoRewriteImports',
|
|
257
|
+
'autoStripExports',
|
|
258
|
+
'autoSplitRedeclarations',
|
|
259
|
+
'durableReplay',
|
|
260
|
+
'tipsEnabled',
|
|
261
|
+
]),
|
|
262
|
+
},
|
|
263
|
+
{
|
|
264
|
+
key: 'limits',
|
|
265
|
+
label: '资源限制',
|
|
266
|
+
labelEn: 'Resource limits',
|
|
267
|
+
fields: Object.freeze([
|
|
268
|
+
'computeMs',
|
|
269
|
+
'maxWallMs',
|
|
270
|
+
'maxOldGenerationSizeMb',
|
|
271
|
+
'maxNestedRunCodeDepth',
|
|
272
|
+
'maxOutputBytes',
|
|
273
|
+
'maxValueNodes',
|
|
274
|
+
'maxValueEdges',
|
|
275
|
+
'maxValueArrayLength',
|
|
276
|
+
'maxValueBigIntDigits',
|
|
277
|
+
'tipCooldownMessages',
|
|
278
|
+
'tipEscalationFailures',
|
|
279
|
+
]),
|
|
280
|
+
},
|
|
281
|
+
])
|
|
282
|
+
|
|
218
283
|
/** Resolved defaults, derived once from the field definitions. */
|
|
219
284
|
export const CONFIG_DEFAULTS = Object.freeze(
|
|
220
285
|
Object.fromEntries(CONFIG_FIELDS.map(field => [field.key, field.default])),
|
|
@@ -6,6 +6,11 @@ import { projectProgramSdk } from './sdk-projection.js'
|
|
|
6
6
|
import { EDIT_RUN_CODE } from './edit-transport-owner.js'
|
|
7
7
|
import { RUN_CODE } from './runtime-bridge-owner.js'
|
|
8
8
|
import { isRecord } from './record-utils.js'
|
|
9
|
+
import { missingDescriptionPath } from './failure-reporting.js'
|
|
10
|
+
import {
|
|
11
|
+
generatedRunCodeExecutionArguments,
|
|
12
|
+
generatedRunCodeDescriptionMeta,
|
|
13
|
+
} from './run-code-description.js'
|
|
9
14
|
|
|
10
15
|
const RUN_CODE_TOOL_DESCRIPTION = 'Evaluate the next TypeScript cell in this session-bound persistent REPL. Earlier top-level bindings remain available, so this call extends the current environment instead of creating a fresh one. Use `code` for the async-function body and `description` for its short UI summary. Successful image-bearing subtool results are attached after the cell.'
|
|
11
16
|
const RUN_CODE_CODE_DESCRIPTION = 'Code for the next REPL cell, parsed as the body of an async TypeScript function.'
|
|
@@ -147,6 +152,7 @@ export function createDirectSurfaceOwner({
|
|
|
147
152
|
const sessions = new Map()
|
|
148
153
|
const cordisRecovery = createCordisRecoveryPolicy(runtimeConfig.cordisToolsEnabled)
|
|
149
154
|
let currentCanonicalizeToolCalls = canonicalizeToolCalls
|
|
155
|
+
let currentAutoDescribeRunCode = runtimeConfig.autoDescribeRunCode
|
|
150
156
|
const tipConfig = {
|
|
151
157
|
enabled: runtimeConfig.tipsEnabled,
|
|
152
158
|
cooldownMessages: runtimeConfig.tipCooldownMessages,
|
|
@@ -187,9 +193,9 @@ export function createDirectSurfaceOwner({
|
|
|
187
193
|
return undefined
|
|
188
194
|
}
|
|
189
195
|
|
|
190
|
-
const rememberRequest = (id, signal, presentation, nativeSchemas) => {
|
|
196
|
+
const rememberRequest = (id, signal, presentation, nativeSchemas, autoDescribeRunCode) => {
|
|
191
197
|
const owner = sessionOwner(id)
|
|
192
|
-
const request = { presentation, nativeSchemas, owner }
|
|
198
|
+
const request = { presentation, nativeSchemas, autoDescribeRunCode, owner }
|
|
193
199
|
owner.latestRequest = request
|
|
194
200
|
if (signal !== undefined) canonicalRequests.set(signal, request)
|
|
195
201
|
}
|
|
@@ -211,12 +217,15 @@ export function createDirectSurfaceOwner({
|
|
|
211
217
|
return Object.freeze({
|
|
212
218
|
reconfigure(nextConfig) {
|
|
213
219
|
currentCanonicalizeToolCalls = nextConfig.canonicalizeToolCalls
|
|
220
|
+
currentAutoDescribeRunCode = nextConfig.autoDescribeRunCode
|
|
214
221
|
cordisRecovery.reconfigure(nextConfig.cordisToolsEnabled)
|
|
215
222
|
tipConfig.enabled = nextConfig.tipsEnabled
|
|
216
223
|
tipConfig.cooldownMessages = nextConfig.tipCooldownMessages
|
|
217
224
|
tipConfig.escalationFailures = nextConfig.tipEscalationFailures
|
|
218
225
|
},
|
|
219
226
|
async assemble(initialAssembly, context, next) {
|
|
227
|
+
// Keep schema projection and later execution on one configuration snapshot.
|
|
228
|
+
const autoDescribeRunCode = currentAutoDescribeRunCode
|
|
220
229
|
const agent = context?.agent
|
|
221
230
|
const id = sessionId(agent)
|
|
222
231
|
const initialState = presentationState(initialAssembly)
|
|
@@ -252,7 +261,7 @@ export function createDirectSurfaceOwner({
|
|
|
252
261
|
throw new Error(`ptc-plus: ${presentation} agent composition assembled without run_code`)
|
|
253
262
|
}
|
|
254
263
|
if (id !== undefined) {
|
|
255
|
-
rememberRequest(id, requestSignal, 'native', new Map())
|
|
264
|
+
rememberRequest(id, requestSignal, 'native', new Map(), autoDescribeRunCode)
|
|
256
265
|
}
|
|
257
266
|
return assembly
|
|
258
267
|
}
|
|
@@ -300,14 +309,16 @@ export function createDirectSurfaceOwner({
|
|
|
300
309
|
&& schema.name !== RUN_CODE && schema.name !== EDIT_RUN_CODE)
|
|
301
310
|
.map(schema => [schema.name, schema]))
|
|
302
311
|
: new Map()
|
|
303
|
-
rememberRequest(id, requestSignal, presentation, nativeSchemas)
|
|
312
|
+
rememberRequest(id, requestSignal, presentation, nativeSchemas, autoDescribeRunCode)
|
|
304
313
|
}
|
|
305
314
|
|
|
306
315
|
return {
|
|
307
316
|
...assembly,
|
|
308
317
|
tools: sessionPtcProjection
|
|
309
318
|
? directTools
|
|
310
|
-
: directTools.map(tool => tool?.name === RUN_CODE
|
|
319
|
+
: directTools.map(tool => tool?.name === RUN_CODE
|
|
320
|
+
? adaptRunCodeSchema(tool)
|
|
321
|
+
: tool),
|
|
311
322
|
sections,
|
|
312
323
|
contexts,
|
|
313
324
|
}
|
|
@@ -343,6 +354,46 @@ export function createDirectSurfaceOwner({
|
|
|
343
354
|
if (policy?.presentation !== 'ptc') return undefined
|
|
344
355
|
return rejection(`tool ${exec.name} is not a direct PTC tool; use run_code or edit_run_code directly, and call native tools from inside run_code`)
|
|
345
356
|
},
|
|
357
|
+
executionArguments(exec) {
|
|
358
|
+
const id = sessionId(exec.agent)
|
|
359
|
+
const policy = executionPolicy(id, exec.callId)
|
|
360
|
+
?? requestPolicy(exec?.signal, id)
|
|
361
|
+
const originalArguments = exec.arguments
|
|
362
|
+
if (exec.name !== RUN_CODE || exec.parent !== undefined
|
|
363
|
+
|| policy?.autoDescribeRunCode !== true || policy.presentation === 'native'
|
|
364
|
+
|| !isRecord(originalArguments) || Object.hasOwn(originalArguments, 'description')
|
|
365
|
+
|| typeof originalArguments.code !== 'string') {
|
|
366
|
+
return originalArguments
|
|
367
|
+
}
|
|
368
|
+
return generatedRunCodeExecutionArguments(originalArguments)
|
|
369
|
+
},
|
|
370
|
+
argumentDiagnostic(exec, result) {
|
|
371
|
+
// DSH uses success-result identity to avoid re-running output projectors
|
|
372
|
+
// after this middleware's settlement scope has ended.
|
|
373
|
+
if (exec?.name !== RUN_CODE || result?.isError !== true) return result
|
|
374
|
+
const meta = generatedRunCodeDescriptionMeta(exec.arguments, result.meta)
|
|
375
|
+
const diagnosed = meta === result.meta
|
|
376
|
+
? result
|
|
377
|
+
: { ...result, ...(meta === undefined ? {} : { meta }) }
|
|
378
|
+
const missingPath = missingDescriptionPath(diagnosed.error)
|
|
379
|
+
if (missingPath === undefined) return diagnosed
|
|
380
|
+
const id = sessionId(exec.agent)
|
|
381
|
+
const policy = executionPolicy(id, exec.callId)
|
|
382
|
+
?? requestPolicy(exec?.signal, id)
|
|
383
|
+
const outer = missingPath === 'description'
|
|
384
|
+
&& policy?.autoDescribeRunCode !== true
|
|
385
|
+
&& !(isRecord(exec.arguments) && typeof exec.arguments.description === 'string')
|
|
386
|
+
const context = {
|
|
387
|
+
name: 'tools:ptc-plus-run-code-arguments',
|
|
388
|
+
text: outer
|
|
389
|
+
? 'The run_code outer transport arguments are invalid at JSON path $.description. Add a sibling string `description` field to run_code; a description nested inside a native-tool argument does not satisfy this outer requirement.'
|
|
390
|
+
: `A nested native-tool argument is missing required property "${missingPath}". Add a string description at that path in the native-tool arguments; the outer run_code description does not satisfy this nested requirement.`,
|
|
391
|
+
}
|
|
392
|
+
return {
|
|
393
|
+
...diagnosed,
|
|
394
|
+
additionalContexts: [...diagnosed.additionalContexts ?? [], context],
|
|
395
|
+
}
|
|
396
|
+
},
|
|
346
397
|
handleResult(exec) {
|
|
347
398
|
const id = sessionId(exec.agent)
|
|
348
399
|
if (id === undefined || typeof exec.callId !== 'string') return
|
|
@@ -20,6 +20,10 @@ import {
|
|
|
20
20
|
import { editTargetForCall, projectSessionLog } from './session-log-view.js'
|
|
21
21
|
import { RUN_CODE } from './runtime-bridge-owner.js'
|
|
22
22
|
import { isRecord } from './record-utils.js'
|
|
23
|
+
import {
|
|
24
|
+
validatedReplMemorySnapshot,
|
|
25
|
+
withReplMemorySnapshot,
|
|
26
|
+
} from './repl-memory-projection.js'
|
|
23
27
|
|
|
24
28
|
export const EDIT_RUN_CODE = 'edit_run_code'
|
|
25
29
|
|
|
@@ -52,6 +56,7 @@ function derivedEditResult(inner) {
|
|
|
52
56
|
export function createEditTransportOwner(ctx, {
|
|
53
57
|
durableReplay,
|
|
54
58
|
executeTentative,
|
|
59
|
+
presentationGeneration,
|
|
55
60
|
sessionId,
|
|
56
61
|
toolSchemasForAgent,
|
|
57
62
|
}) {
|
|
@@ -91,7 +96,9 @@ export function createEditTransportOwner(ctx, {
|
|
|
91
96
|
if (derived.recoveryBoundaries !== undefined) {
|
|
92
97
|
meta[RECOVERY_BOUNDARY_KEY] = normalizeRecoveryBoundaries(derived.recoveryBoundaries)
|
|
93
98
|
}
|
|
94
|
-
return
|
|
99
|
+
return derived.replMemory === undefined
|
|
100
|
+
? meta
|
|
101
|
+
: withReplMemorySnapshot(meta, derived.replMemory, presentationGeneration)
|
|
95
102
|
}
|
|
96
103
|
definition.output = {
|
|
97
104
|
schema: {
|
|
@@ -178,12 +185,14 @@ export function createEditTransportOwner(ctx, {
|
|
|
178
185
|
&& Object.hasOwn(inner.meta, RECOVERY_BOUNDARY_KEY)
|
|
179
186
|
? normalizeRecoveryBoundaries(inner.meta[RECOVERY_BOUNDARY_KEY])
|
|
180
187
|
: undefined
|
|
188
|
+
const replMemory = validatedReplMemorySnapshot(inner?.meta, presentationGeneration)
|
|
181
189
|
const value = derivedEditResult(inner)
|
|
182
190
|
const derived = {
|
|
183
191
|
targetCallSeq: target.callSeq,
|
|
184
192
|
journal,
|
|
185
193
|
rewrites,
|
|
186
194
|
recoveryBoundaries,
|
|
195
|
+
replMemory,
|
|
187
196
|
code: edited.code,
|
|
188
197
|
description: edited.description,
|
|
189
198
|
}
|
|
@@ -64,6 +64,21 @@ export function oneLineMessage(error) {
|
|
|
64
64
|
return firstLine(messageOf(error), 'Unknown error').replace(/\s+\(\d+:\d+\)$/, '')
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
+
/** Return DSH's reported missing-description property path when it is actionable. */
|
|
68
|
+
export function missingDescriptionPath(error) {
|
|
69
|
+
const violations = messageOf(error).matchAll(/missing required property ["']([^"']+)["']/g)
|
|
70
|
+
for (const match of violations) {
|
|
71
|
+
const path = match[1]
|
|
72
|
+
if (path === 'description' || path.endsWith('.description')) return path
|
|
73
|
+
}
|
|
74
|
+
return undefined
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** Identify DSH's stable missing-description validation fact without parsing arbitrary errors. */
|
|
78
|
+
export function hasMissingDescriptionError(error) {
|
|
79
|
+
return missingDescriptionPath(error) !== undefined
|
|
80
|
+
}
|
|
81
|
+
|
|
67
82
|
/** Keep only the newest log entries so an output-limit error cannot flood the model. */
|
|
68
83
|
export function limitLogs(logs) {
|
|
69
84
|
let bytes = 0
|
|
@@ -252,15 +252,29 @@ function assemble(source, replacements) {
|
|
|
252
252
|
return changed ? { code: chunks.join('') } : { error: 'edits must change at least one matched fragment' }
|
|
253
253
|
}
|
|
254
254
|
|
|
255
|
+
function editRunCodeParameterBranch(operation, operationSchema) {
|
|
256
|
+
return {
|
|
257
|
+
type: 'object',
|
|
258
|
+
additionalProperties: false,
|
|
259
|
+
properties: {
|
|
260
|
+
[operation]: operationSchema,
|
|
261
|
+
[EXPECTED_TARGET_CALL_SEQ]: {
|
|
262
|
+
type: 'integer', minimum: 0,
|
|
263
|
+
description: 'Optional target precondition copied from a validated diagnostic. The edit is rejected if the captured cell has another call sequence.',
|
|
264
|
+
},
|
|
265
|
+
},
|
|
266
|
+
required: [operation],
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
255
270
|
export function editRunCodeSchema() {
|
|
256
271
|
return {
|
|
257
272
|
name: 'edit_run_code',
|
|
258
273
|
description: 'Make a small exact or regular-expression change to the most recent eligible cell captured when this edit call is dispatched, then run the complete corrected cell. A successful edit becomes the next eligible cell. Use this only when replaying the whole cell is safe. If earlier code may already have caused an external effect, use a new run_code cell and its existing variables instead; this tool does not resume at the error location. Send exactly one atomic edits or regex_edits array, plus expected_target_call_seq only when a diagnostic supplies it to bind a validated repair to its rejected cell. Choose edits for a few unique literal fragments; choose regex_edits when one counted pattern covers repeated fragments. Every resolved range must be non-overlapping in the original cell.',
|
|
259
274
|
parameters: {
|
|
260
275
|
type: 'object',
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
edits: {
|
|
276
|
+
oneOf: [
|
|
277
|
+
editRunCodeParameterBranch('edits', {
|
|
264
278
|
type: 'array', minItems: 1, maxItems: EDIT_LIMITS.exactEdits,
|
|
265
279
|
description: 'Atomic exact replacements, all resolved against the original target cell.',
|
|
266
280
|
items: {
|
|
@@ -271,8 +285,8 @@ export function editRunCodeSchema() {
|
|
|
271
285
|
},
|
|
272
286
|
required: ['old_string', 'new_string'],
|
|
273
287
|
},
|
|
274
|
-
},
|
|
275
|
-
regex_edits
|
|
288
|
+
}),
|
|
289
|
+
editRunCodeParameterBranch('regex_edits', {
|
|
276
290
|
type: 'array', minItems: 1, maxItems: EDIT_LIMITS.regexEdits,
|
|
277
291
|
description: 'Atomic regular-expression replacements, all matched against the original target cell.',
|
|
278
292
|
items: {
|
|
@@ -285,13 +299,8 @@ export function editRunCodeSchema() {
|
|
|
285
299
|
},
|
|
286
300
|
required: ['pattern', 'flags', 'replacement', 'expected_matches'],
|
|
287
301
|
},
|
|
288
|
-
},
|
|
289
|
-
|
|
290
|
-
type: 'integer', minimum: 0,
|
|
291
|
-
description: 'Optional target precondition copied from a validated diagnostic. The edit is rejected if the captured cell has another call sequence.',
|
|
292
|
-
},
|
|
293
|
-
},
|
|
294
|
-
oneOf: [{ required: ['edits'] }, { required: ['regex_edits'] }],
|
|
302
|
+
}),
|
|
303
|
+
],
|
|
295
304
|
},
|
|
296
305
|
}
|
|
297
306
|
}
|