dsh-ptc-plus 0.4.10 → 0.5.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 +65 -127
- package/README.md +65 -127
- package/assets/dsh-ptc-plus-banner-en.webp +0 -0
- package/assets/dsh-ptc-plus-banner-zh.webp +0 -0
- package/assets/ptc-plus-repl-workspace-en.png +0 -0
- package/assets/ptc-plus-repl-workspace-zh.png +0 -0
- package/assets/ptc-plus-settings-en.png +0 -0
- package/assets/ptc-plus-settings-zh.png +0 -0
- package/client.cjs +42702 -0
- package/cordis.patch.yml +1 -0
- package/docs/README.md +6 -2
- package/docs/adr/0005-temporary-rejected-cell-edit-transport.md +31 -198
- package/docs/adr/0008-define-agent-operating-contract.md +5 -1
- package/docs/adr/0009-bound-expensive-acceptance-default.md +2 -2
- package/docs/adr/0016-archive-resolved-review-findings.md +1 -1
- package/docs/adr/0017-track-the-latest-dsh-public-surface.md +4 -4
- package/docs/adr/0019-plugin-settings-and-kill-switch.md +1 -1
- package/docs/adr/0020-optional-cordis-tools-in-ptc-mode.md +1 -1
- package/docs/adr/0022-stage-npm-releases-with-oidc.md +4 -2
- package/docs/adr/0023-global-user-bindings.md +2 -0
- package/docs/adr/0026-persist-the-delivery-verdict-against-the-verified-candidate.md +2 -0
- package/docs/adr/0028-attach-to-the-host-ptc-execution-seam.md +25 -23
- package/docs/adr/0031-close-semantic-obligations-by-owner.md +1 -1
- package/docs/adr/0034-keep-program-values-separate-from-output-projections.md +29 -0
- package/docs/adr/0035-run-coverage-only-before-a-new-release.md +27 -0
- package/docs/adr/0036-separate-focused-development-from-delivery-verification.md +29 -0
- package/docs/adr/0037-keep-tool-hover-previews-passive.md +52 -0
- package/docs/adr/0038-freeze-session-capability-plans.md +71 -0
- package/docs/adr/0039-verify-documentation-without-runtime-suites.md +29 -0
- package/docs/adr/0040-separate-capability-configurations-from-session-observations.md +39 -0
- package/docs/adr/0041-record-cell-execution-directories.md +65 -0
- package/docs/adr/0042-persist-provider-availability-and-handback.md +41 -0
- package/docs/adr/0043-compose-capability-and-context-policies.md +37 -0
- package/docs/adr/0044-coexist-with-the-official-persistent-repl.md +35 -0
- package/docs/adr/README.md +8 -0
- package/docs/architecture.md +23 -25
- package/docs/capability-planning-components.md +93 -0
- package/docs/capability-projection.md +7 -0
- package/docs/client-ui.md +70 -23
- package/docs/client-visual-contract.md +26 -9
- package/docs/context-management.md +22 -0
- package/docs/context-optimization-plan.md +353 -0
- package/docs/context-public-interface-coverage.md +25 -0
- package/docs/durability-design.md +20 -15
- package/docs/evaluation.md +41 -6
- package/docs/evaluations/command-goat-deepseek-v4.1-flash-20261006.md +126 -0
- package/docs/evaluations/command-goat-deepseek-v4.1-flash.md +281 -0
- package/docs/installation.md +33 -10
- package/docs/program-data-plane.md +5 -3
- package/docs/publishing.md +7 -7
- package/docs/release-coverage.md +73 -0
- package/docs/release-notes.md +1 -1
- package/docs/review-procedure.md +56 -0
- package/docs/runtime-reference.md +53 -16
- package/docs/semantic-validation.md +14 -2
- package/docs/stateful-binding-updates-proposal.md +2 -2
- package/docs/user-bindings.md +1 -1
- package/docs/value-wire.md +11 -1
- package/docs/verification-optimization-work.md +26 -15
- package/docs/verification.md +30 -88
- package/index.js +146 -20
- package/internal/binding-toggle-receipt.js +24 -0
- package/internal/capability-command-receipt.js +31 -0
- package/internal/capability-environment.js +1253 -0
- package/internal/capability-plan.js +285 -0
- package/internal/capability-policy.js +96 -0
- package/internal/capability-statistics-store.js +180 -0
- package/internal/capability-statistics.js +214 -0
- package/internal/config-spec.js +89 -10
- package/internal/direct-surface-owner.js +27 -29
- package/internal/dynamic-environment-runtime.js +9 -9
- package/internal/edit-transport-owner.js +195 -140
- package/internal/execution-provider-owner.js +40 -12
- package/internal/execution-seam-compat.js +26 -8
- package/internal/kernel-worker.js +104 -32
- package/internal/native-root-dynamic.js +12 -13
- package/internal/official-repl-priority.js +51 -0
- package/internal/program-bindings.js +190 -0
- package/internal/recovery-tips.js +3 -2
- package/internal/rejected-cell-editor.js +8 -8
- package/internal/repl-observation-interest.js +11 -3
- package/internal/rpc-contract.js +1 -0
- package/internal/runtime-bridge-owner.js +275 -34
- package/internal/runtime-config.js +58 -0
- package/internal/runtime-contexts.js +74 -5
- package/internal/runtime-intrinsics.js +1 -0
- package/internal/runtime-messages.js +41 -0
- package/internal/sdk-projection.js +10 -82
- package/internal/session-cell-executor.js +42 -19
- package/internal/session-events.js +34 -0
- package/internal/session-journal-recovery.js +234 -11
- package/internal/session-journal-schema.js +6 -3
- package/internal/session-journal.js +31 -2
- package/internal/session-log-view.js +1 -1
- package/internal/session-runtime.js +119 -15
- package/internal/settings-compat.js +12 -5
- package/internal/stateful-module-compiler.js +3 -2
- package/internal/stateful-module-runtime.js +7 -3
- package/internal/stateful-root-runtime.js +9 -4
- package/internal/user-binding-authoring.js +2 -7
- package/internal/user-bindings-owner.js +19 -2
- package/internal/validated-parse-repair.js +1 -1
- package/internal/value-wire.js +68 -21
- package/internal/worker-cwd-virtualization.js +20 -18
- package/internal/worker-realm-surfaces.js +3 -3
- package/package.json +49 -30
- package/src/client-activity.js +3 -2
- package/src/client-authoring-view.js +67 -30
- package/src/client-binding-review.js +2 -1
- package/src/client-binding-toggle.js +18 -0
- package/src/client-capabilities-view.js +1555 -0
- package/src/client-capability-sort.js +29 -0
- package/src/client-copy.js +923 -8
- package/src/client-feature-gates.js +3 -0
- package/src/client-indicator-view.js +4 -6
- package/src/client-primitives.js +33 -2
- package/src/client-repl-view.js +20 -13
- package/src/client-settings-view.js +411 -41
- package/src/client-styles.js +112 -15
- package/src/client-tool-hover.js +185 -0
- package/src/client-tool-view.js +45 -9
- package/src/client-transport.js +44 -9
- package/src/client-workbench.js +6 -7
- package/src/client.js +76 -22
- package/client.js +0 -32479
|
@@ -12,6 +12,11 @@ export function createReplObservationInterest(ctx, initiallyEnabled, observe = a
|
|
|
12
12
|
for (const watcher of [...watchers]) watcher.release()
|
|
13
13
|
for (const controller of inspections) controller.abort()
|
|
14
14
|
}
|
|
15
|
+
const releaseEvents = typeof ctx.on === 'function' ? ctx.effect(() => ctx.on('session/event', session => {
|
|
16
|
+
for (const watcher of [...watchers]) {
|
|
17
|
+
if (watcher.sessionId === session.id) watcher.changed()
|
|
18
|
+
}
|
|
19
|
+
}), 'ptc-plus: model source observation changes') : undefined
|
|
15
20
|
const handler = async (endpoint, payload, signal) => {
|
|
16
21
|
if (!enabled || !['watch', 'observe'].includes(endpoint) || typeof payload?.sessionId !== 'string'
|
|
17
22
|
|| payload.sessionId.length === 0 || payload.sessionId.length > 256
|
|
@@ -32,11 +37,13 @@ export function createReplObservationInterest(ctx, initiallyEnabled, observe = a
|
|
|
32
37
|
}
|
|
33
38
|
}
|
|
34
39
|
return new Promise(resolve => {
|
|
35
|
-
const
|
|
40
|
+
const finish = value => {
|
|
36
41
|
signal.removeEventListener('abort', watcher.release)
|
|
37
42
|
watchers.delete(watcher)
|
|
38
|
-
resolve({ ok: true, value
|
|
39
|
-
}
|
|
43
|
+
resolve({ ok: true, value })
|
|
44
|
+
}
|
|
45
|
+
const watcher = { sessionId: payload.sessionId,
|
|
46
|
+
release: () => finish(null), changed: () => finish({ changed: true }) }
|
|
40
47
|
watchers.add(watcher)
|
|
41
48
|
signal.addEventListener('abort', watcher.release, { once: true })
|
|
42
49
|
if (signal.aborted) watcher.release()
|
|
@@ -62,6 +69,7 @@ export function createReplObservationInterest(ctx, initiallyEnabled, observe = a
|
|
|
62
69
|
async dispose() {
|
|
63
70
|
enabled = false
|
|
64
71
|
clear()
|
|
72
|
+
await releaseEvents?.()
|
|
65
73
|
for (const release of [...registrations]) await release()
|
|
66
74
|
if (typeof injection === 'function') await injection()
|
|
67
75
|
else await injection?.dispose?.()
|
package/internal/rpc-contract.js
CHANGED
|
@@ -17,6 +17,7 @@ const resultSchema = Schema.union([
|
|
|
17
17
|
export const RPC_CONTRACTS = Object.freeze({
|
|
18
18
|
bindings: Object.freeze({ service: 'ptcPlusBindings' }),
|
|
19
19
|
repl: Object.freeze({ service: 'ptcPlusRepl' }),
|
|
20
|
+
capabilities: Object.freeze({ service: 'ptcPlusCapabilities' }),
|
|
20
21
|
})
|
|
21
22
|
|
|
22
23
|
export function rpcDescriptor({ service }) {
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
/** Own the execution-seam takeover, per-cell lease, journal projection, and session settlement. */
|
|
2
2
|
import { AsyncLocalStorage } from 'node:async_hooks'
|
|
3
|
+
import { deepEqualJson, snapshotJsonValue } from '@deepseek-ai/dsh-util-values'
|
|
4
|
+
import { decodeValue, renderValueWire } from './value-wire.js'
|
|
5
|
+
import { valueLimitsFromConfig } from './value-wire-schema.js'
|
|
3
6
|
import { executionPolicies } from './binding-update-policy.js'
|
|
4
7
|
import { assertObjectJsonSchema, validateJsonSchemaValue } from '@deepseek-ai/dsh-tools'
|
|
5
8
|
import { normalizeBindingDescriptors } from './binding-descriptors.js'
|
|
@@ -17,11 +20,13 @@ import {
|
|
|
17
20
|
capabilityFind,
|
|
18
21
|
capabilityInspect,
|
|
19
22
|
capabilityTree,
|
|
23
|
+
createCapabilitySearcher,
|
|
20
24
|
toolCapabilityMetadata,
|
|
21
25
|
} from './program-bindings.js'
|
|
22
26
|
import { deepFreeze } from './record-utils.js'
|
|
23
|
-
import { withReplMemorySnapshot } from './repl-memory-projection.js'
|
|
27
|
+
import { REPL_MEMORY_META_KEY, withReplMemorySnapshot } from './repl-memory-projection.js'
|
|
24
28
|
import { withUserBindingDraftCapability } from './user-binding-draft-projection.js'
|
|
29
|
+
import { POST_EDIT_KEY } from './session-journal-schema.js'
|
|
25
30
|
import { generatedRunCodeDescriptionMeta } from './run-code-description.js'
|
|
26
31
|
import { BINDING_SUBMISSION } from './user-binding-authoring.js'
|
|
27
32
|
import {
|
|
@@ -71,7 +76,7 @@ const PROGRAM_CAPABILITY_METADATA = deepFreeze([
|
|
|
71
76
|
namespace: 'repl',
|
|
72
77
|
members: [{
|
|
73
78
|
name: 'state',
|
|
74
|
-
description: 'Manage named REPL checkpoints. list returns checkpoint names, not variable names. Save captures the final durable state of this cell, including subsequent mutations; it is lost if the cell becomes volatile or is discarded. Save, restore and delete take effect after cell settlement and journal confirmation, not when the receipt is awaited. Restore
|
|
79
|
+
description: 'Manage named REPL checkpoints. list returns checkpoint names, not variable names. Save requires a durable cell; a volatile save rejection leaves live bindings usable. Save captures the final durable state of this cell, including subsequent mutations; it is lost if the cell becomes volatile or is discarded. Save, restore and delete take effect after cell settlement and journal confirmation, not when the receipt is awaited. Restore discards bindings beyond the selected durable state for subsequent cells; an omitted name selects the prior durable head, or an empty REPL if none exists. Restore does not undo external effects or change enabled binding configuration; subsequent cells may remain volatile.',
|
|
75
80
|
parameters: {
|
|
76
81
|
type: 'object',
|
|
77
82
|
properties: {
|
|
@@ -128,7 +133,7 @@ const PROGRAM_CAPABILITY_METADATA = deepFreeze([
|
|
|
128
133
|
description: 'Child console output in emission order.',
|
|
129
134
|
},
|
|
130
135
|
result: {
|
|
131
|
-
description: '
|
|
136
|
+
description: 'Plugin-owned isolated execution preserves supported PTC Value V1 types and reference relationships; omitted for no return, present for explicit undefined. Native delegation and legacy upstream execution retain their original result contracts.',
|
|
132
137
|
},
|
|
133
138
|
},
|
|
134
139
|
required: ['logs'],
|
|
@@ -154,6 +159,7 @@ export function createRuntimeBridgeOwner({
|
|
|
154
159
|
toolSchemasForAgent,
|
|
155
160
|
userBindingDraftForAgent,
|
|
156
161
|
bindingSubmissionForAgent,
|
|
162
|
+
capabilityEnvironment,
|
|
157
163
|
}) {
|
|
158
164
|
const scope = new AsyncLocalStorage()
|
|
159
165
|
const childScope = new AsyncLocalStorage()
|
|
@@ -173,22 +179,27 @@ export function createRuntimeBridgeOwner({
|
|
|
173
179
|
const withInitiator = ctx.agents === undefined || typeof ctx.agents.withInitiator !== 'function'
|
|
174
180
|
? undefined
|
|
175
181
|
: (agent, operation) => ctx.agents.withInitiator(agent, operation)
|
|
176
|
-
const sessions = new SessionRuntime(sessionConfig, {
|
|
182
|
+
const sessions = new SessionRuntime(sessionConfig, {
|
|
183
|
+
withInitiator, userBindingsCwd, observeSession, readSessionLog,
|
|
184
|
+
sessionForId: id => ctx.get('sessions')?.get(id),
|
|
185
|
+
})
|
|
177
186
|
let currentConfig = sessions.config
|
|
178
187
|
const patchedDefinitions = new Map()
|
|
179
188
|
const pending = new WeakMap()
|
|
180
189
|
const nativeRunCodeHandoffs = new Set()
|
|
181
190
|
let active = true
|
|
182
|
-
const runIsolated = async (request, executionToken, depth, cellConfig, inheritedTools) => {
|
|
191
|
+
const runIsolated = async (request, executionToken, depth, cellConfig, inheritedTools, programCompletion = false) => {
|
|
183
192
|
const child = new SessionRuntime({ ...cellConfig, durableReplay: false, userBindingsEnabled: false,
|
|
184
193
|
replViewEnabled: false }, { withInitiator, userBindingsCwd })
|
|
185
194
|
childRuntimes.add(child)
|
|
186
195
|
const projected = projectBindings(request, depth, executionToken, inheritedTools, cellConfig)
|
|
187
196
|
childFinalizers.add(child)
|
|
188
197
|
try {
|
|
189
|
-
|
|
190
|
-
cwd: executionToken?.session?.header?.cwd,
|
|
191
|
-
} } }, { ...projected.request, executionToken })
|
|
198
|
+
const execution = await child.runTentative({ id: 'isolated-cell', session: { header: {
|
|
199
|
+
cwd: request.cwd ?? executionToken?.session?.header?.cwd,
|
|
200
|
+
} } }, { ...projected.request, executionToken }, { programCompletion })
|
|
201
|
+
if (execution.settlement !== undefined) child.finalize(execution.settlement, true)
|
|
202
|
+
return { result: execution.result, completion: execution.settlement?.journal.completion }
|
|
192
203
|
} finally {
|
|
193
204
|
projected.release()
|
|
194
205
|
try {
|
|
@@ -263,11 +274,12 @@ export function createRuntimeBridgeOwner({
|
|
|
263
274
|
}
|
|
264
275
|
if (languageSemantics !== 'legacy-v1') {
|
|
265
276
|
const child = await runIsolated({ ...request, program: args.code }, executionToken,
|
|
266
|
-
depth + 1, cellConfig, functions)
|
|
267
|
-
if (child.error !== undefined) {
|
|
268
|
-
throw new Error(`nested run_code failed (${child.error.kind}): ${child.error.message}`)
|
|
277
|
+
depth + 1, cellConfig, functions, true)
|
|
278
|
+
if (child.result.error !== undefined) {
|
|
279
|
+
throw new Error(`nested run_code failed (${child.result.error.kind}): ${child.result.error.message}`)
|
|
269
280
|
}
|
|
270
|
-
return { logs: child.logs, ...(child.
|
|
281
|
+
return { logs: child.result.logs, ...(child.completion.hasValue
|
|
282
|
+
? { result: decodeValue(child.completion.value, valueLimitsFromConfig(cellConfig)) } : {}) }
|
|
271
283
|
}
|
|
272
284
|
const childProjected = projectBindings(
|
|
273
285
|
{ ...request, program: args.code }, depth + 1, executionToken, functions, cellConfig,
|
|
@@ -284,7 +296,8 @@ export function createRuntimeBridgeOwner({
|
|
|
284
296
|
return { logs: child.logs, ...(child.value === undefined ? {} : { result: child.value }) }
|
|
285
297
|
}
|
|
286
298
|
|
|
287
|
-
const
|
|
299
|
+
const nativeSchemas = toolSchemasForAgent(executionToken?.agent)
|
|
300
|
+
const schemas = (capabilityEnvironment?.visibleSchemas(executionToken?.agent, nativeSchemas) ?? nativeSchemas)
|
|
288
301
|
.filter(schema => schema?.name === RUN_CODE
|
|
289
302
|
|| (schema?.name !== EDIT_RUN_CODE && typeof functions[schema?.name] === 'function'))
|
|
290
303
|
const emptyObjectTools = new Set(schemas.flatMap(schema => (
|
|
@@ -294,20 +307,30 @@ export function createRuntimeBridgeOwner({
|
|
|
294
307
|
)))
|
|
295
308
|
const projected = bindingDescriptors.namespaces.map((binding) => {
|
|
296
309
|
const wrapped = Object.create(null)
|
|
297
|
-
|
|
310
|
+
const members = binding.global === 'tools'
|
|
311
|
+
? capabilityEnvironment?.projectMembers(executionToken?.agent, binding.members) ?? binding.members
|
|
312
|
+
: binding.members
|
|
313
|
+
for (const key of members) {
|
|
314
|
+
const original = (...args) => binding.functions[key](...args)
|
|
315
|
+
const invoke = binding.global === 'tools'
|
|
316
|
+
? capabilityEnvironment?.adaptFunction(executionToken?.agent, key, original) ?? original
|
|
317
|
+
: original
|
|
298
318
|
Object.defineProperty(wrapped, key, {
|
|
299
319
|
enumerable: true,
|
|
300
320
|
value: async (...args) => {
|
|
301
321
|
ensureLease()
|
|
302
|
-
return binding.
|
|
322
|
+
return binding.global === 'tools' && key === EDIT_RUN_CODE
|
|
323
|
+
? scope.run(executionToken, () => invoke(...args))
|
|
324
|
+
: invoke(...args)
|
|
303
325
|
},
|
|
304
326
|
})
|
|
305
327
|
}
|
|
306
328
|
const emptyObjectMembers = binding.global === 'tools'
|
|
307
|
-
?
|
|
329
|
+
? members.filter(member => emptyObjectTools.has(member))
|
|
308
330
|
: []
|
|
309
331
|
return {
|
|
310
332
|
...binding,
|
|
333
|
+
members,
|
|
311
334
|
functions: wrapped,
|
|
312
335
|
...(binding.global === 'tools' ? { emptyObjectMembers } : {}),
|
|
313
336
|
}
|
|
@@ -318,12 +341,14 @@ export function createRuntimeBridgeOwner({
|
|
|
318
341
|
: []
|
|
319
342
|
)))
|
|
320
343
|
const metadata = Object.freeze([
|
|
321
|
-
...toolCapabilityMetadata(schemas, annotations),
|
|
344
|
+
...(capabilityEnvironment?.toolMetadata(executionToken?.agent, toolCapabilityMetadata(schemas, annotations), schemas) ?? toolCapabilityMetadata(schemas, annotations)),
|
|
345
|
+
...(capabilityEnvironment?.metadata(executionToken?.agent) ?? []),
|
|
322
346
|
...PROGRAM_CAPABILITY_METADATA.map(entry => entry.namespace === 'code'
|
|
323
347
|
&& cellConfig.userBindingsEnabled === true
|
|
324
348
|
? { ...entry, members: [...entry.members, BINDING_SUBMISSION] }
|
|
325
349
|
: entry),
|
|
326
350
|
])
|
|
351
|
+
let searchCapabilities
|
|
327
352
|
projected.push(namespace('capabilities', {
|
|
328
353
|
tree: async value => {
|
|
329
354
|
if (value !== undefined) throw new TypeError('capabilities.tree does not accept arguments')
|
|
@@ -337,11 +362,24 @@ export function createRuntimeBridgeOwner({
|
|
|
337
362
|
},
|
|
338
363
|
inspect: async value => {
|
|
339
364
|
ensureLease()
|
|
340
|
-
if (value === undefined)
|
|
365
|
+
if (value === undefined) {
|
|
366
|
+
const result = capabilityInspect(metadata)
|
|
367
|
+
capabilityEnvironment?.explored(executionToken?.agent, result)
|
|
368
|
+
return result
|
|
369
|
+
}
|
|
341
370
|
if (value === null || typeof value !== 'object' || Array.isArray(value)) {
|
|
342
371
|
throw new TypeError('capabilities.inspect expects an object')
|
|
343
372
|
}
|
|
344
|
-
|
|
373
|
+
const result = capabilityInspect(metadata, value.symbols, value.budget)
|
|
374
|
+
capabilityEnvironment?.explored(executionToken?.agent, result)
|
|
375
|
+
return result
|
|
376
|
+
},
|
|
377
|
+
search: async value => {
|
|
378
|
+
ensureLease()
|
|
379
|
+
searchCapabilities ??= createCapabilitySearcher(metadata)
|
|
380
|
+
const result = searchCapabilities(value)
|
|
381
|
+
capabilityEnvironment?.explored(executionToken?.agent, result)
|
|
382
|
+
return result
|
|
345
383
|
},
|
|
346
384
|
}, 'CapabilityExplorationError', 'operation'))
|
|
347
385
|
projected.push(namespace('code', {
|
|
@@ -367,6 +405,10 @@ export function createRuntimeBridgeOwner({
|
|
|
367
405
|
const output = definition.output
|
|
368
406
|
const ownPresentationMeta = Object.getOwnPropertyDescriptor(output, 'presentationMeta')
|
|
369
407
|
const patchedPresentationMeta = (args, value) => {
|
|
408
|
+
const projectedCurrent = scope.getStore()
|
|
409
|
+
if (projectedCurrent !== undefined) {
|
|
410
|
+
projectedCurrent.presentationMetaCalls = (projectedCurrent.presentationMetaCalls ?? 0) + 1
|
|
411
|
+
}
|
|
370
412
|
const prototype = Object.getPrototypeOf(output)
|
|
371
413
|
const originalPresentationMeta = ownPresentationMeta === undefined
|
|
372
414
|
? prototype === null ? undefined : Reflect.get(prototype, 'presentationMeta', output)
|
|
@@ -374,8 +416,15 @@ export function createRuntimeBridgeOwner({
|
|
|
374
416
|
? ownPresentationMeta.value
|
|
375
417
|
: ownPresentationMeta.get?.call(output)
|
|
376
418
|
const base = originalPresentationMeta === undefined
|
|
377
|
-
|
|
378
|
-
|
|
419
|
+
// Installing a projector replaces an optional Host callback with a
|
|
420
|
+
// required JSON-producing callback, including policy reprojection
|
|
421
|
+
// after the execution scope has ended. An empty object conveys no
|
|
422
|
+
// computation evidence; a stale settlement must never fill that gap.
|
|
423
|
+
? {}
|
|
424
|
+
: snapshotJsonValue(originalPresentationMeta.call(output, args, value))
|
|
425
|
+
// An invalid upstream projection is still the Host's output failure;
|
|
426
|
+
// adding plugin metadata must not make it appear valid.
|
|
427
|
+
if (base === undefined) return undefined
|
|
379
428
|
if (!active) return base
|
|
380
429
|
const current = scope.getStore()
|
|
381
430
|
const settlement = current?.settlement
|
|
@@ -388,9 +437,50 @@ export function createRuntimeBridgeOwner({
|
|
|
388
437
|
if (settlement.userBindings !== undefined) {
|
|
389
438
|
meta = withUserBindingsSnapshot(meta, settlement.userBindings)
|
|
390
439
|
}
|
|
440
|
+
if (current.postEdit?.provenance !== undefined) {
|
|
441
|
+
meta = { ...meta, [POST_EDIT_KEY]: current.postEdit.provenance }
|
|
442
|
+
}
|
|
391
443
|
meta = generatedRunCodeDescriptionMeta(args, meta)
|
|
392
444
|
meta = withReplMemorySnapshot(meta, settlement.replMemory, presentationGeneration)
|
|
393
|
-
|
|
445
|
+
if (current.postEdit?.provenance?.meta?.[REPL_MEMORY_META_KEY] !== undefined) {
|
|
446
|
+
meta = { ...meta,
|
|
447
|
+
[REPL_MEMORY_META_KEY]: current.postEdit.provenance.meta[REPL_MEMORY_META_KEY] }
|
|
448
|
+
}
|
|
449
|
+
meta = withDraftCapability(meta, current)
|
|
450
|
+
return capabilityEnvironment?.complete(current, { meta }).meta ?? meta
|
|
451
|
+
}
|
|
452
|
+
const ownProjectContent = Object.getOwnPropertyDescriptor(definition, 'projectContent')
|
|
453
|
+
const patchedProjectContent = (exec, result) => {
|
|
454
|
+
const prototype = Object.getPrototypeOf(definition)
|
|
455
|
+
const originalProjectContent = ownProjectContent === undefined
|
|
456
|
+
? prototype === null ? undefined : Reflect.get(prototype, 'projectContent', definition)
|
|
457
|
+
: Object.hasOwn(ownProjectContent, 'value')
|
|
458
|
+
? ownProjectContent.value : ownProjectContent.get?.call(definition)
|
|
459
|
+
const original = originalProjectContent?.call(definition, exec, result)
|
|
460
|
+
const current = active ? pending.get(exec) : undefined
|
|
461
|
+
const derived = current?.derivedExecution
|
|
462
|
+
// Some public Host implementations omit the metadata projector for a
|
|
463
|
+
// nested success. Capture its canonical value before policy; the private
|
|
464
|
+
// relation is admitted only if policy retains that same frozen value.
|
|
465
|
+
if (current?.deferredSettlement?.current === current && derived !== undefined
|
|
466
|
+
&& current.exec === exec && exec.token !== undefined && exec.parent !== undefined
|
|
467
|
+
&& current.id === sessionId(exec.agent) && derived.agent === exec.agent
|
|
468
|
+
&& derived.callId === exec.callId && derived.rootCallId === exec.rootCallId
|
|
469
|
+
&& derived.parent === exec.parent && deepEqualJson(derived.arguments, exec.arguments)
|
|
470
|
+
&& current.presentationMetaCalls === undefined && result.isError === false
|
|
471
|
+
&& result.value !== null && typeof result.value === 'object'
|
|
472
|
+
&& Object.isFrozen(result.value) && result.meta?.[JOURNAL_KEY] === undefined
|
|
473
|
+
&& current.settlement !== undefined) {
|
|
474
|
+
const metadata = scope.run(current, () => patchedPresentationMeta(exec.arguments, result.value))
|
|
475
|
+
if (metadata?.[JOURNAL_KEY] !== undefined) {
|
|
476
|
+
current.deferredSettlement.projection = { exec, token: exec.token,
|
|
477
|
+
value: result.value, meta: snapshotJsonValue(result.meta), metadata,
|
|
478
|
+
presentationMetaCalls: current.presentationMetaCalls }
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
const presentation = active ? pending.get(exec)?.postEdit?.presentation : undefined
|
|
482
|
+
if (presentation === undefined) return original
|
|
483
|
+
return [...original ?? result.content, ...presentation.content]
|
|
394
484
|
}
|
|
395
485
|
const ownExecute = Object.getOwnPropertyDescriptor(definition, 'execute')
|
|
396
486
|
const originalExecute = definition.execute
|
|
@@ -409,6 +499,10 @@ export function createRuntimeBridgeOwner({
|
|
|
409
499
|
value: patchedPresentationMeta,
|
|
410
500
|
})
|
|
411
501
|
presentationPatched = true
|
|
502
|
+
Object.defineProperty(definition, 'projectContent', {
|
|
503
|
+
configurable: true, enumerable: ownProjectContent?.enumerable ?? true,
|
|
504
|
+
writable: true, value: patchedProjectContent,
|
|
505
|
+
})
|
|
412
506
|
if (patchedExecute !== undefined) {
|
|
413
507
|
Object.defineProperty(definition, 'execute', {
|
|
414
508
|
configurable: true,
|
|
@@ -422,10 +516,20 @@ export function createRuntimeBridgeOwner({
|
|
|
422
516
|
output,
|
|
423
517
|
ownPresentationMeta,
|
|
424
518
|
patchedPresentationMeta,
|
|
519
|
+
ownProjectContent,
|
|
520
|
+
patchedProjectContent,
|
|
425
521
|
ownExecute,
|
|
426
522
|
patchedExecute,
|
|
427
523
|
})
|
|
428
524
|
} catch (error) {
|
|
525
|
+
if (definition.projectContent === patchedProjectContent) {
|
|
526
|
+
if (ownProjectContent === undefined) delete definition.projectContent
|
|
527
|
+
else Object.defineProperty(definition, 'projectContent', ownProjectContent)
|
|
528
|
+
}
|
|
529
|
+
if (patchedExecute !== undefined && definition.execute === patchedExecute) {
|
|
530
|
+
if (ownExecute === undefined) delete definition.execute
|
|
531
|
+
else Object.defineProperty(definition, 'execute', ownExecute)
|
|
532
|
+
}
|
|
429
533
|
if (presentationPatched && output.presentationMeta === patchedPresentationMeta) {
|
|
430
534
|
if (ownPresentationMeta === undefined) delete output.presentationMeta
|
|
431
535
|
else Object.defineProperty(output, 'presentationMeta', ownPresentationMeta)
|
|
@@ -440,6 +544,7 @@ export function createRuntimeBridgeOwner({
|
|
|
440
544
|
if (!active || !child.active) return Promise.reject(new Error('PTC execution lease expired'))
|
|
441
545
|
if (executionPolicies(child.cellConfig).languageSemantics !== 'legacy-v1') {
|
|
442
546
|
return runIsolated(request, child.executionToken, child.depth, child.cellConfig, child.functions)
|
|
547
|
+
.then(execution => execution.result)
|
|
443
548
|
}
|
|
444
549
|
}
|
|
445
550
|
if (!active) return seam.runUpstream(request)
|
|
@@ -451,22 +556,93 @@ export function createRuntimeBridgeOwner({
|
|
|
451
556
|
executionToken: current,
|
|
452
557
|
...(current.userBindings === undefined ? {} : { userBindings: current.userBindings }),
|
|
453
558
|
})
|
|
454
|
-
.then((execution) => {
|
|
559
|
+
.then(async (execution) => {
|
|
455
560
|
current.settlement = execution.settlement
|
|
456
|
-
|
|
561
|
+
const pendingEdit = current.pendingEdit
|
|
562
|
+
if (pendingEdit === undefined) return execution.result
|
|
563
|
+
if (!pendingEdit.confirmed || current.signal.aborted) {
|
|
564
|
+
pendingEdit.finish(false)
|
|
565
|
+
return execution.result
|
|
566
|
+
}
|
|
567
|
+
try {
|
|
568
|
+
const postEdit = await pendingEdit.dispatch(current.signal, current.exec)
|
|
569
|
+
current.postEdit = postEdit
|
|
570
|
+
for (const context of postEdit.presentation?.additionalContexts ?? []) {
|
|
571
|
+
current.exec.deferContext?.(context)
|
|
572
|
+
}
|
|
573
|
+
if (postEdit.presentation?.concludesTurn === true && execution.result.error === undefined) {
|
|
574
|
+
current.exec.concludeTurn?.()
|
|
575
|
+
}
|
|
576
|
+
const outcome = postEdit.outcome
|
|
577
|
+
const value = postEdit.provenance?.meta?.[JOURNAL_KEY]?.completion
|
|
578
|
+
const hasRenderedContent = postEdit.presentation?.content?.length > 0
|
|
579
|
+
let valueText = ''
|
|
580
|
+
if (!hasRenderedContent && value?.kind === 'return' && value.hasValue) {
|
|
581
|
+
try {
|
|
582
|
+
valueText = `; value: ${renderValueWire(value.value, {
|
|
583
|
+
...valueLimitsFromConfig(current.submission?.config ?? currentConfig),
|
|
584
|
+
maxStringBytes: 2048,
|
|
585
|
+
})}`
|
|
586
|
+
} catch {
|
|
587
|
+
valueText = '; value omitted from preview'
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
const targetDescription = pendingEdit.targetDescription ?? `run_code call ${pendingEdit.targetCallSeq}`
|
|
591
|
+
const status = outcome.edited
|
|
592
|
+
? `edit_run_code settled${outcome.error === undefined ? '' : ' with execution error'} (target ${targetDescription})`
|
|
593
|
+
: `edit_run_code did not execute the accepted revision (target ${targetDescription})`
|
|
594
|
+
const detail = [
|
|
595
|
+
...(hasRenderedContent || !Array.isArray(outcome.logs) ? [] : outcome.logs),
|
|
596
|
+
...(!hasRenderedContent && typeof outcome.error === 'string' ? [outcome.error] : []),
|
|
597
|
+
...(!hasRenderedContent && typeof outcome.reason === 'string' ? [outcome.reason] : []),
|
|
598
|
+
].filter(item => typeof item === 'string').join('\n')
|
|
599
|
+
return { ...execution.result,
|
|
600
|
+
logs: [...execution.result.logs, `${status}${valueText}${detail ? `: ${detail}` : ''}`] }
|
|
601
|
+
} catch (error) {
|
|
602
|
+
pendingEdit.finish(false)
|
|
603
|
+
return { ...execution.result,
|
|
604
|
+
logs: [...execution.result.logs,
|
|
605
|
+
`edit_run_code failed after acceptance: ${error instanceof Error ? error.message : String(error)}`] }
|
|
606
|
+
}
|
|
457
607
|
})
|
|
458
608
|
.finally(projected.release)
|
|
459
609
|
}
|
|
460
610
|
|
|
461
611
|
const releaseSeam = seam.installExecute(patchedRun)
|
|
462
612
|
|
|
613
|
+
const ownedDerivedScope = (exec, executionArguments = exec.arguments) => {
|
|
614
|
+
const inherited = scope.getStore()
|
|
615
|
+
const derived = inherited?.derivedExecution
|
|
616
|
+
if (inherited?.deferredSettlement === undefined
|
|
617
|
+
|| inherited.id !== sessionId(exec.agent) || derived?.agent !== exec.agent
|
|
618
|
+
|| derived.callId !== exec.callId || derived.rootCallId !== exec.rootCallId
|
|
619
|
+
|| derived.parent !== exec.parent || exec.name !== RUN_CODE
|
|
620
|
+
|| !deepEqualJson(derived.arguments, executionArguments)) return undefined
|
|
621
|
+
return inherited
|
|
622
|
+
}
|
|
623
|
+
|
|
463
624
|
const withSubmission = async (exec, operation) => {
|
|
464
625
|
const id = sessionId(exec.agent)
|
|
465
626
|
const inherited = scope.getStore()
|
|
466
|
-
|
|
627
|
+
const ownsDerived = ownedDerivedScope(exec) !== undefined
|
|
628
|
+
if ((exec.parent !== undefined && !ownsDerived) || id === undefined
|
|
629
|
+
|| (inherited?.exec === exec && inherited.submission?.sessionId === id)) return operation()
|
|
467
630
|
const submission = sessions.beginSubmission({ id }, exec.signal)
|
|
631
|
+
const composite = ownsDerived
|
|
632
|
+
? {
|
|
633
|
+
persistedCallSeq: inherited.persistedCallSeq,
|
|
634
|
+
sourceCallSeq: inherited.sourceCallSeq,
|
|
635
|
+
sessionLog: inherited.sessionLog,
|
|
636
|
+
deferredSettlement: inherited.deferredSettlement,
|
|
637
|
+
derivedExecution: inherited.derivedExecution,
|
|
638
|
+
}
|
|
639
|
+
: {}
|
|
468
640
|
try {
|
|
469
|
-
|
|
641
|
+
// Only reentry for this exact execution shares admission. Background
|
|
642
|
+
// continuations can inherit a settled execution's asynchronous context.
|
|
643
|
+
// Only proved derived edits retain composite source and settlement under
|
|
644
|
+
// a fresh admission; other roots own a fresh log and no child handoff.
|
|
645
|
+
return await scope.run({ ...composite, exec, submission }, () => childScope.run(undefined, operation))
|
|
470
646
|
} finally {
|
|
471
647
|
sessions.releaseSubmission(submission)
|
|
472
648
|
}
|
|
@@ -479,6 +655,25 @@ export function createRuntimeBridgeOwner({
|
|
|
479
655
|
return sessionLog
|
|
480
656
|
}
|
|
481
657
|
|
|
658
|
+
const readNestedDispatchLog = async (session, signal) => {
|
|
659
|
+
const inherited = scope.getStore()
|
|
660
|
+
if (inherited === undefined || inherited.session !== session
|
|
661
|
+
|| inherited.signal.aborted || signal?.aborted) {
|
|
662
|
+
throw new Error('ptc-plus: nested edit has no active root run_code cell')
|
|
663
|
+
}
|
|
664
|
+
return readSessionLog(session, signal)
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
const rootEditScope = exec => {
|
|
668
|
+
const current = scope.getStore()
|
|
669
|
+
if (!active || current === undefined || childScope.getStore() !== undefined
|
|
670
|
+
|| current.deferredSettlement !== undefined
|
|
671
|
+
|| current.callId !== exec.rootCallId || current.agent !== exec.agent
|
|
672
|
+
|| current.session !== exec.agent?.session || current.signal.aborted
|
|
673
|
+
|| exec.signal?.aborted) return undefined
|
|
674
|
+
return current
|
|
675
|
+
}
|
|
676
|
+
|
|
482
677
|
return Object.freeze({
|
|
483
678
|
config: sessions.config,
|
|
484
679
|
reconfigure(nextConfig) {
|
|
@@ -488,8 +683,18 @@ export function createRuntimeBridgeOwner({
|
|
|
488
683
|
observeRepl(id, memory, signal) { return sessions.observe(id, memory, signal) },
|
|
489
684
|
withSubmission,
|
|
490
685
|
readSubmissionLog,
|
|
686
|
+
readNestedDispatchLog,
|
|
687
|
+
prepareAgent(agent) { patchRunCodeDefinition(agent) },
|
|
688
|
+
canScheduleEdit(exec) { return rootEditScope(exec) !== undefined },
|
|
689
|
+
scheduleEdit(exec, pendingEdit) {
|
|
690
|
+
const current = rootEditScope(exec)
|
|
691
|
+
if (current === undefined || current.pendingEdit !== undefined) return false
|
|
692
|
+
current.pendingEdit = pendingEdit
|
|
693
|
+
return true
|
|
694
|
+
},
|
|
491
695
|
// A composite tool's outer result owns the final durability decision.
|
|
492
|
-
async executeTentative(callSeq, operation, sessionLog) {
|
|
696
|
+
async executeTentative(callSeq, sourceCallSeq, operation, sessionLog, derivedExecution) {
|
|
697
|
+
const id = scope.getStore()?.id
|
|
493
698
|
const settlement = {
|
|
494
699
|
current: undefined,
|
|
495
700
|
innerConfirmed: false,
|
|
@@ -504,22 +709,27 @@ export function createRuntimeBridgeOwner({
|
|
|
504
709
|
}
|
|
505
710
|
try {
|
|
506
711
|
const result = await scope.run({
|
|
507
|
-
|
|
712
|
+
id,
|
|
508
713
|
...(callSeq === undefined ? {} : { persistedCallSeq: callSeq }),
|
|
714
|
+
...(sourceCallSeq === undefined ? {} : { sourceCallSeq }),
|
|
509
715
|
...(sessionLog === undefined ? {} : { sessionLog }),
|
|
510
716
|
deferredSettlement: settlement,
|
|
717
|
+
derivedExecution,
|
|
511
718
|
}, operation)
|
|
512
|
-
return Object.freeze({ result, finalize
|
|
719
|
+
return Object.freeze({ result, finalize,
|
|
720
|
+
...(settlement.metadata === undefined ? {} : { metadata: settlement.metadata }) })
|
|
513
721
|
} catch (error) {
|
|
514
722
|
finalize(false)
|
|
515
723
|
throw error
|
|
516
724
|
}
|
|
517
725
|
},
|
|
518
726
|
async handleExecute(exec, next, executionArguments = exec.arguments, userBindings = undefined) {
|
|
519
|
-
|
|
727
|
+
const ownsDerived = ownedDerivedScope(exec, executionArguments) !== undefined
|
|
728
|
+
if (exec.parent !== undefined && !ownsDerived) return scope.run(undefined, next)
|
|
520
729
|
return withSubmission(exec, async () => {
|
|
521
730
|
const id = sessionId(exec.agent)
|
|
522
731
|
if (id === undefined) return next()
|
|
732
|
+
await capabilityEnvironment?.prepare(exec.agent)
|
|
523
733
|
patchRunCodeDefinition(exec.agent)
|
|
524
734
|
const inherited = scope.getStore()
|
|
525
735
|
const persistedCallSeq = inherited?.persistedCallSeq
|
|
@@ -528,12 +738,16 @@ export function createRuntimeBridgeOwner({
|
|
|
528
738
|
submission: inherited?.submission,
|
|
529
739
|
callId: String(exec.callId),
|
|
530
740
|
...(persistedCallSeq === undefined ? {} : { persistedCallSeq }),
|
|
741
|
+
...(inherited?.sourceCallSeq === undefined ? {} : { sourceCallSeq: inherited.sourceCallSeq }),
|
|
531
742
|
...(inherited?.deferredSettlement === undefined
|
|
532
743
|
? {}
|
|
533
|
-
: { deferredSettlement: inherited.deferredSettlement
|
|
744
|
+
: { deferredSettlement: inherited.deferredSettlement,
|
|
745
|
+
derivedExecution: inherited.derivedExecution }),
|
|
534
746
|
session: exec.agent?.session,
|
|
747
|
+
signal: exec.signal,
|
|
535
748
|
sessionLog: await readSubmissionLog(exec.agent?.session, exec.signal),
|
|
536
749
|
agent: exec.agent,
|
|
750
|
+
exec,
|
|
537
751
|
executionArguments,
|
|
538
752
|
...(userBindings === undefined ? {} : { userBindings }),
|
|
539
753
|
}
|
|
@@ -554,26 +768,47 @@ export function createRuntimeBridgeOwner({
|
|
|
554
768
|
if (settlement.userBindings !== undefined) {
|
|
555
769
|
meta = withUserBindingsSnapshot(meta, settlement.userBindings)
|
|
556
770
|
}
|
|
771
|
+
if (current.postEdit?.provenance !== undefined) {
|
|
772
|
+
meta = { ...meta, [POST_EDIT_KEY]: current.postEdit.provenance }
|
|
773
|
+
}
|
|
557
774
|
meta = withReplMemorySnapshot(meta, settlement.replMemory, presentationGeneration)
|
|
775
|
+
if (current.postEdit?.provenance?.meta?.[REPL_MEMORY_META_KEY] !== undefined) {
|
|
776
|
+
meta = { ...meta,
|
|
777
|
+
[REPL_MEMORY_META_KEY]: current.postEdit.provenance.meta[REPL_MEMORY_META_KEY] }
|
|
778
|
+
}
|
|
558
779
|
meta = withDraftCapability(meta, current)
|
|
559
|
-
return { ...result, meta }
|
|
780
|
+
return capabilityEnvironment?.complete(current, { ...result, meta }) ?? { ...result, meta }
|
|
560
781
|
}
|
|
561
782
|
return result
|
|
562
783
|
})
|
|
563
784
|
})
|
|
564
785
|
},
|
|
565
786
|
handleResult(exec, result) {
|
|
566
|
-
if (exec.parent !== undefined) return
|
|
787
|
+
if (exec.parent !== undefined && !pending.has(exec)) return
|
|
567
788
|
const id = sessionId(exec.agent)
|
|
568
789
|
if (id === undefined) return
|
|
569
790
|
const current = pending.get(exec)
|
|
570
791
|
pending.delete(exec)
|
|
571
792
|
const settlement = current?.settlement
|
|
572
793
|
if (settlement === undefined) {
|
|
794
|
+
current?.pendingEdit?.finish(false)
|
|
573
795
|
sessions.noteNoop(id, current?.sessionLog, exec.callId)
|
|
574
796
|
return
|
|
575
797
|
}
|
|
576
|
-
const
|
|
798
|
+
const deferred = current.deferredSettlement
|
|
799
|
+
const projection = deferred?.projection
|
|
800
|
+
const derived = current.derivedExecution
|
|
801
|
+
const privateMetadata = projection !== undefined && projection.exec === exec
|
|
802
|
+
&& deferred.current === current && current.exec === exec && current.id === id
|
|
803
|
+
&& derived?.agent === exec.agent && derived.callId === exec.callId
|
|
804
|
+
&& derived.rootCallId === exec.rootCallId && derived.parent === exec.parent
|
|
805
|
+
&& deepEqualJson(derived.arguments, exec.arguments)
|
|
806
|
+
&& projection.token === exec.token && projection.value === result?.value
|
|
807
|
+
&& result.isError === false && deepEqualJson(projection.meta, result.meta)
|
|
808
|
+
&& projection.presentationMetaCalls === current.presentationMetaCalls
|
|
809
|
+
? projection.metadata : undefined
|
|
810
|
+
if (deferred !== undefined) deferred.metadata = privateMetadata
|
|
811
|
+
const meta = privateMetadata ?? result?.meta
|
|
577
812
|
const confirmed = meta !== null && typeof meta === 'object' && !Array.isArray(meta)
|
|
578
813
|
&& Object.hasOwn(meta, JOURNAL_KEY)
|
|
579
814
|
&& journalsEqual(meta[JOURNAL_KEY], settlement.journal)
|
|
@@ -592,6 +827,8 @@ export function createRuntimeBridgeOwner({
|
|
|
592
827
|
return
|
|
593
828
|
}
|
|
594
829
|
sessions.finalize(settlement, confirmed)
|
|
830
|
+
current.pendingEdit?.finish(confirmed && current.postEdit?.provenance !== undefined
|
|
831
|
+
&& deepEqualJson(meta?.[POST_EDIT_KEY], current.postEdit.provenance))
|
|
595
832
|
},
|
|
596
833
|
disposeAgent(agent) {
|
|
597
834
|
return sessions.disposeSession(sessionId(agent) ?? String(agent.id))
|
|
@@ -620,6 +857,10 @@ export function createRuntimeBridgeOwner({
|
|
|
620
857
|
if (patched.ownPresentationMeta === undefined) delete patched.output.presentationMeta
|
|
621
858
|
else Object.defineProperty(patched.output, 'presentationMeta', patched.ownPresentationMeta)
|
|
622
859
|
}
|
|
860
|
+
if (patched.definition.projectContent === patched.patchedProjectContent) {
|
|
861
|
+
if (patched.ownProjectContent === undefined) delete patched.definition.projectContent
|
|
862
|
+
else Object.defineProperty(patched.definition, 'projectContent', patched.ownProjectContent)
|
|
863
|
+
}
|
|
623
864
|
if (patched.patchedExecute !== undefined
|
|
624
865
|
&& patched.definition.execute === patched.patchedExecute) {
|
|
625
866
|
if (patched.ownExecute === undefined) delete patched.definition.execute
|