@deepseek-ai/dsh-cordis-host-runner 0.0.1-rc.3
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/LICENSE +28 -0
- package/README.i18n.yaml +6 -0
- package/README.md +72 -0
- package/README.zh.md +72 -0
- package/lib/index.js +2573 -0
- package/lib/invariant.js +25 -0
- package/lib/typert.host.d.ts +3 -0
- package/lib/typert.host.js +1897 -0
- package/lib/typert.remote-client.d.ts +55 -0
- package/lib/typert.remote-client.js +769 -0
- package/lib/types/guard.d.ts +71 -0
- package/lib/types/guard.js +766 -0
- package/lib/types/index.d.ts +270 -0
- package/lib/types/index.js +1151 -0
- package/lib/types/inspect-registry.d.ts +72 -0
- package/lib/types/inspect-registry.js +192 -0
- package/lib/types/invariant.d.ts +16 -0
- package/lib/types/invariant.js +24 -0
- package/lib/types/lifecycle.d.ts +29 -0
- package/lib/types/lifecycle.js +49 -0
- package/lib/types/registry.d.ts +225 -0
- package/lib/types/registry.js +131 -0
- package/lib/types/sandbox.d.ts +93 -0
- package/lib/types/sandbox.js +223 -0
- package/lib/types/types.d.ts +359 -0
- package/lib/types/types.js +6 -0
- package/package.json +78 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
BSD 3-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026, DeepSeek
|
|
4
|
+
|
|
5
|
+
Redistribution and use in source and binary forms, with or without
|
|
6
|
+
modification, are permitted provided that the following conditions are met:
|
|
7
|
+
|
|
8
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
9
|
+
list of conditions and the following disclaimer.
|
|
10
|
+
|
|
11
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
12
|
+
this list of conditions and the following disclaimer in the documentation
|
|
13
|
+
and/or other materials provided with the distribution.
|
|
14
|
+
|
|
15
|
+
3. Neither the name of the copyright holder nor the names of its
|
|
16
|
+
contributors may be used to endorse or promote products derived from
|
|
17
|
+
this software without specific prior written permission.
|
|
18
|
+
|
|
19
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
20
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
21
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
22
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
23
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
24
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
25
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
26
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
27
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
28
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
package/README.i18n.yaml
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
|
|
2
|
+
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
|
3
|
+
# after editing either side, bring the other along and re-record with:
|
|
4
|
+
# pnpm run verify-translation-pairing --write packages/extensions/cordis-host-runner/README.md
|
|
5
|
+
README.md: f09e7506fe24676ea95b3ae490b55ae120bfad5f
|
|
6
|
+
README.zh.md: f60d3a64ecb1e90427b966c820a857e62d65b375
|
package/README.md
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# @deepseek-ai/dsh-cordis-host-runner
|
|
2
|
+
|
|
3
|
+
English | [中文](README.zh.md)
|
|
4
|
+
|
|
5
|
+
The host half of model-mounted dynamic packages: the definition registry, the `node:vm` sandbox and fiber lifecycle for host halves, the invoke handler table, and the run round trip a browser page carries out. Provided as `ctx.dynamicCordisRunner`. The model-facing tools live in [`@deepseek-ai/dsh-tool-cordis`](../tool-cordis/README.md); the browser half is loaded by [`@deepseek-ai/dsh-cordis-client-runner`](../cordis-client-runner/README.md).
|
|
6
|
+
|
|
7
|
+
## What it does
|
|
8
|
+
|
|
9
|
+
Two phases: `define` only records, and everything with an effect hangs off a run.
|
|
10
|
+
|
|
11
|
+
- `define` / `undefine` own a definition's life. `define` trims and requires the metadata, prechecks each half's syntax by compiling it (running nothing), mints `dyn-<n>`, and records the definition against the session that asked — it has no effect to roll back, so unparseable code is refused before an id exists. `undefine` stops a running definition first, then forgets it. Neither crosses the wire: only the model's own tool call defines.
|
|
12
|
+
- `run` answers the model's request to run one definition, and its two shapes differ by whose business the package is. A host-only package is this process's own: the host half is evaluated in the vm under the `cordis-dynamic` group fiber and the call returns. A package with a browser half has to be carried out by a page, so `run` becomes an answerable round trip — it emits `cordis/request-run`, suspends, and is settled by a person allowing or declining it. There is no timer; the caller's `AbortSignal` (the asking turn was cancelled) is the only other way out, and it announces the cancellation so other pages stop offering an answer. Whether any page will answer is not knowable when the request is sent — a page that received it may still never answer, so a deployment with no page connected suspends like any other unanswered request and ends in `cancelled`. `run` has no wire face — `cordis_run` calls it in process.
|
|
13
|
+
- `runHostHalf` / `getClientCode` are the steps an allowed page walks, host half first, so a host-half failure short-circuits before the browser has moved. `runHostHalf` is idempotent by contract: a running package is bound rather than evaluated again, concurrent calls for one definition evaluate it once, and `startedHere` names the caller that did. `getClientCode` then hands that one page the browser-half source, refusing a definition that is gone, has no browser half, or is not running. Code never rides an announcement, so this is the only way it reaches a browser.
|
|
14
|
+
- `resolveRequestRun` closes the round trip with the answering page's verdict, and broadcasts `cordis/request-run-resolved` so every other page drops the pending affordance. The first answer wins; a later or unknown request id is accepted and ignored. A success naming a revision the registry has moved past is refused rather than applied (`accepted: false`, request still suspended), because the page that answered loaded a dispatch that is no longer live. A failing verdict unwinds the host half only when this same request evaluated it, so a page that cannot load its own half never stops a package the other pages are using.
|
|
15
|
+
- `stop` unwinds one live dispatch — handlers dropped, host-half fiber disposed to quiescence, `dynamicCordisRunner/retract` broadcast — and leaves the definition runnable.
|
|
16
|
+
- `inventory` answers the whole registry, unaddressed by session and with each row naming the session that owns it, because the run-control surface is global. Listing is not acting: every acting verb still checks that ownership. Each row also names whether the definition has a browser half, so a run-control surface offers loading it into the current page only when there is a half to load. `snapshot` is its session-scoped host-local counterpart, carrying each live host half's fiber so `cordis_inspect` can render provides/waiting/state itself (a fiber cannot cross the wire).
|
|
17
|
+
- `reportRenderFailure` records what a page saw a LOADED browser half do wrong at render time. Rendering happens strictly after a load succeeded, so a run has already answered `ok` by then: this report is fire-and-forget, carries no settle authority, and never touches `resolveRequestRun` or any part of the run outcome — **it is not the retired v2 `report`/ack**. The host keeps the last failure per definition across every page (a second page reporting overwrites), and a fresh run, a stop, or an undefine clears it, so the model is never shown a failure from a dispatch that no longer exists. The browser-half face keeps its own "what THIS page is showing now"; the two answer different questions rather than duplicating one. A report for a definition the reporting session does not own is dropped, because the reporting path must never fail a render.
|
|
18
|
+
- `invoke` routes one call from a package's browser half to a method its own host half registered with `harness.handle`. The infrastructure only routes — no host-to-browser direction exists.
|
|
19
|
+
|
|
20
|
+
A refusal from `run` or `stop` names one of `definition-missing`, `host-half-failed`, `client-half-failed`, `rejected`, `cancelled`, or `not-running`; the last three are answers rather than defects — a person declined, the asking turn ended, or there was nothing running to stop.
|
|
21
|
+
|
|
22
|
+
A definition another session defined reads as absent rather than forbidden, so nothing leaks across sessions. `invoke` and `resolveRequestRun` carry no session at all: a component's call and a page's answer are page-global facts, not one session's.
|
|
23
|
+
|
|
24
|
+
Four forwarded events belong to this feature, declared by this package on its client-safe [`./types`](src/types.ts) subpath and allowlisted for delivery by [`@deepseek-ai/dsh-api-remotes`](../../api/remotes/README.md), which is what lets a browser reach them through `ctx.remote.$on`: `cordis/request-run` (`{requestId, agentId, id, name, purpose}` — metadata, never code), `cordis/request-run-resolved` (`{requestId, outcome}`), `dynamicCordisRunner/package` (`{id, name, rev}`), and `dynamicCordisRunner/retract` (`{id, rev}`). The last two are a symmetric pair announcing run state — every fresh start and every stop, whether or not the package has a browser half.
|
|
25
|
+
|
|
26
|
+
## Storage stance
|
|
27
|
+
|
|
28
|
+
The registry is process memory and the only source of truth. The session log carries a define call's metadata — never its code — so a restarted process legitimately has no definitions, and a card whose id no longer resolves says exactly that rather than pretending it can run. Nothing here is written to disk, and no definition is restored automatically; a reloaded page holds nothing until someone runs a package again, which is what makes it bind the live host half and re-fetch the browser half.
|
|
29
|
+
|
|
30
|
+
## Trust stance
|
|
31
|
+
|
|
32
|
+
The vm sandbox isolates globals but is not a security boundary: Node globals are absent or redirect to Cordis services (`ctx.fs`, `ctx.web`, `ctx.bash`, the timer helpers), and a host half receives a façade without framework internals, yet the services it declares reach the live runtime. Treat a dynamic package like bash access — see the [self-referential toolset Agent Note](../../../.agents/notes/implemented/feature/2026-07-08-self-referential-cordis-toolset.md).
|
|
33
|
+
|
|
34
|
+
## Config
|
|
35
|
+
|
|
36
|
+
| Field | Default | Meaning |
|
|
37
|
+
|---|---|---|
|
|
38
|
+
| `vmTimeoutMs` | `5000` | Milliseconds the synchronous portion of a host half may run in the vm before evaluation is aborted |
|
|
39
|
+
|
|
40
|
+
One field is all there is: a run request waits for a person, so the round trip has no deadline of its own.
|
|
41
|
+
|
|
42
|
+
## Export shape
|
|
43
|
+
|
|
44
|
+
Service package: default-exports `DynamicCordisRunnerService` (service key `dynamicCordisRunner`), with `./types` carrying the payload shapes the `dynamicCordisRunner` remote namespace and its consumers share. The `define` / `undefine` shapes stay inside the package, because they never cross the wire.
|
|
45
|
+
|
|
46
|
+
## Model Experience
|
|
47
|
+
|
|
48
|
+
### Refusals and teaching errors relayed by the cordis tools
|
|
49
|
+
|
|
50
|
+
#### What the model sees
|
|
51
|
+
|
|
52
|
+
Nothing directly: this package registers no tool and injects no prompt. Its refusals reach the model through the `cordis_*` tool results that call it — an unparseable half names the offending line, a missing definition explains that definitions live in memory only, a `rejected` or `cancelled` run reports that a person declined or the turn ended rather than that anything failed, and a failed browser-half load carries the answering page's own error text.
|
|
53
|
+
|
|
54
|
+
#### Token effect
|
|
55
|
+
|
|
56
|
+
None of its own: every message above is carried by the calling tool's result.
|
|
57
|
+
|
|
58
|
+
#### KV Cache effect
|
|
59
|
+
|
|
60
|
+
A host half that registers tools changes the next request's tool view, which invalidates prefix reuse from the first changed schema token; running or stopping a package with no tool registrations is prefix-neutral.
|
|
61
|
+
|
|
62
|
+
## Known Limitations and Deferred Work
|
|
63
|
+
|
|
64
|
+
- **A successful run does not mean the UI rendered.** `run` returns once the answering page has LOADED the browser half; React renders afterwards, so a component that throws cannot possibly appear in the run receipt. The failure surfaces through `reportRenderFailure` and is read back with `cordis_inspect what:"temporary"`; the run result says so rather than implying success.
|
|
65
|
+
|
|
66
|
+
- A package with a browser half **suspends where no page is connected** — headless and ACP deployments hold the run until the asking turn is cancelled, because a forwarded event reports nothing about who received it. Host-only packages are unaffected.
|
|
67
|
+
- A suspended run request has **no timeout**: it waits for a person until the asking turn is cancelled, so unattended automation cannot use packages with a browser half.
|
|
68
|
+
- `vmTimeoutMs` bounds only synchronous evaluation; an async host-half body escapes it, matching the toolset's cooperative trust stance.
|
|
69
|
+
- `runHostHalf` carries no request id, so "which request evaluated this host half" is attributed host-side to the most recently armed request for that definition; several concurrent run requests for one definition would need that rule revisited.
|
|
70
|
+
- A success answer naming a superseded revision is refused (`accepted: false`) and leaves the request suspended, so the model's call ends only through a valid answer or its own cancellation. Settling it would take a fresh orchestration against the live revision, and no page does that today — the [browser half](../cordis-client-runner/README.md) does not read the ack — so in practice such a request is closed by another page's answer or by the caller's cancellation.
|
|
71
|
+
- A browser half's declared `inject` is read from the plugin it returns in the page, so the announcement carries no service-declaration field at all.
|
|
72
|
+
- **`zod` is a runtime dependency of the generated TypeRT faces, not of `src`.** `./typert` and `./remote` resolve to `lib/typert.*.js`, which `tsc` emits unbundled with a bare `import { z } from 'zod'`, so the package must declare it (the `@deepseek-ai/dsh-goal` precedent) and `knip.json` must ignore it for this workspace — knip reads source, and these faces are build products. Nothing in `src` imports zod.
|
package/README.zh.md
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# @deepseek-ai/dsh-cordis-host-runner
|
|
2
|
+
|
|
3
|
+
[English](README.md) | 中文
|
|
4
|
+
|
|
5
|
+
由模型挂载的动态包在 host 侧的那一半:定义注册表、host 半所用的 `node:vm` 沙箱与 fiber 生命周期、invoke handler 表,以及由某个浏览器页面执行的 run 往返。以 `ctx.dynamicCordisRunner` 提供。面向模型的工具在 [`@deepseek-ai/dsh-tool-cordis`](../tool-cordis/README.md) 中;浏览器半由 [`@deepseek-ai/dsh-cordis-client-runner`](../cordis-client-runner/README.md) 装载。
|
|
6
|
+
|
|
7
|
+
## 功能
|
|
8
|
+
|
|
9
|
+
分两个阶段:`define` 只做登记,一切带副作用的动作都挂在一次 run 上。
|
|
10
|
+
|
|
11
|
+
- `define`/`undefine` 掌管一个定义的生命周期。`define` 对元数据做首尾去空白与必填校验,通过编译预检每一半的语法(不执行任何代码),铸出 `dyn-<n>`,并把该定义登记在发起调用的会话名下——它没有任何可回滚的副作用,所以无法解析的代码在拿到 id 之前就被拒绝。`undefine` 先停掉正在运行的定义,再把它忘掉。两者都不上 wire:只有模型自己的工具调用才会 define。
|
|
12
|
+
- `run` 回答模型「运行某个定义」的请求,它的两种形态取决于这个包是谁的事。只有 host 半的包是本进程自己的事:host 半在 `cordis-dynamic` group fiber 之下于 vm 中求值,调用随即返回。带浏览器半的包必须由一个页面来执行,于是 `run` 变成一次可作答的往返——它 emit `cordis/request-run`、挂起,并由某个人允许或拒绝来结束。这里没有定时器;调用方的 `AbortSignal`(提问的那一轮次被取消)是唯一的另一条出路,而且它会把这次取消播报出去,让其他页面不再提供作答入口。请求发出时**并不知道**会不会有人作答——收到它的页面也可能永远不答,所以没有页面连接的部署与其他未作答请求一样挂起,最终以 `cancelled` 收场。`run` 没有 wire 面——`cordis_run` 在进程内调用它。
|
|
13
|
+
- `runHostHalf`/`getClientCode` 是获得允许的页面依次走的步骤,host 半在先,因此 host 半失败会在浏览器还没动作之前短路。`runHostHalf` 在约定上是幂等的:已在运行的包只做绑定,不再求值;针对同一个定义的并发调用只求值一次,`startedHere` 指出求值的是哪一个调用方。随后 `getClientCode` 把浏览器半的源码交给这一个页面;定义已消失、没有浏览器半、或未在运行时,它会拒绝。代码从不搭乘任何播报,所以这是它到达浏览器的唯一途径。
|
|
14
|
+
- `resolveRequestRun` 用作答页面的结论结束这次往返,并 emit `cordis/request-run-resolved`,让其他每个页面撤下待作答的入口。首答即成;更晚的或未知的 request id 会被接受并忽略。命名了注册表已越过的版本的成功结论会被拒绝而非应用(`accepted: false`,请求仍处于挂起),因为作答的那个页面装载的是一个已不再存活的下发。失败的结论只会在 host 半正是由这次请求求值时才将它回退,因此某个页面装不上自己那一半,绝不会把其他页面正在使用的包停掉。
|
|
15
|
+
- `stop` 回退一次存活的下发——丢弃 handler、把 host 半 fiber dispose(资源释放)到完全停稳、emit `dynamicCordisRunner/retract`——并让该定义仍然可运行。
|
|
16
|
+
- `inventory` 回答整个注册表,不按会话寻址,且每一行都指明拥有该定义的会话,因为运行控制面是全局的。能列出不等于能操作:每个有实际动作的动词仍会检查这份归属。每一行还会指明该定义有没有浏览器半,因此运行控制面只在确有可装载的半时,才提供「装入当前页面」。`snapshot` 是它按会话限定的 host 本地对侧,携带每个存活 host 半的 fiber,供 `cordis_inspect` 自行渲染 provides/waiting/state(fiber 无法跨 wire)。
|
|
17
|
+
- `reportRenderFailure` 记录某个页面看到一个**已装载**的浏览器半在渲染时做错了什么。渲染严格发生在装载成功之后,因此到那时 run 早已回答了 `ok`:这份上报是 fire-and-forget 的,不带任何结算权威,也绝不触碰 `resolveRequestRun` 或 run 结论的任何部分——**它不是那个已退役的 v2 `report`/ack**。host 按定义保留跨所有页面的最后一次失败(第二个页面上报即覆盖),而一次全新的 run、一次 stop 或一次 undefine 都会清掉它,因此模型绝不会看到一次已不存在的下发留下的失败。浏览器半的契约面自己保留一份「**这个页面**当前正在显示什么」;两者回答的是不同的问题,不是同一个问题的两份答案。上报的会话若并不拥有该定义,这次上报会被丢弃,因为上报路径绝不能让一次渲染失败。
|
|
18
|
+
- `invoke` 把一个包的浏览器半发起的一次调用,路由到它自己的 host 半用 `harness.handle` 注册的方法。这套基础设施只做路由:不存在 host 到浏览器的方向。
|
|
19
|
+
|
|
20
|
+
`run` 或 `stop` 的拒绝会给出 `definition-missing`、`host-half-failed`、`client-half-failed`、`rejected`、`cancelled`、`not-running` 之一;后三者是答复而非缺陷——有人拒绝了、提问的那一轮次已结束,或本来就没有在运行的东西可停。
|
|
21
|
+
|
|
22
|
+
别的会话登记的定义读起来是不存在,而不是被禁止,因此不会跨会话泄漏任何东西。`invoke` 与 `resolveRequestRun` 完全不携带会话:组件的一次调用和页面的一次作答都是页面全局的事实,不属于某一个会话。
|
|
23
|
+
|
|
24
|
+
本功能拥有四条转发事件,由本包在其 client-safe 的 [`./types`](src/types.ts) 子路径上声明,并由 [`@deepseek-ai/dsh-api-remotes`](../../api/remotes/README.md) 的白名单准许投递——正是这一点让浏览器能经 `ctx.remote.$on` 收到它们:`cordis/request-run`(`{requestId, agentId, id, name, purpose}`——只有元数据,绝无代码)、`cordis/request-run-resolved`(`{requestId, outcome}`)、`dynamicCordisRunner/package`(`{id, name, rev}`),以及 `dynamicCordisRunner/retract`(`{id, rev}`)。后两者是对称的一对运行状态播报:每次全新启动与每次停止都播,与该包有没有浏览器半无关。
|
|
25
|
+
|
|
26
|
+
## 存储立场
|
|
27
|
+
|
|
28
|
+
注册表就是进程内存,也是唯一真源。会话日志只承载一次 define 调用的元数据,绝不承载它的代码:因此进程重启后确实没有任何定义,这是合理的;而 id 已无法解析的卡片会如实说明这一点,不会假装自己还能运行。本包不向磁盘写任何东西,也不会自动恢复任何定义;刷新过的页面手上什么都没有,直到有人再次运行某个包——正是这一步让它绑定存活的 host 半并重新取回浏览器半。
|
|
29
|
+
|
|
30
|
+
## 信任立场
|
|
31
|
+
|
|
32
|
+
vm 沙箱隔离全局变量,但不是安全边界:Node 全局变量不存在,或重定向到 Cordis 服务(`ctx.fs`、`ctx.web`、`ctx.bash` 以及定时器 helper),host 半收到的是不含框架内部机制的 façade,但它声明的服务仍会触达存活运行时。应当像对待 bash 访问一样对待动态包,参见[自引用工具集 Agent Note](../../../.agents/notes/implemented/feature/2026-07-08-self-referential-cordis-toolset.md)。
|
|
33
|
+
|
|
34
|
+
## 配置
|
|
35
|
+
|
|
36
|
+
| 字段 | 默认值 | 含义 |
|
|
37
|
+
|---|---|---|
|
|
38
|
+
| `vmTimeoutMs` | `5000` | host 半在 vm 中同步执行的那部分被中止求值前可运行的毫秒数 |
|
|
39
|
+
|
|
40
|
+
就这一个字段:一次 run 请求等的是人,所以这趟往返本身没有任何截止期限。
|
|
41
|
+
|
|
42
|
+
## 导出形状
|
|
43
|
+
|
|
44
|
+
服务包:默认导出 `DynamicCordisRunnerService`(服务键 `dynamicCordisRunner`),`./types` 则承载 `dynamicCordisRunner` remote namespace 与其消费方共享的载荷形状。`define`/`undefine` 的形状留在包内部,因为它们从不跨 wire。
|
|
45
|
+
|
|
46
|
+
## 模型体验
|
|
47
|
+
|
|
48
|
+
### 经 cordis 工具转达的拒绝与教学式错误
|
|
49
|
+
|
|
50
|
+
#### 模型看到的内容
|
|
51
|
+
|
|
52
|
+
没有直接可见的内容:本包不注册任何工具,也不注入提示词。它的拒绝经调用它的 `cordis_*` 工具结果到达模型——无法解析的半会指出出错的那一行,缺失的定义会解释定义只活在内存里,`rejected` 或 `cancelled` 的 run 报告的是有人拒绝或该轮次已结束而非出了故障,浏览器半装载失败则带上作答页面自己的错误文本。
|
|
53
|
+
|
|
54
|
+
#### Token 影响
|
|
55
|
+
|
|
56
|
+
本包自身没有:上述每条消息都由调用它的那个工具的结果承载。
|
|
57
|
+
|
|
58
|
+
#### KV Cache 影响
|
|
59
|
+
|
|
60
|
+
注册工具的 host 半会改变下一次请求的工具视图,从第一个变化的 schema token 起使前缀复用失效;运行或停止一个不注册任何工具的包对前缀不产生影响。
|
|
61
|
+
|
|
62
|
+
## 已知限制与暂缓事项
|
|
63
|
+
|
|
64
|
+
- **run 成功不等于 UI 渲染成功。** 只要作答页面**已装载**浏览器半,`run` 就会返回;React 是随后才渲染的,因此一个抛异常的组件根本不可能出现在 run 的回执里。该失败经 `reportRenderFailure` 浮现,并通过 `cordis_inspect what:"temporary"` 读回;run 的结果会把这一点说出来,而不是暗示成功。
|
|
65
|
+
|
|
66
|
+
- 带浏览器半的包在**没有页面连接的地方会挂起**——headless 与 ACP(Agent Client Protocol)部署会把这次 run 一直挂到提问的轮次被取消,因为转发事件不回报谁收到了它。只有 host 半的包不受影响。
|
|
67
|
+
- 挂起的 run 请求**没有超时**:它一直等人,直到提问的那一轮次被取消,因此无人值守的自动化用不了带浏览器半的包。
|
|
68
|
+
- `vmTimeoutMs` 只约束同步求值;async 的 host 半函数体会逃出该上限,这与该工具集基于协作的信任立场一致。
|
|
69
|
+
- `runHostHalf` 不携带 request id,因此「这个 host 半是哪次请求求值的」由 host 侧归因到该定义最近一次挂起的请求;若同一个定义出现多个并发 run 请求,这条规则需要重新审议。
|
|
70
|
+
- 命名了已被取代版本的成功结论会被拒绝(`accepted: false`)并让该请求继续挂起,因此模型这次调用只能靠一次有效作答或自身被取消才结束。要把它结算掉,需要对着存活版本重新走一遍编排,而当前没有任何页面会这么做——[浏览器半](../cordis-client-runner/README.md)不读这个 ack——所以这类请求实际上由别的页面作答、或由调用方取消来收尾。
|
|
71
|
+
- 浏览器半声明的 `inject` 是从它在页面里返回的插件上读出的,因此播报完全不携带服务声明字段。
|
|
72
|
+
- **`zod` 是生成的 TypeRT 契约面的运行时依赖,不是 `src` 的依赖。** `./typert` 与 `./remote` 解析到 `lib/typert.*.js`,`tsc` 以不打包的形式产出它们,其中带有裸的 `import { z } from 'zod'`,所以本包必须声明它(沿用 `@deepseek-ai/dsh-goal` 的先例),而 `knip.json` 必须在这个 workspace 里忽略它:knip 读的是源码,而这些契约面是构建产物。`src` 里没有任何代码 import zod。
|