Parcourir la source

feat(ptc): present provider execution guidance in logged program schema

Tianyi Cui il y a 2 semaines
Parent
commit
2a08bf6ab9

+ 2 - 2
docs/subsystems/code-runtime.i18n.yaml

@@ -2,5 +2,5 @@
 # side as of the last confirmed-consistent state. Both languages carry equal authority;
 # after editing either side, bring the other along and re-record with:
 #   pnpm run verify-translation-pairing --write docs/subsystems/code-runtime.md
-code-runtime.md: b3d4fbbb4bbfd85e6460ba333cb4c6365e0bc43c
-code-runtime.zh.md: 81e5df9bf401f9123ec7fe7ac2577c80ba27bc70
+code-runtime.md: 085d51e1c51fefe37b9b5913d1a2d1e69fbf5fc8
+code-runtime.zh.md: 887e0dabc6c1c5cf9faa0a9c47813cc0681ccbfa

+ 1 - 1
docs/subsystems/code-runtime.md

@@ -192,7 +192,7 @@ interface CodeRunFailure {
 
 ## The service
 
-`CodeRuntime` is defined in [`src/index.ts`](../../packages/code-runtime/code-runtime/src/index.ts). `resolve(request)` returns complete execution inputs, and `run(spec)` executes them. `language` selects supported program presentation; `isolation` describes the substrate without claiming security. `sandboxMode` advertises file-policy support, with `undefined` for a provider that does not supply confinement. Each implementation keeps program state separate between runs and terminates and awaits active executions during disposal.
+`CodeRuntime` is defined in [`src/index.ts`](../../packages/code-runtime/code-runtime/src/index.ts). `resolve(request)` returns complete execution inputs, and `run(spec)` executes them. `executionInstructions` supplies provider-owned usage guidance for consumer presentation. `language` selects supported program presentation; `isolation` describes the substrate without claiming security. `sandboxMode` advertises file-policy support, with `undefined` for a provider that does not supply confinement. Each implementation keeps program state separate between runs and terminates and awaits active executions during disposal.
 
 <!-- BEGIN GENERATED cordis-surface (gen-cordis-catalog.ts) — do not edit between markers -->
 

+ 1 - 1
docs/subsystems/code-runtime.zh.md

@@ -192,7 +192,7 @@ interface CodeRunFailure {
 
 ## 服务
 
-`CodeRuntime` 定义于 [`src/index.ts`](../../packages/code-runtime/code-runtime/src/index.ts)。`resolve(request)` 返回完整执行输入,`run(spec)` 执行它们。`language` 选择支持的程序呈现;`isolation` 描述执行基底,不作安全声明。`sandboxMode` 声明文件策略支持,不提供约束的提供方返回 `undefined`。每个实现将各次运行的程序状态分离,并在资源释放期间终止且等待活跃执行。
+`CodeRuntime` 定义于 [`src/index.ts`](../../packages/code-runtime/code-runtime/src/index.ts)。`resolve(request)` 返回完整执行输入,`run(spec)` 执行它们。`executionInstructions` 提供由运行时拥有的使用说明,供消费方呈现。`language` 选择支持的程序呈现;`isolation` 描述执行基底,不作安全声明。`sandboxMode` 声明文件策略支持,不提供约束的提供方返回 `undefined`。每个实现将各次运行的程序状态分离,并在资源释放期间终止且等待活跃执行。
 
 <!-- BEGIN GENERATED cordis-surface (gen-cordis-catalog.ts) — do not edit between markers -->
 

+ 2 - 2
packages/code-runtime/code-runtime-node/README.i18n.yaml

@@ -2,5 +2,5 @@
 # side as of the last confirmed-consistent state. Both languages carry equal authority;
 # after editing either side, bring the other along and re-record with:
 #   pnpm run verify-translation-pairing --write packages/code-runtime/code-runtime-node/README.md
-README.md: 4897656b6b42a7a5b38401576506088130d7b92a
-README.zh.md: 83c17be7c1d3a0c9b6d1ac5b7e1c2dd647006914
+README.md: a5285ae296b4f3380d8fc593f54f12fd68355a7a
+README.zh.md: 762e5912497d1ce3388305655514eb5faa2b4540

+ 1 - 1
packages/code-runtime/code-runtime-node/README.md

@@ -65,7 +65,7 @@ Direct filesystem, network and subprocess operations remain Node operations, sub
 
 ### Deadlines and cancellation
 
-The PTC consumer exposes per-call timeout and approved sandbox choices as described in [dsh-tools](../../core/tools/README.md#ptc-mode). The runtime's readonly `timeout` descriptor reports its effective default and maximum to that consumer.
+The PTC consumer exposes per-call timeout and approved sandbox choices as described in [dsh-tools](../../core/tools/README.md#ptc-mode). The runtime's readonly `timeout` descriptor reports its effective default and maximum to that consumer. Its `executionInstructions` describes fresh Node state, direct Node APIs, the empty program environment and file policy in the model-visible schema.
 
 The elapsed deadline covers runtime setup and execution, including time awaiting nested tools or approval. It is not a CPU meter. Timeout or cancellation stops a synchronous loop through the host's managed process owner; successful completion also cleans that managed range. The timer stops when an outcome is selected, before cleanup, so the returned call can take longer than its execution deadline while cleanup settles.
 

+ 1 - 1
packages/code-runtime/code-runtime-node/README.zh.md

@@ -65,7 +65,7 @@ kind: "package-reference"
 
 ### 截止时间与取消
 
-PTC 消费方按 [dsh-tools](../../core/tools/README.zh.md#ptc-mode) 的说明公开逐次超时与经审批的沙箱选择。运行时只读 `timeout` 描述符向该消费方报告有效默认值与上限。
+PTC 消费方按 [dsh-tools](../../core/tools/README.zh.md#ptc-mode) 的说明公开逐次超时与经审批的沙箱选择。运行时只读 `timeout` 描述符向该消费方报告有效默认值与上限。 其 `executionInstructions` 在面向模型的 schema 中说明全新 Node 状态、直接 Node API、空程序环境和文件策略。
 
 经过时间截止覆盖运行时准备和执行,包括等待嵌套工具或审批的时间。它不是 CPU 计量器。超时或取消通过 Host 的受管进程所有者停止同步循环;成功完成也会清理该受管范围。选择结果后、清理前停止计时器,因此调用可能要在执行截止之后等待清理结算才返回。
 

+ 3 - 0
packages/code-runtime/code-runtime-node/src/index.ts

@@ -64,6 +64,9 @@ export class NodeCodeRuntime extends CodeRuntime {
   })
   readonly language = 'typescript'
   readonly isolation = 'process'
+  override get executionInstructions(): string {
+    return 'Each call runs in a fresh Node process. Node APIs are available through await import(...). Relative paths use the supplied working directory; process.env starts empty. Direct filesystem access follows this execution\'s sandbox policy.'
+  }
   private readonly config: ResolvedConfig
   private readonly live = new Set<LiveRun>()
   private disposed = false

+ 1 - 0
packages/code-runtime/code-runtime-node/tests/runtime.spec.ts

@@ -132,6 +132,7 @@ describe('Node program process', () => {
 
   it('uses the default deadline and caps explicit requests', async () => {
     const { runtime } = await setup()
+    expect(runtime.executionInstructions).toBe('Each call runs in a fresh Node process. Node APIs are available through await import(...). Relative paths use the supplied working directory; process.env starts empty. Direct filesystem access follows this execution\'s sandbox policy.')
     expect(runtime.resolve({ program: '', bindings: [] }).timeoutMs).toBe(120_000)
     expect(runtime.resolve({ program: '', bindings: [], timeoutMs: 900_000 }).timeoutMs).toBe(600_000)
     for (const timeoutMs of [0, -1, NaN, Infinity]) expect(() => runtime.resolve({ program: '', bindings: [], timeoutMs })).toThrow()

+ 2 - 2
packages/code-runtime/code-runtime/README.i18n.yaml

@@ -2,5 +2,5 @@
 # side as of the last confirmed-consistent state. Both languages carry equal authority;
 # after editing either side, bring the other along and re-record with:
 #   pnpm run verify-translation-pairing --write packages/code-runtime/code-runtime/README.md
-README.md: ede55ec882cc8d51f0457800d6c79c31145882c4
-README.zh.md: 938ccd0dcfa37dbc237f8f8b016763053b4e0ea2
+README.md: 162d875966b0225b629a722986757035e30082e9
+README.zh.md: 9f794d1c65b165e302e1d2349dc169bd672d00c3

+ 2 - 0
packages/code-runtime/code-runtime/README.md

@@ -70,6 +70,8 @@ The package is the Service Definition role of the code-execution capability seam
 
 The readonly `timeout` descriptor exposes `{ defaultMs, maxMs }` for a provider supporting per-call overrides; `undefined` means that the consumer must omit the field. It reports presentation values, while `resolve` remains the validation and clamping authority.
 
+`executionInstructions` supplies provider-owned usage guidance, or an empty string when none is needed. Consumers can include it in their program presentation without identifying the provider from its language or isolation descriptor; PTC includes it in the logged `run_code` schema.
+
 `resolve(request)` owns supported option validation and deployment defaulting. `run(spec)` executes the complete inputs and resolves program outcomes after cleanup. Language and substrate descriptors guide presentation; `sandboxMode` indicates whether the consumer can pass a resolved file policy. Neither descriptors nor a successful program result substitute for the backend's reported enforcement facts.
 
 The exhaustive semantics live in the [code runtime subsystem reference](../../../docs/subsystems/code-runtime.md); the exact signatures are in [`src/index.ts`](src/index.ts).

+ 2 - 0
packages/code-runtime/code-runtime/README.zh.md

@@ -70,6 +70,8 @@ binding-global 与 error-class 名称是语言可移植的:必须匹配 `[A-Za
 
 只读 `timeout` 描述符为支持逐次覆盖的提供方公开 `{ defaultMs, maxMs }`;`undefined` 表示消费方必须省略该字段。它报告呈现值,验证与截断仍由 `resolve` 负责。
 
+`executionInstructions` 提供由运行时拥有的使用说明;不需要说明时返回空字符串。消费方可将其纳入程序呈现,无需根据语言或隔离描述符识别提供方;PTC 将它纳入已记录的 `run_code` schema。
+
 `resolve(request)` 负责支持选项的验证与部署默认值。`run(spec)` 执行完整输入,并在清理后返回程序结果。语言和执行基底描述符指导呈现;`sandboxMode` 表示消费方能否传入已解析文件策略。描述符与程序成功结果都不能代替后端报告的强制能力事实。
 
 穷尽式语义见[代码运行时子系统参考](../../../docs/subsystems/code-runtime.zh.md);确切签名见 [`src/index.ts`](src/index.ts)。

+ 3 - 0
packages/code-runtime/code-runtime/src/index.ts

@@ -121,6 +121,9 @@ export abstract class CodeRuntime extends Service {
    */
   abstract readonly isolation: string
 
+  /** Provider-owned program usage guidance for consumers to present alongside the source language. */
+  get executionInstructions(): string { return '' }
+
   /** Deployment file-policy mode, or undefined for a provider without confinement support. */
   get sandboxMode(): SandboxMode | undefined { return undefined }
 

+ 2 - 2
packages/core/tools/README.i18n.yaml

@@ -2,5 +2,5 @@
 # side as of the last confirmed-consistent state. Both languages carry equal authority;
 # after editing either side, bring the other along and re-record with:
 #   pnpm run verify-translation-pairing --write packages/core/tools/README.md
-README.md: 8b93c831a7570e6521dc5fdffb18f76619e945b1
-README.zh.md: 1d4ecfbcf1e5b5af96df6217647b2659e836bb51
+README.md: 4304e447a57bbd87a6661ffe8cff574fadb8a3d5
+README.zh.md: fbe49361fcd742911eb98aa62a905eb84fd151d4

+ 1 - 1
packages/core/tools/README.md

@@ -126,7 +126,7 @@ Under `ptc` or `both`, the registry exposes the reserved `run_code` transport pl
 
 New sub-calls use `<parent>:ptc:<n>` ids. Consumers treat these ids as opaque and correlate events by exact equality; restored historical ids retain their original bytes. The [PTC mode decision](../../../.agents/notes/implemented/feature/2026-06-15-ptc.md) owns durable naming and restoration rules.
 
-`run_code` accepts `timeoutMs` when the mounted runtime supports an override; its schema reports the configured default and maximum. The Node default is 120,000 ms with a 600,000 ms cap, including nested tool and approval waits. A wider `sandbox_permissions` mode requires a non-empty `justification` and approval before the program starts. The grant applies to that complete execution; standing Session policy and nested tools retain their own authority. Programs are never replayed automatically: inspect earlier effects before explicitly retrying a denied program.
+`run_code` accepts `timeoutMs` when the mounted runtime supports an override; its schema reports the configured default and maximum, the runtime's usage instructions and the Session working directory. The Node default is 120,000 ms with a 600,000 ms cap, including nested tool and approval waits. A wider `sandbox_permissions` mode requires a non-empty `justification` and approval before the program starts. The grant applies to that complete execution; standing Session policy and nested tools retain their own authority. Programs are never replayed automatically: inspect earlier effects before explicitly retrying a denied program.
 
 <a id="extension-points"></a>
 ### Extension points

+ 1 - 1
packages/core/tools/README.zh.md

@@ -126,7 +126,7 @@ ctx.tools.register(defineTool({
 
 新子调用使用 `<parent>:ptc:<n>` 标识。消费方将这些标识视为不透明值,并通过精确相等关联事件;恢复的历史标识保留原始字节。[PTC mode 决策](../../../.agents/notes/implemented/feature/2026-06-15-ptc.zh.md) 负责持久化命名与恢复规则。
 
-当已挂载运行时支持覆盖时,`run_code` 接受 `timeoutMs`;其 schema 报告配置的默认值和上限。Node 默认值为 120,000 ms,上限为 600,000 ms,包含嵌套工具和审批等待。更宽的 `sandbox_permissions` 模式要求非空 `justification`,并在程序启动前获得审批。授权仅用于该次完整执行;常驻 Session 策略与嵌套工具保留各自权限。程序不会自动重放:显式重试被拒程序前,应检查先前已发生的效果。
+当已挂载运行时支持覆盖时,`run_code` 接受 `timeoutMs`;其 schema 报告配置的默认值和上限、运行时使用说明及 Session 工作目录。Node 默认值为 120,000 ms,上限为 600,000 ms,包含嵌套工具和审批等待。更宽的 `sandbox_permissions` 模式要求非空 `justification`,并在程序启动前获得审批。授权仅用于该次完整执行;常驻 Session 策略与嵌套工具保留各自权限。程序不会自动重放:显式重试被拒程序前,应检查先前已发生的效果。
 
 <a id="extension-points"></a>
 ### 扩展点

+ 7 - 1
packages/core/tools/src/ptc.ts

@@ -737,7 +737,13 @@ export function createRunCodeTool(registry: ToolRuntime, options: RunCodeBridgeO
   // is the least invasive point that still emits the loaded runtime's language.
   Object.defineProperty(definition, 'description', {
     enumerable: true,
-    get: () => resolveFlavor(peekRuntime).description + escalationGuidance(peekRuntime()),
+    get: () => {
+      const runtime = peekRuntime()
+      const instructions = runtime?.executionInstructions
+      return resolveFlavor(peekRuntime).description
+        + (instructions ? ` ${instructions} The working directory is the Session's current directory.` : '')
+        + escalationGuidance(runtime)
+    },
   })
   Object.defineProperty(definition, 'parameters', {
     enumerable: true,

+ 4 - 0
packages/core/tools/tests/ptc.spec.ts

@@ -2005,6 +2005,7 @@ describe('per-program execution controls', () => {
     if (approval) await state.ctx.plugin(ApprovalService, { policy: 'ask' })
     Object.defineProperties(state.runtime, {
       sandboxMode: { get: () => 'read-only' },
+      executionInstructions: { get: () => 'Programs start with an empty environment.' },
       timeout: { get: () => ({ defaultMs: 120_000, maxMs: 600_000 }) },
     })
     const session = Session.create(SessionId('program-controls'))
@@ -2024,12 +2025,15 @@ describe('per-program execution controls', () => {
       expect(JSON.stringify(schema.parameters)).toContain('Default 120000; capped at 600000')
       expect(JSON.stringify(schema.parameters)).toContain('sandbox_permissions')
       expect(schema.description).toContain('Nested tools retain their own policies')
+      expect(schema.description).toContain('Programs start with an empty environment.')
+      expect(schema.description).toContain("The working directory is the Session's current directory.")
     } finally { await ctx.fiber.dispose() }
     const python = await setup({ runtime: { language: 'python' } })
     try {
       const schema = python.tools.schemas().find(tool => tool.name === RUN_CODE_NAME)!
       expect(JSON.stringify(schema.parameters)).not.toContain('timeoutMs')
       expect(JSON.stringify(schema.parameters)).not.toContain('sandbox_permissions')
+      expect(schema.description).not.toContain('Programs start with an empty environment.')
       const rejected = await python.tools.execute({
         callId: ToolCallId('hidden-timeout'), name: RUN_CODE_NAME, signal: testToolSignal,
         arguments: { code: 'pass', description: 'Try unsupported timeout', timeoutMs: 5 },