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
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
const CATEGORIES = new Set(['tool', 'skill', 'resource', 'resource-template', 'task'])
|
|
2
|
+
const OUTCOMES = new Set(['complete', 'failed', 'cancelled', 'unknown'])
|
|
3
|
+
const USE_EVIDENCE = new Map([
|
|
4
|
+
['tool', 'host-execution-result'], ['task', 'host-execution-result'], ['skill', 'skill-body-accepted'],
|
|
5
|
+
['resource', 'resource-access'], ['resource-template', 'resource-access'],
|
|
6
|
+
])
|
|
7
|
+
|
|
8
|
+
function fail(label) { throw new TypeError(`ptc-plus: invalid capability statistics ${label}`) }
|
|
9
|
+
function record(value, label) {
|
|
10
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) fail(label)
|
|
11
|
+
return value
|
|
12
|
+
}
|
|
13
|
+
function identity(value, label) {
|
|
14
|
+
if (typeof value !== 'string' || !value.trim() || value.length > 4096) fail(label)
|
|
15
|
+
return value
|
|
16
|
+
}
|
|
17
|
+
function integer(value, label, minimum = 0) {
|
|
18
|
+
if (!Number.isSafeInteger(value) || value < minimum) fail(label)
|
|
19
|
+
return value
|
|
20
|
+
}
|
|
21
|
+
function key(value) { return JSON.stringify(value) }
|
|
22
|
+
function orderSamples(a, b) { return b.eligibleOrder - a.eligibleOrder }
|
|
23
|
+
function freeze(value) {
|
|
24
|
+
if (value && typeof value === 'object') {
|
|
25
|
+
for (const item of Object.values(value)) freeze(item)
|
|
26
|
+
Object.freeze(value)
|
|
27
|
+
}
|
|
28
|
+
return value
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** Bounds are explicit calibration inputs; no observation, clock or process directory is inferred. */
|
|
32
|
+
export function createCapabilityStatistics(configuration) {
|
|
33
|
+
const options = record(configuration, 'configuration')
|
|
34
|
+
const limits = {}
|
|
35
|
+
for (const name of ['windowSize', 'maxFamilies', 'maxScopes', 'maxCapabilitiesPerFamily']) limits[name] = integer(options[name], name, 1)
|
|
36
|
+
return freeze({ schema: 'ptc-capability-statistics/v1', status: 'usable', limits, families: [], windows: [] })
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function observation(raw) {
|
|
40
|
+
const value = record(raw, 'availability observation')
|
|
41
|
+
const category = value.category
|
|
42
|
+
if (!CATEGORIES.has(category)) fail('category')
|
|
43
|
+
if (!['full', 'on-demand', 'host'].includes(value.disclosure)) fail('availability disclosure')
|
|
44
|
+
const useEvidence = value.useEvidence ?? null
|
|
45
|
+
if (useEvidence !== null && useEvidence !== USE_EVIDENCE.get(category)) fail('owner use evidence')
|
|
46
|
+
const outcome = useEvidence === null ? null : value.outcome ?? 'unknown'
|
|
47
|
+
if (outcome !== null && !OUTCOMES.has(outcome)) fail('owner outcome evidence')
|
|
48
|
+
return {
|
|
49
|
+
workspaceId: identity(value.workspaceId, 'workspace identity'),
|
|
50
|
+
id: identity(value.id, 'capability identity'), revision: identity(value.revision, 'capability revision'), category,
|
|
51
|
+
disclosure: value.disclosure, planRevision: identity(value.planRevision, 'plan revision'),
|
|
52
|
+
used: useEvidence !== null, outcome,
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function sampleObservation(value) {
|
|
57
|
+
const item = record(value, 'retained observation')
|
|
58
|
+
identity(item.workspaceId, 'retained workspace identity')
|
|
59
|
+
identity(item.id, 'retained capability identity')
|
|
60
|
+
identity(item.revision, 'retained capability revision')
|
|
61
|
+
if (!CATEGORIES.has(item.category) || typeof item.used !== 'boolean' || !Array.isArray(item.exposures) || item.exposures.length < 1) fail('retained evidence')
|
|
62
|
+
if (!Array.isArray(item.outcomes) || item.outcomes.some(outcome => !OUTCOMES.has(outcome))
|
|
63
|
+
|| new Set(item.outcomes).size !== item.outcomes.length || item.used !== (item.outcomes.length > 0)) fail('retained outcomes')
|
|
64
|
+
for (const exposure of item.exposures) {
|
|
65
|
+
record(exposure, 'retained exposure')
|
|
66
|
+
if (!['full', 'on-demand', 'host'].includes(exposure.disclosure)) fail('retained disclosure')
|
|
67
|
+
identity(exposure.planRevision, 'retained plan revision')
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** Validate retained state before it can supply an automatic-allocation denominator. */
|
|
72
|
+
export function validateCapabilityStatistics(state) {
|
|
73
|
+
const value = record(state, 'state')
|
|
74
|
+
if (value.schema !== 'ptc-capability-statistics/v1' || !['usable', 'capacity-exceeded'].includes(value.status)) fail('state schema or status')
|
|
75
|
+
const template = createCapabilityStatistics(value.limits)
|
|
76
|
+
if (!Array.isArray(value.families) || !Array.isArray(value.windows)
|
|
77
|
+
|| value.families.length > template.limits.maxFamilies || value.windows.length > template.limits.maxScopes) fail('state bounds')
|
|
78
|
+
const familyKeys = new Set()
|
|
79
|
+
const orders = new Set()
|
|
80
|
+
for (const family of value.families) {
|
|
81
|
+
record(family, 'retained family')
|
|
82
|
+
const familyKey = key([identity(family.userId, 'user identity'), identity(family.familyId, 'family identity')])
|
|
83
|
+
if (familyKeys.has(familyKey)) fail('duplicate family')
|
|
84
|
+
familyKeys.add(familyKey)
|
|
85
|
+
integer(family.observationRevision, 'observation revision')
|
|
86
|
+
if (!['active', 'settled', 'unknown'].includes(family.settlement)) fail('family settlement')
|
|
87
|
+
if (family.eligibleOrder !== null) {
|
|
88
|
+
integer(family.eligibleOrder, 'qualification order', 1)
|
|
89
|
+
const orderKey = key([family.userId, family.eligibleOrder])
|
|
90
|
+
if (orders.has(orderKey)) fail('duplicate qualification order')
|
|
91
|
+
orders.add(orderKey)
|
|
92
|
+
} else if (family.settlement === 'settled') fail('settled family without qualification order')
|
|
93
|
+
if (!Array.isArray(family.observations) || family.observations.length > value.limits.maxCapabilitiesPerFamily) fail('family observation bounds')
|
|
94
|
+
const observationKeys = new Set()
|
|
95
|
+
for (const item of family.observations) {
|
|
96
|
+
sampleObservation(item)
|
|
97
|
+
const observationKey = key([item.workspaceId, item.id, item.revision])
|
|
98
|
+
if (observationKeys.has(observationKey)) fail('duplicate observation')
|
|
99
|
+
observationKeys.add(observationKey)
|
|
100
|
+
if (item.exposures.length > value.limits.maxCapabilitiesPerFamily) fail('exposure bounds')
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
const windowKeys = new Set()
|
|
104
|
+
for (const window of value.windows) {
|
|
105
|
+
record(window, 'window')
|
|
106
|
+
identity(window.userId, 'window user identity')
|
|
107
|
+
if (window.workspaceId !== null) identity(window.workspaceId, 'window workspace identity')
|
|
108
|
+
identity(window.id, 'window capability identity')
|
|
109
|
+
identity(window.revision, 'window capability revision')
|
|
110
|
+
integer(window.floor, 'evicted qualification frontier')
|
|
111
|
+
const windowKey = key([window.userId, window.workspaceId, window.id, window.revision])
|
|
112
|
+
if (windowKeys.has(windowKey)) fail('duplicate window')
|
|
113
|
+
windowKeys.add(windowKey)
|
|
114
|
+
}
|
|
115
|
+
return value
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function windowKey(userId, workspaceId, item) { return key([userId, workspaceId, item.id, item.revision]) }
|
|
119
|
+
function qualifies(family, window) {
|
|
120
|
+
return family.userId === window.userId && family.settlement === 'settled' && family.eligibleOrder > window.floor
|
|
121
|
+
&& family.observations.some(item => item.id === window.id && item.revision === window.revision
|
|
122
|
+
&& (window.workspaceId === null || item.workspaceId === window.workspaceId))
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Public adapters supply actual family/workspace identities, monotone observation revisions,
|
|
127
|
+
* and an immutable qualification order. Observations are cumulative additions, never log guesses.
|
|
128
|
+
* A resumed or unknown family contributes no negative sample until owner-proven settlement.
|
|
129
|
+
*/
|
|
130
|
+
export function reduceCapabilityStatistics(previous, event) {
|
|
131
|
+
validateCapabilityStatistics(previous)
|
|
132
|
+
if (previous.status !== 'usable') return previous
|
|
133
|
+
const value = record(event, 'event')
|
|
134
|
+
if (value.type !== 'family-observation') fail('event type')
|
|
135
|
+
const userId = identity(value.userId, 'user identity')
|
|
136
|
+
const familyId = identity(value.familyId, 'family identity')
|
|
137
|
+
const observationRevision = integer(value.observationRevision, 'observation revision')
|
|
138
|
+
const settlement = value.settlement
|
|
139
|
+
if (!['active', 'settled', 'unknown'].includes(settlement)) fail('family settlement')
|
|
140
|
+
const eligibleOrder = value.eligibleOrder == null ? null : integer(value.eligibleOrder, 'qualification order', 1)
|
|
141
|
+
if (settlement === 'settled' && eligibleOrder === null) fail('settlement qualification order')
|
|
142
|
+
if (!Array.isArray(value.observations) || value.observations.length > previous.limits.maxCapabilitiesPerFamily) fail('observation bounds')
|
|
143
|
+
const additions = value.observations.map(observation)
|
|
144
|
+
const state = structuredClone(previous)
|
|
145
|
+
let family = state.families.find(item => item.userId === userId && item.familyId === familyId)
|
|
146
|
+
if (family) {
|
|
147
|
+
if (family.eligibleOrder !== null && eligibleOrder !== family.eligibleOrder) fail('changed qualification order')
|
|
148
|
+
if (observationRevision <= family.observationRevision) return previous
|
|
149
|
+
family.observationRevision = observationRevision
|
|
150
|
+
family.settlement = settlement
|
|
151
|
+
family.eligibleOrder ??= eligibleOrder
|
|
152
|
+
} else {
|
|
153
|
+
if (eligibleOrder !== null && state.families.some(item => item.userId === userId && item.eligibleOrder === eligibleOrder)) fail('qualification order collision')
|
|
154
|
+
family = { userId, familyId, observationRevision, settlement, eligibleOrder, observations: [] }
|
|
155
|
+
state.families.push(family)
|
|
156
|
+
}
|
|
157
|
+
for (const addition of additions) {
|
|
158
|
+
let retained = family.observations.find(item => item.workspaceId === addition.workspaceId && item.id === addition.id && item.revision === addition.revision)
|
|
159
|
+
if (!retained) {
|
|
160
|
+
retained = { workspaceId: addition.workspaceId, id: addition.id, revision: addition.revision, category: addition.category, used: false, exposures: [], outcomes: [] }
|
|
161
|
+
family.observations.push(retained)
|
|
162
|
+
} else if (retained.category !== addition.category) fail('changed capability category')
|
|
163
|
+
retained.used ||= addition.used
|
|
164
|
+
if (addition.outcome !== null && !retained.outcomes.includes(addition.outcome)) retained.outcomes.push(addition.outcome)
|
|
165
|
+
const exposure = { disclosure: addition.disclosure, planRevision: addition.planRevision }
|
|
166
|
+
if (!retained.exposures.some(item => item.disclosure === exposure.disclosure && item.planRevision === exposure.planRevision)) retained.exposures.push(exposure)
|
|
167
|
+
for (const workspaceId of [addition.workspaceId, null]) {
|
|
168
|
+
const targetKey = windowKey(userId, workspaceId, addition)
|
|
169
|
+
if (!state.windows.some(item => windowKey(item.userId, item.workspaceId, item) === targetKey)) {
|
|
170
|
+
state.windows.push({ userId, workspaceId, id: addition.id, revision: addition.revision, floor: 0 })
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
const retainedFamilies = new Set()
|
|
175
|
+
for (const window of state.windows) {
|
|
176
|
+
const eligible = state.families.filter(item => qualifies(item, window)).sort(orderSamples)
|
|
177
|
+
const selected = eligible.slice(0, state.limits.windowSize)
|
|
178
|
+
for (const item of selected) retainedFamilies.add(key([item.userId, item.familyId]))
|
|
179
|
+
for (const item of eligible.slice(state.limits.windowSize)) window.floor = Math.max(window.floor, item.eligibleOrder)
|
|
180
|
+
}
|
|
181
|
+
state.families = state.families.filter(item => item.settlement !== 'settled' || retainedFamilies.has(key([item.userId, item.familyId])))
|
|
182
|
+
if (state.families.length > state.limits.maxFamilies || state.windows.length > state.limits.maxScopes
|
|
183
|
+
|| state.families.some(item => item.observations.length > state.limits.maxCapabilitiesPerFamily
|
|
184
|
+
|| item.observations.some(entry => entry.exposures.length > state.limits.maxCapabilitiesPerFamily))) {
|
|
185
|
+
return freeze({ ...structuredClone(previous), status: 'capacity-exceeded' })
|
|
186
|
+
}
|
|
187
|
+
validateCapabilityStatistics(state)
|
|
188
|
+
return freeze(state)
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/** Per-capability eligible windows; workspace and global evidence are never added together. */
|
|
192
|
+
export function capabilityCoverage(state, query) {
|
|
193
|
+
validateCapabilityStatistics(state)
|
|
194
|
+
const options = record(query, 'coverage query')
|
|
195
|
+
const userId = identity(options.userId, 'coverage user identity')
|
|
196
|
+
const id = identity(options.id, 'coverage capability identity')
|
|
197
|
+
const revision = identity(options.revision, 'coverage capability revision')
|
|
198
|
+
const workspaceId = options.workspaceId === null ? null : identity(options.workspaceId, 'coverage workspace identity')
|
|
199
|
+
if (state.status !== 'usable') return { status: state.status, windowSize: state.limits.windowSize, eligible: null, used: null, coverage: null }
|
|
200
|
+
const window = state.windows.find(item => item.userId === userId && item.workspaceId === workspaceId && item.id === id && item.revision === revision)
|
|
201
|
+
// "Nothing recorded yet" and "recorded families are not currently settled"
|
|
202
|
+
// are different facts from a measured window; neither may read as a zero.
|
|
203
|
+
if (window === undefined) return { status: 'no-samples', windowSize: state.limits.windowSize, eligible: null, used: null, coverage: null }
|
|
204
|
+
const families = state.families.filter(item => qualifies(item, window)).sort(orderSamples).slice(0, state.limits.windowSize)
|
|
205
|
+
// A resumed family can expose a gap behind the irreversible eviction frontier.
|
|
206
|
+
// Surviving samples do not prove the recent settled window until it is full again.
|
|
207
|
+
if (window.floor > 0 && families.length < state.limits.windowSize) {
|
|
208
|
+
return { status: 'incomplete-window', windowSize: state.limits.windowSize, eligible: null, used: null, coverage: null }
|
|
209
|
+
}
|
|
210
|
+
if (families.length === 0) return { status: 'pending-settlement', windowSize: state.limits.windowSize, eligible: null, used: null, coverage: null }
|
|
211
|
+
const used = families.filter(family => family.observations.some(item => item.id === id && item.revision === revision && item.used
|
|
212
|
+
&& (workspaceId === null || item.workspaceId === workspaceId))).length
|
|
213
|
+
return { status: 'usable', windowSize: state.limits.windowSize, eligible: families.length, used, coverage: families.length ? used / families.length : null }
|
|
214
|
+
}
|
package/internal/config-spec.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { CAPABILITY_POLICY_DEFAULT } from './capability-policy.js'
|
|
2
|
+
|
|
1
3
|
/** Configuration fields shared by the Host schema and settings card. */
|
|
2
4
|
export const MAX_TIMER_DELAY_MS = 2_147_483_647
|
|
3
5
|
|
|
@@ -11,6 +13,54 @@ export const SETTINGS_NAMESPACE = 'ptc-plus'
|
|
|
11
13
|
* exists in both locales or in neither.
|
|
12
14
|
*/
|
|
13
15
|
export const CONFIG_FIELDS = Object.freeze([
|
|
16
|
+
{ key: 'capabilityContextEnabled', type: 'boolean', default: true,
|
|
17
|
+
label: '能力与上下文', labelEn: 'Capabilities and context',
|
|
18
|
+
description: '整体暂停能力规则、统计采集、说明恢复和结果预览,保留各项设置;新会话或明确刷新后生效。',
|
|
19
|
+
descriptionEn: 'Pauses capability rules, statistics collection, description recovery and result previews while retaining each setting. Applies to new sessions or explicit refreshes.' },
|
|
20
|
+
{ key: 'capabilityManagementEnabled', type: 'boolean', default: false,
|
|
21
|
+
label: '实验性能力管理', labelEn: 'Experimental capability management',
|
|
22
|
+
description: '为新 PTC 会话应用可用性与说明规则;已有会话使用 /capabilities refresh 生效。收益尚未经过模型对照验收。',
|
|
23
|
+
descriptionEn: 'Applies availability and disclosure rules to new PTC sessions. Use /capabilities refresh for existing sessions. Model cost benefits remain unverified.' },
|
|
24
|
+
{ key: 'capabilityPolicy', preserveOmission: true, type: 'string', default: CAPABILITY_POLICY_DEFAULT,
|
|
25
|
+
label: '能力规则', labelEn: 'Capability rules',
|
|
26
|
+
description: '分别设置可用性、说明方式以及常用集、统计和预算分配;默认、类别、MCP 来源、单项依次覆盖。',
|
|
27
|
+
descriptionEn: 'Choose availability, disclosure and baseline, statistics and budget allocation separately. Default, category, MCP source and item rules apply in order.' },
|
|
28
|
+
{ key: 'capabilityRecoveryEnabled', preserveOmission: true, type: 'boolean', default: false,
|
|
29
|
+
label: '压缩后恢复已使用的 API 说明', labelEn: 'Recover used API descriptions after compaction',
|
|
30
|
+
description: '只补回已展开、仍有效且不可见的近期 API 说明,不恢复 Skill 正文。',
|
|
31
|
+
descriptionEn: 'Restores only expanded, current, no longer visible API descriptions from recent use; never Skill bodies.' },
|
|
32
|
+
{ key: 'modelPreviewEnabled', preserveOmission: true, type: 'boolean', default: false,
|
|
33
|
+
label: '限制模型侧结果与日志展示', labelEn: 'Bound model-facing results and logs',
|
|
34
|
+
description: '独立使用插件预览预算;关闭时沿用宿主展示,程序值始终完整。',
|
|
35
|
+
descriptionEn: 'Independently selects the plugin preview budget. Otherwise retains Host presentation; program values remain complete.' },
|
|
36
|
+
{ key: 'capabilityBaseline', type: 'string', default: '[]',
|
|
37
|
+
label: '初始常用能力', labelEn: 'Initial common capabilities',
|
|
38
|
+
description: '从能力列表勾选常用项;adaptive 选用常用集依据时参与分配,不生成使用记录。',
|
|
39
|
+
descriptionEn: 'Select common capabilities as an optional allocation basis for adaptive disclosure. Creates no usage records.' },
|
|
40
|
+
{ key: 'capabilityOverrides', type: 'string', default: '{}',
|
|
41
|
+
label: '旧版能力选择', labelEn: 'Legacy capability selections',
|
|
42
|
+
description: '旧配置迁移输入;新规则由能力工作台分别保存可用性与说明方式。',
|
|
43
|
+
descriptionEn: 'Migration input for older settings. The workbench saves availability and disclosure separately in the policy.' },
|
|
44
|
+
{ key: 'capabilityStatistics', type: 'string',
|
|
45
|
+
default: '{"enabled":false,"windowSize":100,"minimumSamples":10,"fullThreshold":0.5}',
|
|
46
|
+
label: '能力统计设置', labelEn: 'Capability statistics settings',
|
|
47
|
+
description: '独立采集使用统计,并设置样本窗口、最低样本数和完整披露阈值;关闭或不可用时保留手动基线。',
|
|
48
|
+
descriptionEn: 'Collect usage statistics independently and set the sample window, minimum samples and full-disclosure threshold. Disabled or unavailable statistics preserve the manual baseline.' },
|
|
49
|
+
{ key: 'capabilityProfiles', type: 'string', default: '{"schema":"ptc-capability-profiles/v1","profiles":[]}',
|
|
50
|
+
label: '保存的能力配置', labelEn: 'Saved capability configurations',
|
|
51
|
+
description: '在能力工作台命名保存、导入导出和切换配置;已有会话需要主动刷新。',
|
|
52
|
+
descriptionEn: 'Name, save, import, export and switch configurations in the capability workbench. Existing sessions require explicit refresh.' },
|
|
53
|
+
{ key: 'capabilityBudgetBytes', type: 'integer', default: 16384, min: 1, max: Number.MAX_SAFE_INTEGER,
|
|
54
|
+
label: '完整说明预算 (UTF-8 bytes)', labelEn: 'Full contract budget (UTF-8 bytes)',
|
|
55
|
+
description: '显式 full 可以超出此预算;不截断调用契约。', descriptionEn: 'Explicit full selections may exceed this budget; calling contracts are never truncated.' },
|
|
56
|
+
{ key: 'capabilityDirectoryBytes', type: 'integer', default: 2048, min: 512, max: Number.MAX_SAFE_INTEGER,
|
|
57
|
+
label: '能力导航预算 (UTF-8 bytes)', labelEn: 'Capability navigation budget (UTF-8 bytes)', description: '', descriptionEn: '' },
|
|
58
|
+
{ key: 'capabilityRecoveryBytes', type: 'integer', default: 8192, min: 1, max: Number.MAX_SAFE_INTEGER,
|
|
59
|
+
label: '压缩后说明恢复预算 (UTF-8 bytes)', labelEn: 'Description recovery budget (UTF-8 bytes)', description: '', descriptionEn: '' },
|
|
60
|
+
{ key: 'modelPreviewTokens', type: 'integer', default: 4096, min: 1, max: Number.MAX_SAFE_INTEGER,
|
|
61
|
+
label: '模型结果预览预算 (estimated tokens)', labelEn: 'Model result preview budget (estimated tokens)',
|
|
62
|
+
description: '选用模型侧预览时复用 DSH spill policy;完整内容需要宿主 spill store,程序值保持完整。',
|
|
63
|
+
descriptionEn: 'Uses DSH spill policy when model-facing previews are selected. Complete content requires a host spill store; program values remain complete.' },
|
|
14
64
|
{
|
|
15
65
|
key: 'legacyBindingSettings',
|
|
16
66
|
type: 'boolean',
|
|
@@ -38,6 +88,15 @@ export const CONFIG_FIELDS = Object.freeze([
|
|
|
38
88
|
description: '开启时使用增强工具卡片;关闭后使用 DSH 原生工具卡片。',
|
|
39
89
|
descriptionEn: 'Uses enhanced tool cards when enabled and DSH native tool cards when disabled.',
|
|
40
90
|
},
|
|
91
|
+
{
|
|
92
|
+
key: 'toolHoverPreviewEnabled',
|
|
93
|
+
type: 'boolean',
|
|
94
|
+
default: true,
|
|
95
|
+
label: '悬停预览执行内容',
|
|
96
|
+
labelEn: 'Preview execution content on hover',
|
|
97
|
+
description: '在增强执行卡片上停留或键盘聚焦时显示简短预览;滚动时自动隐藏。',
|
|
98
|
+
descriptionEn: 'Shows a quick preview on enhanced tool cards after hovering or keyboard focus; hides while scrolling.',
|
|
99
|
+
},
|
|
41
100
|
{
|
|
42
101
|
key: 'replViewEnabled',
|
|
43
102
|
type: 'boolean',
|
|
@@ -53,8 +112,8 @@ export const CONFIG_FIELDS = Object.freeze([
|
|
|
53
112
|
default: true,
|
|
54
113
|
label: '显示 PTC Plus 快捷入口',
|
|
55
114
|
labelEn: 'Show the PTC Plus shortcut',
|
|
56
|
-
description: '
|
|
57
|
-
descriptionEn: 'Shows the
|
|
115
|
+
description: '在输入框旁显示星光菜单:打开插件设置、刷新当前会话能力,并在全局绑定开启时查看、启停和编写绑定;隐藏后仍可使用斜杠命令。',
|
|
116
|
+
descriptionEn: 'Shows the sparkle menu beside the composer: open settings, refresh current-session capabilities, and manage or author global bindings when enabled. Hiding it does not remove slash commands.',
|
|
58
117
|
},
|
|
59
118
|
{
|
|
60
119
|
key: 'autoDescribeRunCode',
|
|
@@ -156,6 +215,15 @@ export const CONFIG_FIELDS = Object.freeze([
|
|
|
156
215
|
description: 'worker 重启后从 session journal 重建可恢复的 REPL 状态。',
|
|
157
216
|
descriptionEn: 'Rebuilds recoverable REPL state from the session journal after a worker restart.',
|
|
158
217
|
},
|
|
218
|
+
{
|
|
219
|
+
key: 'officialReplPriority',
|
|
220
|
+
type: 'boolean',
|
|
221
|
+
default: false,
|
|
222
|
+
label: '官方 REPL 模式优先',
|
|
223
|
+
labelEn: 'Prioritize the official REPL mode',
|
|
224
|
+
description: '检测到官方持久 REPL 模式时由官方运行时接管 PTC 会话执行;PTC Plus 让出 run_code 及其进程内会话状态语义,关闭时始终由 PTC Plus 接管。',
|
|
225
|
+
descriptionEn: 'Lets the official runtime own PTC session execution when the official persistent REPL mode is active; PTC Plus then leaves run_code and its in-process session-state semantics to DSH. Disabled keeps PTC Plus in charge.',
|
|
226
|
+
},
|
|
159
227
|
{
|
|
160
228
|
key: 'tipsEnabled',
|
|
161
229
|
type: 'boolean',
|
|
@@ -296,12 +364,6 @@ export const CONFIG_GROUPS = Object.freeze([
|
|
|
296
364
|
labelEn: 'Plugin switch',
|
|
297
365
|
fields: Object.freeze(['enabled']),
|
|
298
366
|
},
|
|
299
|
-
{
|
|
300
|
-
key: 'calls',
|
|
301
|
-
label: '调用容错',
|
|
302
|
-
labelEn: 'Tool call tolerance',
|
|
303
|
-
fields: Object.freeze(['autoDescribeRunCode', 'canonicalizeToolCalls']),
|
|
304
|
-
},
|
|
305
367
|
{
|
|
306
368
|
key: 'syntax',
|
|
307
369
|
label: 'REPL 语法',
|
|
@@ -314,7 +376,7 @@ export const CONFIG_GROUPS = Object.freeze([
|
|
|
314
376
|
key: 'recovery',
|
|
315
377
|
label: '状态与恢复',
|
|
316
378
|
labelEn: 'State and recovery',
|
|
317
|
-
fields: Object.freeze(['durableReplay', 'tipsEnabled', 'tipCooldownMessages', 'tipEscalationFailures']),
|
|
379
|
+
fields: Object.freeze(['durableReplay', 'officialReplPriority', 'tipsEnabled', 'tipCooldownMessages', 'tipEscalationFailures']),
|
|
318
380
|
},
|
|
319
381
|
{
|
|
320
382
|
key: 'extensions',
|
|
@@ -322,11 +384,17 @@ export const CONFIG_GROUPS = Object.freeze([
|
|
|
322
384
|
labelEn: 'Tool extensions',
|
|
323
385
|
fields: Object.freeze(['userBindingsEnabled', 'cordisToolsEnabled']),
|
|
324
386
|
},
|
|
387
|
+
{
|
|
388
|
+
key: 'calls',
|
|
389
|
+
label: '调用容错',
|
|
390
|
+
labelEn: 'Tool call tolerance',
|
|
391
|
+
fields: Object.freeze(['autoDescribeRunCode', 'canonicalizeToolCalls']),
|
|
392
|
+
},
|
|
325
393
|
{
|
|
326
394
|
key: 'interface',
|
|
327
395
|
label: '界面显示',
|
|
328
396
|
labelEn: 'Interface display',
|
|
329
|
-
fields: Object.freeze(['enhancedToolView', 'replViewEnabled', 'bindingAuthorButtonVisible']),
|
|
397
|
+
fields: Object.freeze(['enhancedToolView', 'toolHoverPreviewEnabled', 'replViewEnabled', 'bindingAuthorButtonVisible']),
|
|
330
398
|
},
|
|
331
399
|
{
|
|
332
400
|
key: 'limits',
|
|
@@ -344,8 +412,19 @@ export const CONFIG_GROUPS = Object.freeze([
|
|
|
344
412
|
'maxValueBigIntDigits',
|
|
345
413
|
]),
|
|
346
414
|
},
|
|
415
|
+
{ key: 'capabilities', label: '能力与上下文', labelEn: 'Capabilities and context',
|
|
416
|
+
fields: Object.freeze(['capabilityContextEnabled', 'capabilityManagementEnabled', 'capabilityBaseline', 'capabilityOverrides',
|
|
417
|
+
'capabilityStatistics', 'capabilityPolicy', 'capabilityRecoveryEnabled', 'modelPreviewEnabled', 'capabilityProfiles', 'capabilityBudgetBytes', 'capabilityDirectoryBytes', 'capabilityRecoveryBytes', 'modelPreviewTokens']) },
|
|
347
418
|
])
|
|
348
419
|
|
|
420
|
+
/** Functional modules share the same section order across every settings entry. */
|
|
421
|
+
export const CONFIG_MODULES = Object.freeze([
|
|
422
|
+
{ key: 'workspace', label: '核心工作区', labelEn: 'Core workspace', groups: Object.freeze(['syntax', 'recovery']) },
|
|
423
|
+
{ key: 'extensions', label: '扩展与容错', labelEn: 'Extensions and tolerance', groups: Object.freeze(['extensions', 'calls']) },
|
|
424
|
+
{ key: 'presentation', label: '界面与资源', labelEn: 'Interface and resources', groups: Object.freeze(['interface', 'limits']) },
|
|
425
|
+
{ key: 'experimental', label: '实验性', labelEn: 'Experimental', groups: Object.freeze(['capabilities']) },
|
|
426
|
+
].map(Object.freeze))
|
|
427
|
+
|
|
349
428
|
/** Resolved defaults, derived once from the field definitions. */
|
|
350
429
|
export const CONFIG_DEFAULTS = Object.freeze(
|
|
351
430
|
Object.fromEntries(CONFIG_FIELDS.map(field => [field.key, field.default])),
|
|
@@ -3,7 +3,6 @@ import { boundContextSummary, createUserMessage } from '@deepseek-ai/dsh-llm'
|
|
|
3
3
|
import { validateJsonSchemaValue } from '@deepseek-ai/dsh-tools'
|
|
4
4
|
import { PTC_MESSAGE_SOURCE_KIND } from './message-sources.js'
|
|
5
5
|
import { canonicalizeToolCallStream } from './tool-call-canonicalizer.js'
|
|
6
|
-
import { editRunCodeSchema } from './rejected-cell-editor.js'
|
|
7
6
|
import { sessionRuntimeContexts } from './runtime-contexts.js'
|
|
8
7
|
import { projectProgramSdk } from './sdk-projection.js'
|
|
9
8
|
import { EDIT_RUN_CODE } from './edit-transport-owner.js'
|
|
@@ -16,11 +15,12 @@ import {
|
|
|
16
15
|
} from './run-code-description.js'
|
|
17
16
|
import { userBindingsConfiguredContext } from './user-bindings.js'
|
|
18
17
|
import { BINDING_AUTHORING_SDK } from './user-binding-authoring.js'
|
|
18
|
+
import { executionPolicies } from './binding-update-policy.js'
|
|
19
19
|
|
|
20
|
-
const RUN_CODE_TOOL_DESCRIPTION = 'Evaluate the next TypeScript cell in this session-bound persistent REPL, reusing earlier top-level bindings. Use `code` for the
|
|
21
|
-
const RUN_CODE_CODE_DESCRIPTION = 'Code for the next
|
|
20
|
+
const RUN_CODE_TOOL_DESCRIPTION = 'Evaluate the next TypeScript cell in this session-bound persistent REPL, reusing earlier top-level bindings. Use `code` for the cell and `description` for its short UI summary. Successful image-bearing subtool results are attached after the cell.'
|
|
21
|
+
const RUN_CODE_CODE_DESCRIPTION = 'Code for the next PTC TypeScript cell, following the selected language conventions.'
|
|
22
22
|
const RUN_CODE_DESCRIPTION_DESCRIPTION = 'Short active-voice summary of what this cell does, 5-10 words (shown in the UI).'
|
|
23
|
-
const CODE_TRANSPORT_INSTRUCTION = '`run_code`
|
|
23
|
+
const CODE_TRANSPORT_INSTRUCTION = '`run_code` is the only tool callable directly. Call `tools.edit_run_code` and other SDK tools from inside a program. An accepted edit runs after the current cell finishes.'
|
|
24
24
|
const PTC_COLLAPSE_SECTION_NAMES = Object.freeze(['tools:ptc-only', 'tools:code-only'])
|
|
25
25
|
const INVALID_TOOL_JSON_FAILURE = Object.freeze({
|
|
26
26
|
code: 'MALFORMED_RESPONSE',
|
|
@@ -53,19 +53,20 @@ function adaptRunCodeSchema(tool) {
|
|
|
53
53
|
}
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
-
function capabilitySdk(nativeSdk, userBindingsEnabled) {
|
|
57
|
-
return `${projectProgramSdk(nativeSdk)}
|
|
56
|
+
function capabilitySdk(nativeSdk, userBindingsEnabled, languageSemantics) {
|
|
57
|
+
return `${projectProgramSdk(nativeSdk, { languageSemantics })}
|
|
58
58
|
|
|
59
59
|
## PTC Plus program capabilities
|
|
60
60
|
|
|
61
|
-
Discover program APIs without calling them. \`
|
|
61
|
+
Discover program APIs without calling them. \`search({query})\` retrieves whole indexed API descriptions by English/Chinese words; its UTF-8 JSON byte budget includes the envelope, with a continuation cursor and inspect references for oversized entries. \`tree()\` lists namespaces and members; \`find()\` matches case-insensitive symbols or contiguous words, separating CamelCase and punctuation; \`inspect()\` returns selected \`namespace.member\` symbols with an item-count budget. Missing metadata is unknown.
|
|
62
62
|
|
|
63
63
|
\`\`\`ts
|
|
64
|
-
declare class CapabilityExplorationError extends Error { readonly operation: "tree" | "find" | "inspect" }
|
|
64
|
+
declare class CapabilityExplorationError extends Error { readonly operation: "tree" | "find" | "inspect" | "search" }
|
|
65
65
|
declare const capabilities: {
|
|
66
66
|
tree(): Promise<Array<{ namespace: string; members: string[] }>>
|
|
67
67
|
find(query: string): Promise<Array<{ symbol: string; description?: string; completeness: string; effect: string; replay: string }>>
|
|
68
68
|
inspect(args?: { symbols?: string[]; budget?: number }): Promise<{ symbols: unknown[]; omitted: number; unknown: string[]; budget: number }>
|
|
69
|
+
search(args: { query: string; budgetBytes?: number; limit?: number; cursor?: string }): Promise<{ matches: Array<{ symbol: string; owner: unknown; contract: unknown }>; oversized: Array<{ symbol: string; requiredBytes: number; inspect: { symbols: string[]; budget: number } }>; total: number; remaining: number; cursor: string | null; budgetBytes: number; usedBytes: number; unit: "utf8-json-bytes" }>
|
|
69
70
|
}
|
|
70
71
|
\`\`\`${userBindingsEnabled ? `\n${BINDING_AUTHORING_SDK}` : ''}`
|
|
71
72
|
}
|
|
@@ -118,16 +119,8 @@ function presentationState(assembly) {
|
|
|
118
119
|
const collapse = PTC_COLLAPSE_SECTION_NAMES
|
|
119
120
|
.map(name => assembly?.sections?.find(section => section?.name === name))
|
|
120
121
|
.find(section => section !== undefined)
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
? 'ptc'
|
|
124
|
-
: 'both'
|
|
125
|
-
return { presentation, ownerProven: true, collapseSectionName: collapse.name }
|
|
126
|
-
}
|
|
127
|
-
const presentation = tools.every(tool => tool?.name === RUN_CODE || tool?.name === EDIT_RUN_CODE)
|
|
128
|
-
? 'ptc'
|
|
129
|
-
: 'both'
|
|
130
|
-
return { presentation, ownerProven: false, collapseSectionName: undefined }
|
|
122
|
+
return { presentation: 'ptc', ownerProven: collapse !== undefined,
|
|
123
|
+
collapseSectionName: collapse?.name }
|
|
131
124
|
}
|
|
132
125
|
|
|
133
126
|
async function* bindCallPolicies(source, policy, calls) {
|
|
@@ -465,6 +458,7 @@ export function createDirectSurfaceOwner({
|
|
|
465
458
|
userBindingsForAgent = async () => undefined,
|
|
466
459
|
setAgentPresentation = async () => {},
|
|
467
460
|
sessionLogView,
|
|
461
|
+
capabilityEnvironment,
|
|
468
462
|
}) {
|
|
469
463
|
// Composition is anchored to Agent identity because DSH selects presentation
|
|
470
464
|
// once per composed agent. Request signals bind the exact assembly to stream
|
|
@@ -478,6 +472,7 @@ export function createDirectSurfaceOwner({
|
|
|
478
472
|
let disposed = false
|
|
479
473
|
let currentCanonicalizeToolCalls = canonicalizeToolCalls
|
|
480
474
|
let currentAutoDescribeRunCode = runtimeConfig.autoDescribeRunCode
|
|
475
|
+
let currentLanguageSemantics = executionPolicies(runtimeConfig).languageSemantics
|
|
481
476
|
const tipConfig = {
|
|
482
477
|
enabled: runtimeConfig.tipsEnabled,
|
|
483
478
|
cooldownMessages: runtimeConfig.tipCooldownMessages,
|
|
@@ -563,6 +558,7 @@ export function createDirectSurfaceOwner({
|
|
|
563
558
|
|
|
564
559
|
return Object.freeze({
|
|
565
560
|
reconfigure(nextConfig) {
|
|
561
|
+
currentLanguageSemantics = executionPolicies(nextConfig).languageSemantics
|
|
566
562
|
currentCanonicalizeToolCalls = nextConfig.canonicalizeToolCalls
|
|
567
563
|
currentAutoDescribeRunCode = nextConfig.autoDescribeRunCode
|
|
568
564
|
cordisRecovery.reconfigure(nextConfig.cordisToolsEnabled)
|
|
@@ -571,8 +567,11 @@ export function createDirectSurfaceOwner({
|
|
|
571
567
|
tipConfig.escalationFailures = nextConfig.tipEscalationFailures
|
|
572
568
|
},
|
|
573
569
|
async assemble(initialAssembly, context, next) {
|
|
570
|
+
// Settings observes Host-owned catalogs without preparing a session environment.
|
|
571
|
+
if (context?.ptcPlusCapabilityObservation === true) return next()
|
|
574
572
|
// Keep schema projection and later execution on one configuration snapshot.
|
|
575
573
|
const autoDescribeRunCode = currentAutoDescribeRunCode
|
|
574
|
+
const languageSemantics = currentLanguageSemantics
|
|
576
575
|
const agent = context?.agent
|
|
577
576
|
const id = sessionId(agent)
|
|
578
577
|
const requestOwner = id === undefined ? undefined : sessionOwner(id)
|
|
@@ -625,13 +624,14 @@ export function createDirectSurfaceOwner({
|
|
|
625
624
|
if (!isCurrent()) return assembly
|
|
626
625
|
const sessionPtc = presentation !== 'native' && id !== undefined
|
|
627
626
|
const sessionPtcProjection = presentation === 'ptc' && id !== undefined
|
|
627
|
+
if (sessionPtc) await capabilityEnvironment?.prepare(agent, assembly.sections)
|
|
628
628
|
const userBindings = sessionPtc ? await userBindingsForAgent(agent) : undefined
|
|
629
629
|
if (!isCurrent()) return assembly
|
|
630
630
|
const runCode = tools.find(tool => tool?.name === RUN_CODE)
|
|
631
|
-
let directTools = tools
|
|
631
|
+
let directTools = sessionPtc ? capabilityEnvironment?.visibleSchemas(agent, tools) ?? tools : tools
|
|
632
632
|
if (sessionPtcProjection) {
|
|
633
633
|
editTransport.ensureInstalled(agent)
|
|
634
|
-
directTools = [adaptRunCodeSchema(runCode)
|
|
634
|
+
directTools = [adaptRunCodeSchema(runCode)]
|
|
635
635
|
}
|
|
636
636
|
const runtimeContexts = sessionPtc
|
|
637
637
|
? sessionRuntimeContexts(agent, tipConfig, {
|
|
@@ -650,9 +650,10 @@ export function createDirectSurfaceOwner({
|
|
|
650
650
|
&& assembly.sections.some(section => section?.name === 'tools:sdk'
|
|
651
651
|
|| (sessionPtcProjection && section?.name === completedState.collapseSectionName))
|
|
652
652
|
const sections = projectsSections
|
|
653
|
-
? assembly.sections.map(section => {
|
|
653
|
+
? (capabilityEnvironment?.projectSections(agent, assembly.sections) ?? assembly.sections).map(section => {
|
|
654
654
|
if (section?.name === 'tools:sdk') {
|
|
655
|
-
return { ...section, text: capabilitySdk(section.text
|
|
655
|
+
return { ...section, text: capabilitySdk(capabilityEnvironment?.sdk(agent, section.text) ?? section.text,
|
|
656
|
+
userBindings !== undefined, languageSemantics) }
|
|
656
657
|
}
|
|
657
658
|
if (sessionPtcProjection && section?.name === completedState.collapseSectionName) {
|
|
658
659
|
return { ...section, text: CODE_TRANSPORT_INSTRUCTION }
|
|
@@ -662,7 +663,7 @@ export function createDirectSurfaceOwner({
|
|
|
662
663
|
: assembly.sections
|
|
663
664
|
if (id !== undefined) {
|
|
664
665
|
const nativeSchemas = presentation === 'ptc'
|
|
665
|
-
? new Map(toolSchemasForAgent(agent)
|
|
666
|
+
? new Map((capabilityEnvironment?.visibleSchemas(agent, toolSchemasForAgent(agent)) ?? toolSchemasForAgent(agent))
|
|
666
667
|
.filter(schema => typeof schema?.name === 'string'
|
|
667
668
|
&& schema.name !== RUN_CODE && schema.name !== EDIT_RUN_CODE)
|
|
668
669
|
.map(schema => [schema.name, schema]))
|
|
@@ -706,20 +707,17 @@ export function createDirectSurfaceOwner({
|
|
|
706
707
|
return bindCallPolicies(recovered, policy, policy.owner.calls)
|
|
707
708
|
},
|
|
708
709
|
executionRejection(exec) {
|
|
709
|
-
if (exec.name === EDIT_RUN_CODE && exec.parent !== undefined) {
|
|
710
|
-
return rejection(`tool ${EDIT_RUN_CODE} is only callable directly in PTC mode; call native tools from inside run_code`)
|
|
711
|
-
}
|
|
712
710
|
const policy = dispatchPolicy(exec)
|
|
713
711
|
if (exec.name === EDIT_RUN_CODE) {
|
|
714
|
-
return
|
|
712
|
+
return exec.parent !== undefined
|
|
715
713
|
? undefined
|
|
716
|
-
: rejection(`tool ${EDIT_RUN_CODE}
|
|
714
|
+
: rejection(`tool ${EDIT_RUN_CODE} must be called through tools.${EDIT_RUN_CODE} inside run_code`)
|
|
717
715
|
}
|
|
718
716
|
if (exec.name === RUN_CODE || exec.parent !== undefined) {
|
|
719
717
|
return undefined
|
|
720
718
|
}
|
|
721
719
|
if (policy?.presentation !== 'ptc') return undefined
|
|
722
|
-
return rejection(`tool ${exec.name} is not a direct PTC tool; use run_code
|
|
720
|
+
return rejection(`tool ${exec.name} is not a direct PTC tool; use run_code directly, and call SDK tools from inside run_code`)
|
|
723
721
|
},
|
|
724
722
|
executionArguments(exec) {
|
|
725
723
|
const policy = dispatchPolicy(exec)
|
|
@@ -54,7 +54,7 @@ const asBindings = value => {
|
|
|
54
54
|
|
|
55
55
|
/** Native reference operations over compiler-proved lexical and object frames. */
|
|
56
56
|
export function createDynamicEnvironmentRuntime({
|
|
57
|
-
importModule = (source, options) => import(source, options),
|
|
57
|
+
importModule: defaultImportModule = (source, options) => import(source, options),
|
|
58
58
|
intrinsicEval = defaultIntrinsics.intrinsicEval, realmFunction = defaultIntrinsics.realmFunction, globalObject = defaultIntrinsics.globalObject,
|
|
59
59
|
errors, reflect = defaultIntrinsics.reflect, object, interfaceOwner, resolveAmbient = programAmbientResolver,
|
|
60
60
|
} = {}) {
|
|
@@ -173,7 +173,7 @@ export function createDynamicEnvironmentRuntime({
|
|
|
173
173
|
|
|
174
174
|
function environment({ frames = [], varFrame = new internal.Map(), strict = false, origin, lexicalContext = {},
|
|
175
175
|
getThis = () => globalObject, getNewTarget = () => undefined, allowNewTarget = false,
|
|
176
|
-
ambient = ambientReference, createVar, declareVars, nativeAwait = false } = {}) {
|
|
176
|
+
ambient = ambientReference, createVar, declareVars, nativeAwait = false, importModule = defaultImportModule } = {}) {
|
|
177
177
|
varFrame = asBindings(varFrame)
|
|
178
178
|
const capturedFrames = []
|
|
179
179
|
for (let index = 0; index < frames.length; index++) {
|
|
@@ -268,19 +268,19 @@ export function createDynamicEnvironmentRuntime({
|
|
|
268
268
|
internal.copyArray(captured, rootIndex, captured.length, combined)
|
|
269
269
|
internal.copyArray(frames, boundary, frames.length, combined)
|
|
270
270
|
}
|
|
271
|
-
return environment({ frames: combined,
|
|
271
|
+
return environment({ importModule, frames: combined,
|
|
272
272
|
varFrame, strict: nextStrict, getThis, getNewTarget, allowNewTarget, ambient, createVar, declareVars, nativeAwait, origin, lexicalContext })
|
|
273
273
|
},
|
|
274
274
|
awaitActivation() {
|
|
275
275
|
const local = new internal.Map()
|
|
276
|
-
return environment({ frames: internal.copyArray(frames, 0, frames.length, [{ kind: 'lexical', bindings: local }]), varFrame: local,
|
|
276
|
+
return environment({ importModule, frames: internal.copyArray(frames, 0, frames.length, [{ kind: 'lexical', bindings: local }]), varFrame: local,
|
|
277
277
|
strict, getThis, getNewTarget, allowNewTarget, ambient, nativeAwait: true, origin, lexicalContext })
|
|
278
278
|
},
|
|
279
279
|
activation(bindings, nextGetThis = getThis, nextGetNewTarget = getNewTarget, nextStrict = strict, ownFunction = true, selfBindings) {
|
|
280
280
|
bindings = asBindings(bindings)
|
|
281
281
|
const activationFrames = [{ kind: 'lexical', bindings }]
|
|
282
282
|
if (selfBindings !== undefined) internal.appendArray(activationFrames, { kind: 'self', bindings: asBindings(selfBindings) })
|
|
283
|
-
return environment({ frames: internal.copyArray(frames, 0, frames.length, activationFrames), varFrame: bindings,
|
|
283
|
+
return environment({ importModule, frames: internal.copyArray(frames, 0, frames.length, activationFrames), varFrame: bindings,
|
|
284
284
|
strict: nextStrict, getThis: nextGetThis, getNewTarget: nextGetNewTarget, allowNewTarget: ownFunction || allowNewTarget, ambient, origin,
|
|
285
285
|
lexicalContext: ownFunction ? { privateReferences: lexicalContext.privateReferences } : lexicalContext })
|
|
286
286
|
},
|
|
@@ -294,7 +294,7 @@ export function createDynamicEnvironmentRuntime({
|
|
|
294
294
|
}
|
|
295
295
|
const parameterFrames = [{ kind: 'lexical', bindings }]
|
|
296
296
|
if (selfBindings !== undefined) internal.appendArray(parameterFrames, { kind: 'self', bindings: asBindings(selfBindings) })
|
|
297
|
-
selected = environment({ frames: internal.copyArray(frames, 0, frames.length, parameterFrames), varFrame: bindings,
|
|
297
|
+
selected = environment({ importModule, frames: internal.copyArray(frames, 0, frames.length, parameterFrames), varFrame: bindings,
|
|
298
298
|
strict: nextStrict, getThis: nextGetThis, getNewTarget: nextGetNewTarget, allowNewTarget: ownFunction || allowNewTarget, ambient, origin, lexicalContext })
|
|
299
299
|
internal.weakMapSet(parameterEnvironments, key, selected)
|
|
300
300
|
}
|
|
@@ -309,15 +309,15 @@ export function createDynamicEnvironmentRuntime({
|
|
|
309
309
|
} })
|
|
310
310
|
return nativeCalls.registerCallableSourceTarget(adapter, fn)
|
|
311
311
|
},
|
|
312
|
-
context(options) { return environment({ frames, varFrame, strict: options.strict ?? strict,
|
|
312
|
+
context(options) { return environment({ importModule, frames, varFrame, strict: options.strict ?? strict,
|
|
313
313
|
getThis: options.getThis ?? getThis, getNewTarget: options.getNewTarget ?? getNewTarget,
|
|
314
314
|
allowNewTarget: options.allowNewTarget ?? allowNewTarget, ambient, createVar, declareVars, nativeAwait, origin,
|
|
315
315
|
lexicalContext: { ...lexicalContext, ...options } }) },
|
|
316
|
-
at(nextOrigin) { return environment({ frames, varFrame, strict, getThis, getNewTarget,
|
|
316
|
+
at(nextOrigin) { return environment({ importModule, frames, varFrame, strict, getThis, getNewTarget,
|
|
317
317
|
allowNewTarget, ambient, createVar, declareVars, nativeAwait, origin: nextOrigin, lexicalContext }) },
|
|
318
318
|
withObject(value) {
|
|
319
319
|
if (value === null || value === undefined) throw new errors.TypeError('Cannot convert undefined or null to object')
|
|
320
|
-
return environment({ frames: internal.copyArray(frames, 0, frames.length, [{ kind: 'object', object: object(value) }]),
|
|
320
|
+
return environment({ importModule, frames: internal.copyArray(frames, 0, frames.length, [{ kind: 'object', object: object(value) }]),
|
|
321
321
|
varFrame, strict, getThis, getNewTarget, allowNewTarget, ambient, createVar, declareVars, nativeAwait, origin, lexicalContext })
|
|
322
322
|
},
|
|
323
323
|
declareEvalVars(names) {
|