@tbox.cn/app-template-agent 0.10.13 → 0.10.14

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/AGENTS.md CHANGED
@@ -49,7 +49,7 @@ apps/client/src/cards/registry.ts # 卡片注册表快照(CardType
49
49
  apps/server/src/index.ts # 服务端入口(HTTP + WS + Vite middleware + createServerContext + createEngineFromContext)
50
50
  apps/server/src/modules.ts # 服务端模块装配(registerAll)
51
51
  apps/server/src/module-ports.ts # 模块 ports 动态装配(LinkedPanel/bumpin 数据源;契约派生 + 漂移守卫)
52
- packages/provider-custom/src/server/index.ts # 自定义 API adapter 实施落点(步骤见该包 AGENTS.md)
52
+ packages/provider-custom/src/server/index.ts # 自定义 API adapter 实施落点(指引见 packages/provider-custom/INTEGRATION.md)
53
53
  config/ # chat/model/plugin 配置
54
54
  ```
55
55
 
@@ -90,111 +90,10 @@ CLI 免安装,命令均经 `npx --yes @tbox.cn/app-cli <cmd>` 运行(下表
90
90
 
91
91
  ## 自定义服务集成(provider-custom)
92
92
 
93
- 自定义 API = 服务的真实后端由你自己对接:声明住在 `config/integrations.json`,adapter
94
- 代码住在 `packages/provider-custom/`。服务后端三选一:Mock(演示数据,装 provider-mock
95
- 即用)/ 自定义 API(你自己的后端接口——本节流程)/ 服务商集成(官方 provider 包,
96
- `module add` + `provider bind`)。收到「为某服务/模块/应用接入自定义 API」(或「对接
97
- 我的 API」等同义说法)的请求时按四步走:
98
-
99
- 1. **说明并收集信息**:目标不在已装模块服务槽词汇内 → 说明未装该模块,引导
100
- `module add` 或 `new module`,不进入后续步骤。在词汇内 → 简要说明目标——服务 = 槽
101
- 展示名与描述 + Port 能力(消费模块 `src/server/ports.ts`(或 `ports/` 目录)或
102
- `@app/contracts-mall`);模块 = `tbox.module.json` `declare.owns` 清单逐个一句
103
- (`*.snapshot` 聚合槽在清单内,数据随底层服务派生——落声明时跳过);应用 = 已装业务模块服务清单概览
104
- (空装配 chat 形态无业务服务,不适用)。再向用户收集:API 地址、认证方式(密钥值经
105
- 平台凭据引用,不进 prompt/代码/配置明文)、可选连接参数。用户已给出的不重复问。
106
- 未实施前调用报 `PROVIDER_NOT_IMPLEMENTED` 属预期中间态。
107
-
108
- #### integrations.json 结构 schema 参考
109
-
110
- 完整接口见 `packages/contracts/src/providers.ts`,下表是给落声明用的字段速查。
111
-
112
- **InlineVendorDeclaration**(providers.ts:140)——**仅 `services.<slot>.provider` 层合法**(`modules[].provider` 与 `integrations.provider` 只接受字符串厂商名):
113
-
114
- | 字段 | 类型 | 必填 | 说明 |
115
- |---|---|---|---|
116
- | `provider` | `string` | ✅ | 厂商名(自定语义化短标识,同一后端多服务共用) |
117
- | `credentialType` | `string` | ✅ | 认证类型:`'-'`=无凭据(仅 local 供给合法)/ SDK 内置 `static-headers-v1` / 自定如 `bearer-v1` |
118
- | `configSchema` | `string` | ❌ | schema 文件路径(相对应用 `config/`),**可选**,无强制 schema 格式 |
119
-
120
- **ConfiguredService**(providers.ts:176)——服务槽绑定:
121
-
122
- | 字段 | 类型 | 必填 | 说明 |
123
- |---|---|---|---|
124
- | `provider` | `string \| InlineVendorDeclaration` | ❌ | 字符串厂商名 **或** 内联声明对象(唯一支持内联对象的层) |
125
- | `implementation` | `string` | ❌ | `id@version` 字面量;字符串厂商可派生可省,内联声明必须显式 |
126
- | `config` | `Record<string, unknown>` | ❌ | 服务级连接参数(明文,如 baseUrl/超时) |
127
- | `credentialRef` | `string` | ❌ | 凭据引用 `secret://<stem>` |
128
- | `instances` | `Record<instId, ServiceInstanceConfig>` | ❌ | 实例激活表;**省略=通配激活,`{}`=零激活(禁)** |
129
-
130
- **ModuleConfig**(providers.ts:192)——模块级(key = install id = `tbox.module.json` id):
131
-
132
- | 字段 | 类型 | 必填 | 说明 |
133
- |---|---|---|---|
134
- | `provider` | `string` | ❌ | **仅字符串厂商,不支持内联声明对象** |
135
- | `config` | `Record<string, unknown>` | ❌ | 模块级共享配置 |
136
- | `resources` | `Record<id, ResourceSpec>` | ❌ | 资源声明(知识库等,不算 binding 面) |
137
-
138
- **IntegrationsConfig**(providers.ts:239)——顶层,仅 `services` 必填:
139
-
140
- | 字段 | 类型 | 必填 | 说明 |
141
- |---|---|---|---|
142
- | `services` | `Record<slot, ConfiguredService>` | ✅ | 服务槽绑定 |
143
- | `provider` | `string` | ❌ | 全局默认厂商(**仅字符串**) |
144
- | `config` | `Record<string, unknown>` | ❌ | 全局默认配置(明文) |
145
- | `configByInstance` | `Record<instId, Record>` | ❌ | 按实例的全局配置覆盖 |
146
- | `credentialRef` | `string` | ❌ | 全局凭据引用 |
147
- | `credentialRefByInstance` | `Record<instId, string>` | ❌ | 实例级凭据(商户级主写位) |
148
- | `instances` | `DeploymentInstance[]` | ❌ | 部署实例注册表(参考表) |
149
- | `defaultInstanceId` | `string \| null` | ❌ | 默认实例 id(单实例免填) |
150
- | `modules` | `Record<install-id, ModuleConfig>` | ❌ | 模块集成位 |
151
-
152
- #### 级联优先级链(resolveEffectiveService,providers.ts:336)
153
-
154
- **provider 头 4 层**(最特异优先):
155
- ```
156
- services[slot].instances[instId].provider → services[slot].provider → modules[owner].provider → integrations.provider
157
- ```
158
-
159
- **config 5 层浅合并**(后者覆盖前者同字段):
160
- ```
161
- integrations.config → integrations.configByInstance[instId] → modules[owner].config → services[slot].config → services[slot].instances[instId].config
162
- ```
163
-
164
- **credentialRef 4 层链**:
165
- ```
166
- services[slot].instances[instId].credentialRef → services[slot].credentialRef → integrations.credentialRefByInstance[instId] → integrations.credentialRef
167
- ```
168
-
169
- **implementation 派生**:显式 `slot.implementation` / `inst.implementation` 优先;字符串厂商缺省则按 `supplies[provider\u0000service]` 查表派生(unique→自动取一 / 0→`BINDING_UNRESOLVED` / 多→要求显式);内联声明必须显式(zod 已拦)。
170
-
171
- > 内联声明对象只在 `services[slot].provider` 层合法。`modules[].provider` 与 `integrations.provider` 只接受字符串厂商名——这是 zod 直接拒导致 fail-visible 的常见错点。
172
-
173
- #### provider 名三处一致
174
-
175
- 取的 provider 名必须下三处同名(任何一处失配则 `PROVIDER_NOT_IMPLEMENTED`):
176
-
177
- 1. `config/integrations.json` 中 `services.<slot>.provider.provider`(内联对象里的 `provider` 字段)
178
- 2. `packages/provider-custom/src/server/index.ts` 里 `ctx.integrations?.registerAdapter('<同名>', 'inline', factory)` 第一参
179
- 3. `config/credentials/${provider名}-${service}.json`(如 `my-parking-api-parking.query.json`)的 stem 前缀
180
-
181
- 2. **落声明**:目标槽已有内联声明则跳过;否则直接编辑 `config/integrations.json`
182
- (CLI provider 命令仅支持字符串厂商)按下表范围写入槽级声明(`{ provider,
183
- credentialType, configSchema? }` + implementation 字面量,仅槽级合法;provider 名自定
184
- 语义化短标识,同一后端的多服务共用同一 provider 名——单键注册,三处一致见上文,见
185
- `packages/provider-custom/AGENTS.md`;凭据接线见同文件):
186
-
187
- | 维度 | 声明范围 | 共享连接参数落点 |
188
- |---|---|---|
189
- | 指定服务 | `services.<slot>` 单槽 | 槽/实例级 `config` |
190
- | 指定模块 | 模块 `declare.owns` 全部服务槽(snapshot 除外) | `modules[<install id>].config` |
191
- | 应用 | 已装业务模块 owns 并集(空装配不适用) | root `config` |
192
-
193
- 3. **实施 adapter**:按 `packages/provider-custom/AGENTS.md` 实施(注册键 implementation
194
- 段 = `'inline'`)。
195
- 4. **验收**:`pnpm typecheck && pnpm build` 通过 + `npx --yes @tbox.cn/app-cli module
196
- doctor`;平台重启后该服务的调用不再报 `PROVIDER_NOT_IMPLEMENTED`(resolveService
197
- 惰性——调用时观测;doctor 对通配槽凭据不设防,运行时判据为最终裁判)。
93
+ 自定义 API = 服务的真实后端由你自己对接。收到「为某服务/模块/应用接入自定义 API」
94
+ (或「对接我的 API」「先要接口清单」等同义说法)请求时:**完整流程、任务路由与接入
95
+ 材料清单规范见应用根 `INTEGRATION.md`——先读它再动手**。本节不再展开(指引真源 =
96
+ INTEGRATION.md,勿在本节扩展)。
198
97
 
199
98
  ## 删除模块
200
99
 
@@ -247,3 +146,9 @@ pnpm install
247
146
  - `scripts/` 下所有文件保持可执行位(git 100755;CLI create 后 chmod 兜底)。
248
147
  - 装配文件不得裸 import(全部 import 行在锚区内);模块包不得 import SDK/契约内部路径(仅公开入口 `@tbox.cn/app-sdk{/server,/client,/platform}` 与 `@tbox.cn/app-contracts`)。
249
148
  - 构建序列单源 = 根 `build` / `build:client` script;`scripts/build.sh` 只管环境 + install + 委托(平台调用)。
149
+
150
+ ## 代码注释纪律
151
+
152
+ 修改本应用任何代码时,导出面与装配文件的注释保持**自包含短文档**(用途 + 关键约束 +
153
+ 消费视角);不引用仓库内部路径与决策编号——它们对沙箱外的读者无意义。指引类内容
154
+ 不写进注释:集成指引见 `INTEGRATION.md`(真源),本文件为发现入口。
package/ENV.md CHANGED
@@ -61,6 +61,7 @@ dev/src 与 prod/dist bundle 形态恒等):
61
61
  槽 `instances` 键缺席 = 通配激活)。模板不内置——`tbox-app module add` 装入 local 供给
62
62
  (provider-mock / provider-mocktest——local 供给双包同语义)时由 CLI mock 绑定生成器自动派生零拓扑形态(root.provider + 全 local 槽
63
63
  空对象);真厂商绑定经 `tbox-app provider use/bind` 或 `--config-dir` 真实素材注入。
64
+ 自定义 API 接入操作指引(任务路由/材料清单/落声明/adapter 实施)见应用根 `INTEGRATION.md`。
64
65
  - `config/integrations.json` 顶层 `modules` 节:模块资源绑定(键 = 模块 install id,如
65
66
  `module-customer-service`;`resources.<resourceId> = { type: 'knowledge', datasetId | ref, topK?, scoreThreshold? }`)。
66
67
  经 SDK `createModuleResourceResolver`(zod discriminatedUnion + 无内联密钥断言)→ `app-config` 服务
package/INTEGRATION.md ADDED
@@ -0,0 +1,91 @@
1
+ # INTEGRATION —— 自定义服务集成指引(真源)
2
+
3
+ 本文件是应用「自定义服务集成」指引的唯一真源;发现入口 = 根 `AGENTS.md`
4
+ 「自定义服务集成(provider-custom)」节(该节为指针,勿在其下扩展内容)。
5
+
6
+ **自定义 API** = 服务的真实后端由你自己对接:声明住在 `config/integrations.json`,adapter
7
+ 代码住在 `packages/provider-custom/`。服务后端三选一:Mock(演示数据,装 provider-mock
8
+ 即用)/ 自定义 API(你自己的后端接口——本文件流程)/ 服务商集成(官方 provider 包,
9
+ `module add` + `provider bind`)。
10
+
11
+ ## 任务路由
12
+
13
+ | 你的任务 | 按此读取 |
14
+ |---|---|
15
+ | 为一个服务接入 | `packages/contracts-mall/src/services/<域>.ts`(Port 定义)+ `packages/provider-custom/INTEGRATION.md` |
16
+ | 为某模块全部服务接入 | `packages/<module>/INTEGRATION.md` + `packages/<module>/tbox.module.json` + 该域 Port 文件 + `packages/provider-custom/INTEGRATION.md` |
17
+ | 应用全部服务接入 | `tbox-app module list` 后逐模块按上行 |
18
+ | 实施与排障 | `packages/provider-custom/INTEGRATION.md`(声明/骨架/注册/凭据/完成判据全链) |
19
+
20
+ ## 四步流程
21
+
22
+ 收到「为某服务/模块/应用接入自定义 API」(或「对接我的 API」「先要接口清单」等同义
23
+ 说法)的请求时按四步走:
24
+
25
+ 1. **说明并产出接入材料清单**(规范见下节)。目标不在已装模块服务槽词汇内 → 说明未装
26
+ 该模块,引导 `module add` 或 `new module`,不进入后续步骤。用户已给出的信息不重复问。
27
+ 未实施前调用报 `PROVIDER_NOT_IMPLEMENTED` 属预期中间态。
28
+ 2. **落声明**:目标槽已有内联声明则跳过;否则直接编辑 `config/integrations.json`
29
+ (CLI provider 命令仅支持字符串厂商)按「声明落点」表写入。
30
+ 3. **实施 adapter**:按 `packages/provider-custom/INTEGRATION.md` 实施。
31
+ 4. **验收**:`pnpm typecheck && pnpm build` 通过 + `npx --yes @tbox.cn/app-cli module
32
+ doctor`;平台重启后该服务的调用不再报 `PROVIDER_NOT_IMPLEMENTED`(resolveService
33
+ 惰性——调用时观测;doctor 对通配槽凭据不设防,运行时判据为最终裁判)。
34
+
35
+ ### 第 1 步:接入材料清单规范
36
+
37
+ 清单回答**「你的后端需要提供什么」**——从用户需要准备的材料出发;不解释槽/Port/registry/
38
+ 级联等平台内部机制(用户追问除外)。
39
+
40
+ **信息源(按序读,勿凭空编造)**:
41
+
42
+ - 槽位清单与必选性 → `packages/<module>/tbox.module.json`(`declare.consumes` 消费需求、
43
+ `declare.owns` 服务归属);
44
+ - 接口签名细节 → 消费模块 `src/server/ports.ts` 或 `packages/contracts-mall/src/services/<域>.ts`
45
+ (每个 Port 方法 = 后端需提供的一个接口);
46
+ - 该模块接入语义(顺序/依赖/可选降级)→ `packages/<module>/INTEGRATION.md`。
47
+
48
+ **清单交付项**(每服务一份,模块/应用维度 = 逐服务罗列):
49
+
50
+ - 服务槽:展示名 + 一句业务说明;
51
+ - 每个接口(Port 方法):接口语义(查询什么/写入什么);入参中来自平台的定位键
52
+ (如 userId / plateNo——平台传入,你的后端按它定位用户/车辆);返回**必选**字段与
53
+ **可选**字段;可选方法(`?` 结尾)缺席时的产品降级行为;
54
+ - 连接材料:API 地址(baseUrl)、认证方式(静态请求头 → `static-headers-v1`;Bearer/
55
+ 自定义签名 → 自定义认证策略)、其他可选连接参数(超时等);
56
+ - 依赖与顺序:接入该服务前需要先接入的其他服务/模块;`*.snapshot` 聚合槽由底层服务
57
+ 派生——落声明时跳过;
58
+ - 材料收集后仍缺的信息(baseUrl / 认证 / 密钥放置方式)明确列出请用户补充。
59
+
60
+ **纯询问即停**:用户仅询问「需要提供哪些接口/材料」(未给连接信息)→ 产出清单即停,
61
+ 等用户补充材料后再落声明与实施。密钥等敏感值不写进 prompt/代码/明文——经平台凭据
62
+ (`credentialRef`)配置,见 `packages/provider-custom/INTEGRATION.md`「认证与凭据」。
63
+
64
+ **中文名称寻址**:用户用中文展示名指代(如「会员积分」模块)→ 经 `packages/*/tbox.module.json`
65
+ 的 `name`/`id` 或 `tbox-app module list` 解析到模块;解析歧义时向用户确认。
66
+
67
+ ## 声明落点
68
+
69
+ | 维度 | 声明范围 | 共享连接参数落点 |
70
+ |---|---|---|
71
+ | 指定服务 | `services.<slot>` 单槽 | 槽/实例级 `config` |
72
+ | 指定模块 | 模块 `declare.owns` 全部服务槽(snapshot 除外) | `modules[<install id>].config` |
73
+ | 应用 | 已装业务模块 owns 并集(空装配不适用) | root `config` |
74
+
75
+ 关键形态约束:
76
+
77
+ - **内联 provider 声明(对象形态)恒槽级合法**——`modules[].provider` 与 root
78
+ `provider` 只接受字符串厂商名(zod 直接拒,fail-visible)。模块/应用维度 = 逐槽落
79
+ 对象声明,共享的是 `config` 层。
80
+ - `implementation` 写 `<provider名>@1` 字面量(槽级兄弟键,不在 provider 对象内)。
81
+ - 完整字段语义(各层级联、instances 激活等)单源 = `@tbox.cn/app-contracts` 的
82
+ integrations-config(zod 校验,与运行时同一解析面);可复制片段见
83
+ `packages/provider-custom/INTEGRATION.md`「内联声明 JSON 片段」。
84
+ - **provider 名三处一致**(声明/注册/凭据)规则与失败信号见
85
+ `packages/provider-custom/INTEGRATION.md`「provider 名三处一致」。
86
+
87
+ ## 验收
88
+
89
+ - `pnpm typecheck && pnpm build` 通过 + `npx --yes @tbox.cn/app-cli module doctor`;
90
+ - 平台重启后该服务的调用不再报 `PROVIDER_NOT_IMPLEMENTED`(resolveService 惰性——
91
+ 调用时观测;doctor 对通配槽凭据不设防,运行时判据为最终裁判)。
@@ -71,6 +71,6 @@ business/
71
71
 
72
72
  ## 对话智能体应用
73
73
 
74
- 保留平台对话能力时继续使用 `AgentChatApp`。缺省无 landing 注入:空态首屏 = 平台对话,服务端欢迎卡经 `engine.emitCard` 旁路呈现(012 出卡协议);mall 形态(`--profile mall`)下首屏由 home 槽供给(`MallHome`,来源 = `modules/module-mall-core`)。生成欢迎卡的智能体可直接由服务端出卡,无需改 `App.tsx`。
74
+ 保留平台对话能力时继续使用 `AgentChatApp`。缺省无 landing 注入:空态首屏 = 平台对话,服务端欢迎卡经 `engine.emitCard` 旁路呈现(012 出卡协议);mall 形态(`--profile mall`)下首屏由 home 槽供给(`MallHome`,来源 = `mall-core 模块`)。生成欢迎卡的智能体可直接由服务端出卡,无需改 `App.tsx`。
75
75
 
76
76
  修改对话组件、卡片或服务端工具时再读取对应目录的 `AGENTS.md`。不要修改通用首页入口来写死具体行业内容。
@@ -4,7 +4,7 @@
4
4
  * 卡片注册发生在各模块 clientModule.register(ctx) 内(模块内自注册闭环),
5
5
  * 本文件仅消费组装端上下文;CardType 由 apps/client/src/modules.ts 从装配数组自动推导。
6
6
  *
7
- * W3-2(薄装配):三通道全经 ctx 读取——
7
+ * 薄装配:三通道全经 ctx 读取——
8
8
  * - CHAT_REGISTRY = 原始注册 + 覆盖通道(聊天视图;覆盖优先);
9
9
  * - CARD_REGISTRY = 原始注册(RawCardRenderer 详情弹层消费);
10
10
  * - INLINE_CARD_FILTER = 内联流过滤复合(ChatPage filterInlineCards 注入值);
@@ -31,7 +31,7 @@ export const CHAT_REGISTRY: Record<string, CardComponent> = {
31
31
  export const INLINE_CARD_FILTER = (cards: readonly TboxCardPayload[]): TboxCardPayload[] =>
32
32
  ctx.cards.applyInlineFilters(cards);
33
33
 
34
- /** 客户端槽注册表(home 槽由模块 register 注册——W3-2 收口完成) */
34
+ /** 客户端槽注册表(home 槽由模块 register 注册—— 收口完成) */
35
35
  export const CLIENT_SLOTS = ctx.slots;
36
36
 
37
37
  export type { CardType } from '../modules';
@@ -12,8 +12,8 @@ import type { ClientContext, InferModuleCards } from '@tbox.cn/app-agent-sdk-cli
12
12
  // @tbox:imports-end
13
13
 
14
14
  // @tbox:register-begin
15
- // W4 单一模板统一化:缺省出厂 = 空装配(chat 流;home 槽缺席 → chat 形态派生)——
16
- // mall-core(home 槽/覆盖卡/内联过滤)经 profiles/mall 加装(W5 接线)。
15
+ // 单一模板统一化:缺省出厂 = 空装配(chat 流;home 槽缺席 → chat 形态派生)——
16
+ // mall-core(home 槽/覆盖卡/内联过滤)经 profiles/mall 加装(接线)。
17
17
  // 形态约定:数组恒多行(register 锚区行式插入依赖换行结构;单行 [] 会让 add 只插 import 不插注册行)
18
18
  const modules = [
19
19
  ] as const;
@@ -1,5 +1,5 @@
1
1
  /**
2
- * 首页(薄页,单一模板统一化 W2-5/W3-2):kit ChatPage 单点装配——零域 import。
2
+ * 首页(薄页,单一模板统一化/):kit ChatPage 单点装配——零域 import。
3
3
  *
4
4
  * - store = 应用薄壳 store(会话泳道 deps 注入 SDK 默认实现);
5
5
  * - cards/rawCards = 覆盖通道组装 / 原始形态(registry.ts 经 ctx 读取);
@@ -4,7 +4,7 @@
4
4
  * 环境值(VITE_API_URL / VITE_AUTH_PROVIDER)由 main.tsx 经 configureRuntime / 选项注入(H1)。
5
5
  */
6
6
  import { createAuthClient, createPlatformApi } from '@tbox.cn/app-agent-sdk-client';
7
- // 读源归位 TIER1(W1-①):mall-scope-url 契约助手(search-only 语义;壳 URL 改写层契约见包注释)
7
+ // 读源归位 TIER1():mall-scope-url 契约助手(search-only 语义;壳 URL 改写层契约见包注释)
8
8
  import { readMallIdFromUrl } from '@app/contracts-mall';
9
9
 
10
10
  /** VITE_AUTH_PROVIDER=external 时壳内换码登录转发外部(服务端需同步配置 AUTH_EXTERNAL_*) */
@@ -1,5 +1,5 @@
1
1
  /**
2
- * 对话状态(Zustand)薄壳(单一模板统一化 W2-5):
2
+ * 对话状态(Zustand)薄壳(单一模板统一化):
3
3
  * 会话泳道/历史分页/凭证升级调度全部下沉 SDK createCoreChatState——
4
4
  * 本壳只做域参数注入(HELLO context 采集)+ 排水订阅装配(应用侧一行)。
5
5
  */
@@ -33,7 +33,7 @@ export const useChatStore = create<CoreChatState>()((set, get) => ({
33
33
  ),
34
34
  }));
35
35
 
36
- // 011 L4:HELLO context 采集——mallId 经 URL query 采集(mall 部署;无 mallId 时不携带 context)
36
+ // HELLO context 采集——mallId 经 URL query 采集(mall 部署;无 mallId 时不携带 context)
37
37
  // 停车缴费按用户就近车场查(服务端 #ensureParkingId 用 lbs 反查 cityId→最近车场),
38
38
  // 故伴采集实时 lbs(best-effort:H5/无定位权限时静默丢弃,服务端自行降级 plaza)。
39
39
  // getter 同步签名,不能现 await getLocation() → 装配期先发起,缓存供 getter 同步读取。
@@ -60,5 +60,5 @@ configureHelloContext(() => {
60
60
 
61
61
  // 4002 scope 拒绝 / 4001 鉴权耗尽的终态提示与禁用由 SDK 统一出站(chat-store configureWsFatalCloseHandler)
62
62
 
63
- // 凭证升级排水(W2-2 SDK 装配位):生成中排队的升级在 isGenerating true→false 跃迁时执行
63
+ // 凭证升级排水(SDK 装配位):生成中排队的升级在 isGenerating true→false 跃迁时执行
64
64
  subscribeSessionUpgradeDrain(useChatStore);
@@ -6,7 +6,7 @@ import { clockTool } from './tools/clock.js';
6
6
  * apps 级工具统一注册面(010:双注册面同步):
7
7
  * start()(运行时)与 cli/collect-registry.ts(doctor/inspect 视图)两处同调本函数,
8
8
  * 未来新增 apps 级工具只改此处,避免两处注册面失同步(R 评审修正)。
9
- * W3-1:mall-info(含 preTool/缓存)迁 module-mall-core(模块注册面自持)。
9
+ * mall-info(含 preTool/缓存)迁 module-mall-core(模块注册面自持)。
10
10
  */
11
11
  export function registerAppTools(ctx: ServerContext): void {
12
12
  ctx.tools.register(translateTool);
@@ -52,12 +52,12 @@ import { registerAppTools } from './app-tools.js';
52
52
  import { APP_PRE_TOOLS } from './pre-tools.js';
53
53
  import { INTENT_ROUTES, createAppIntentDispatcher } from './intent-routes.js';
54
54
  import { loadIntegrations } from './config/integration.js';
55
- // W3-1/W4:mall 域语义(部署投影/scope 校验/默认值/instanceIdOf/mall-directory)归 module-mall-core,
55
+ ///mall 域语义(部署投影/scope 校验/默认值/instanceIdOf/mall-directory)归 module-mall-core,
56
56
  // 经 ctx.domainAssemblies 注册 + 运行期惰性查表——本文件按 TIER1 契约类型(MallScopeAssembly)
57
57
  // 泛型断言读取,零 mall-core 包 import(workspace-dag:应用消费模块经注册表 + 契约)
58
58
  import { SCOPE_ASSEMBLY_KIND } from '@tbox.cn/app-contracts';
59
59
  import type { MallScopeAssembly } from '@app/contracts-mall';
60
- // 011 S2/S3:mall 装配原语(条件装配——未配置部署文件时零引用)
60
+ ///mall 装配原语(条件装配——未配置部署文件时零引用)
61
61
  import {
62
62
  createScopeSessionRegistry,
63
63
  createActionGrantService,
@@ -92,9 +92,9 @@ const earlyToolExecution = resolveEarlyToolExecution(process.env.TBOX_EARLY_TOOL
92
92
 
93
93
  // 017:长期记忆(与 base 同源三件套:默认 inmemory;off 逃生舱;knowledge 需 KB_ID)。
94
94
  // mall 域措辞段仅装配态拼接(死能力零广告 L1;构造期常量 → 前缀缓存稳定)。
95
- // 记忆隔离:resolveScope 经域装配 buildScope 单点(mallId 命名空间;W3-1 查表)——
95
+ // 记忆隔离:resolveScope 经域装配 buildScope 单点(mallId 命名空间; 查表)——
96
96
  // 多 mall 单实例下互不可见;未装配控制面/无 mall 上下文 → 用户级全局记忆。
97
- // 017 M4:KB 校验三态(TBOX_MEMORY_KB_VALIDATE:1=异步降级不阻塞启动 / strict=同步 fail-fast /
97
+ // KB 校验三态(TBOX_MEMORY_KB_VALIDATE:1=异步降级不阻塞启动 / strict=同步 fail-fast /
98
98
  // 未设置不校验)——gated store 统一收口,装配面恒定(INV-D),降级只发生在调用执行时。
99
99
  const memoryBase = await resolveMemoryStoreGuarded({
100
100
  store: process.env.TBOX_MEMORY_STORE,
@@ -116,18 +116,18 @@ const memory = {
116
116
  const AGENT_PROMPT = loadAgentPromptConfig(CONFIG_DIR);
117
117
 
118
118
  // 平台能力装配(003/006 平台轴,已下沉 @tbox.cn/app-agent-sdk-server)
119
- // 011 L1 + F2/F3 + W3-1:装配序 integrations → authStrategies → auth → catalog → ctx——
119
+ // +/ + 装配序 integrations → authStrategies → auth → catalog → ctx——
120
120
  // v4:部署拓扑并入 integrations.json(单文件真源);域投影/校验(deployment 语义)迁
121
121
  // module-mall-core(ctx.domainAssemblies 惰性查表——auth 构造先于装配,动态判定经闭包后补)。
122
122
  // auth 提前构造(登录换码器由 provider 包 register 期经 ctx.authExchanges.register 自供给;
123
123
  // 注册表持引用惰性查找,register 晚于构造仍生效);
124
124
  // catalog 无条件装载(integrations 槽位解析唯一真源 = config/integrations.json)
125
- // 011 B2:可变认证策略注册表——模块 register 期注册(厂商签名策略),transportFactory 同引用
125
+ // 可变认证策略注册表——模块 register 期注册(厂商签名策略),transportFactory 同引用
126
126
  const authStrategies = createAuthStrategyRegistry();
127
127
  const integrationsConfig = loadIntegrations();
128
128
 
129
129
  /**
130
- * 域装配查表(W3-1):module-mall-core register 期注册;全部消费点运行期惰性读取
130
+ * 域装配查表:module-mall-core register 期注册;全部消费点运行期惰性读取
131
131
  * (auth/registry 构造早于 ctx 与 registerAll——查表时刻 ∈ listen 后请求/会话链路,装配必已就位)。
132
132
  * 无装配(无 integrations.json / 模块未装)→ undefined,各消费点按"无控制面"降级(语义对齐迁移前)。
133
133
  */
@@ -160,9 +160,9 @@ const providerCatalog = loadProviderCatalog(appRoot());
160
160
  // modules[owner] 级绑定/配置求值的显式注入参(缺注入 + 文件含 modules 绑定 → fail-visible)
161
161
  const ownershipMap = buildOwnershipMap(appRoot());
162
162
 
163
- // provider 拆包 F2/F3:integrations 槽位解析轴(config/integrations.json 存在即生效;
163
+ // provider 拆包/integrations 槽位解析轴(config/integrations.json 存在即生效;
164
164
  // 缺席 → undefined,模块槽解析与换码链 fail-fast 显性暴露——旧 ProviderRegistry 链已拆除)
165
- // instanceIdOf 注入 mall 语义(W3-1:沿域装配查表——mallId 派生归 module-mall-core)
165
+ // instanceIdOf 注入 mall 语义(沿域装配查表——mallId 派生归 module-mall-core)
166
166
  const integrations = integrationsConfig
167
167
  ? createIntegrationsRegistry({
168
168
  integrations: integrationsConfig.config,
@@ -181,7 +181,7 @@ const integrations = integrationsConfig
181
181
  production: isProduction,
182
182
  }),
183
183
  instanceIdOf: (scope) => mallAssembly()?.instanceIdOf(scope) ?? '',
184
- // F5 观测轴:provider factory 收到的 transport 统一包外部调用日志(→/← path durMs)
184
+ // 观测轴:provider factory 收到的 transport 统一包外部调用日志(→/← path durMs)
185
185
  logger: createLogger('provider'),
186
186
  })
187
187
  : undefined;
@@ -260,9 +260,9 @@ if (!isProduction) {
260
260
 
261
261
  // 自注册闭环:模块路由挂载到 /api/m/<moduleId>/(在 apiRouter 之前,避免被 /api 兜底 404 截获)
262
262
  // ctx 为模块级单例:registerAll 在 start() 内执行,ApiRouteRegistry 共享 root 保证延迟注册即时生效
263
- // 011 L1 + F2/F3:条件 mall 装配——integrations 槽位轴在上方装配段创建;
264
- // F2:authExchanges 同引用传递(provider 包 register 期自注册换码器)+ scopeDefaults 中立注入
265
- // W3-1:scopeDefaults 静态注入退役——域装配(含 defaultMallId)经 registry 读取视图供给
263
+ // + 条件 mall 装配——integrations 槽位轴在上方装配段创建;
264
+ // authExchanges 同引用传递(provider 包 register 期自注册换码器)+ scopeDefaults 中立注入
265
+ // scopeDefaults 静态注入退役——域装配(含 defaultMallId)经 registry 读取视图供给
266
266
  // (SDK ctx.scopeDefaults 惰性优先注册表 → provider getter 登录期求值)
267
267
  const ctx = createServerContext({
268
268
  authStrategies,
@@ -272,8 +272,8 @@ const ctx = createServerContext({
272
272
  });
273
273
 
274
274
  // real-env 统一配置链:app-config 服务(模块资源消费入口)——由 registerServerModules
275
- // 自动装配(W1-④:raw 派生 modules 资源节 + 源目录台账锚;无条件注册、与控制面正交,
276
- // 防无控制面启动静默丢失)。模板显式注册已拆(W3-1:装配默认兜底覆盖同语义)。
275
+ // 自动装配(-④:raw 派生 modules 资源节 + 源目录台账锚;无条件注册、与控制面正交,
276
+ // 防无控制面启动静默丢失)。模板显式注册已拆(装配默认兜底覆盖同语义)。
277
277
 
278
278
  // 全局 /api 鉴权(H2 挂载顺序契约):除 public(login/health)外一律要求 Bearer token;
279
279
  // optional 模式缺失 token → 匿名身份(写通道仍被 action gateway 拒绝)
@@ -282,8 +282,8 @@ app.use('/api', auth.middleware);
282
282
 
283
283
  app.use('/api/m', ctx.routes.mount());
284
284
 
285
- // 业务动作网关(004 D3/C2):POST /api/action — SDK 黑盒唯一写入口(幂等/防重放/签名槽位;
286
- // 006 D11:匿名写拒绝,不随 AUTH_MODE 变)
285
+ // 业务动作网关(/C2):POST /api/action — SDK 黑盒唯一写入口(幂等/防重放/签名槽位;
286
+ // 006 匿名写拒绝,不随 AUTH_MODE 变)
287
287
  app.use('/api/action', ctx.actions.middleware());
288
288
 
289
289
  // ===== GET /assets/deploy/:file — 部署态静态资产(.real-env/assets;厂商物料不进中立模板) =====
@@ -360,7 +360,7 @@ async function createEngine(
360
360
  },
361
361
  }
362
362
  : {}),
363
- // 011 B3:卡片动作 token 签发器(mall 装配时注入)
363
+ // 卡片动作 token 签发器(mall 装配时注入)
364
364
  cardActionAttacher: extra?.cardActionAttacher,
365
365
  // B21:意图路由接线(业务意图表 + handlerDispatch)
366
366
  intentRoutes: INTENT_ROUTES,
@@ -376,10 +376,10 @@ async function createEngine(
376
376
  const service = getConversationService();
377
377
  if (!service || !agentId) return undefined;
378
378
  const imageUrls = extractImageUrls(mediaItems, TBOX_FILE_URL_PREFIX);
379
- // P3 W1:卡片快照随消息持久化(MessageEmbedded,004 D1)。
380
- // 009 D10:skill 加载记录随消息持久化(inputs.skills,前端历史表达重建)。
379
+ // 卡片快照随消息持久化(MessageEmbedded)。
380
+ // 009 skill 加载记录随消息持久化(inputs.skills,前端历史表达重建)。
381
381
  // 010:前置工具记录随消息持久化(inputs.preTools,前端历史表达重建)。
382
- // inputs「非空才加」组装规则已下沉 SDK buildMessageInputs(010 S3)。
382
+ // inputs「非空才加」组装规则已下沉 SDK buildMessageInputs。
383
383
  // 若平台拒绝 inputs(V1 验证失败),此处切换为 extraParams 字符串或 FileCardPersistenceBackend 落盘。
384
384
  const inputs = buildMessageInputs({ cards, skills, preTools });
385
385
  return await service.saveMessage({
@@ -422,26 +422,26 @@ export function registerUpgradeDelegate(delegate: UpgradeDelegate): void {
422
422
  }
423
423
 
424
424
  export async function start() {
425
- // 注册业务模块(自注册闭环)——mall-directory 服务由 module-mall-core register 期注入(W3-1)
425
+ // 注册业务模块(自注册闭环)——mall-directory 服务由 module-mall-core register 期注入
426
426
  await registerAll(ctx);
427
427
 
428
- // 模板演示工具(apps 级工具,P3 建议迁入模块):不参与模块体系,经统一注册面注册
428
+ // 模板演示工具(apps 级工具, 建议迁入模块):不参与模块体系,经统一注册面注册
429
429
  // (010:start() 与 cli/collect-registry.ts 双处同调,防注册面失同步)
430
430
  registerAppTools(ctx);
431
431
 
432
- // W3-1 时序契约:域装配解析必须晚于 registerAll——module-mall-core 在 register 期经
433
- // ctx.domainAssemblies 注册装配;解析点置于 start() 头部会查空表(W4 引入回归:
432
+ // 时序契约:域装配解析必须晚于 registerAll——module-mall-core 在 register 期经
433
+ // ctx.domainAssemblies 注册装配;解析点置于 start() 头部会查空表(引入回归:
434
434
  // 默认商圈兜底/卡片动作授权/enhanceContext 全断——见 Agent Note 2026-09-17-mall-assembly-resolution-order)
435
435
  const assembly = mallAssembly();
436
436
 
437
- // 011 S6:mall 装配 + 生产环境缺动作授权密钥 → 启动期提示(≥32B TBOX_API_KEY 在场回退 apiKey 档;整链空装配期 fail-fast)
437
+ // mall 装配 + 生产环境缺动作授权密钥 → 启动期提示(≥32B TBOX_API_KEY 在场回退 apiKey 档;整链空装配期 fail-fast)
438
438
  if (assembly && isProduction && !process.env.ACTION_TOKEN_SECRET && !process.env.AUTH_TOKEN_SECRET) {
439
439
  actionLogger.warn('生产环境未配置 ACTION_TOKEN_SECRET/AUTH_TOKEN_SECRET——TBOX_API_KEY(≥32B) 缺席时装配将 fail-fast 拒绝启动;在场则回退 apiKey 档(平台运维可伪 action token)');
440
440
  }
441
441
 
442
- // 011 F2/E2:mall 装配(条件)——scope 会话 + 动作授权先行(engine attacher 依赖)
443
- // 014 T1:buildScope 回填 mallName(ChatHeader 品牌区服务端真源;三级回退内聚于域装配)
444
- // W3-1:域装配经查表(assembly 于上方 registerAll 后解析——解析点必须晚于模块注册)
442
+ ///E2:mall 装配(条件)——scope 会话 + 动作授权先行(engine attacher 依赖)
443
+ // buildScope 回填 mallName(ChatHeader 品牌区服务端真源;三级回退内聚于域装配)
444
+ // 域装配经查表(assembly 于上方 registerAll 后解析——解析点必须晚于模块注册)
445
445
  const scopeSessions: ReturnType<typeof createScopeSessionRegistry> | undefined = assembly
446
446
  ? createScopeSessionRegistry({
447
447
  extractScopeKey: (c) => assembly.extractScopeKey(c),
@@ -451,7 +451,7 @@ export async function start() {
451
451
  : undefined;
452
452
  const grants = scopeSessions ? createActionGrantService({ store: ctx.state }) : undefined;
453
453
 
454
- // 011 B3:卡片动作 token 签发(build → attach → send;sessionId 引擎登记、scope 经 sessions 查)
454
+ // 卡片动作 token 签发(build → attach → send;sessionId 引擎登记、scope 经 sessions 查)
455
455
  const cardActionAttacher = grants && scopeSessions
456
456
  ? async (
457
457
  payload: import('@tbox.cn/app-contracts').TboxCardPayload,
@@ -470,7 +470,7 @@ export async function start() {
470
470
  : undefined;
471
471
  const engine = await createEngine(cardActionAttacher ? { cardActionAttacher } : undefined);
472
472
 
473
- // 011 F2/E2:模块动作分发(依赖 scopeSessions/grants)
473
+ ///E2:模块动作分发(依赖 scopeSessions/grants)
474
474
  let moduleActions: ReturnType<typeof createModuleActionDispatcher> | undefined;
475
475
  if (assembly && scopeSessions && grants) {
476
476
  moduleActions = createModuleActionDispatcher({
@@ -479,7 +479,7 @@ export async function start() {
479
479
  state: ctx.state,
480
480
  actions: ctx.cardActions,
481
481
  cardRegistry: ctx.cards.getAll(),
482
- // 015 P3:effect 运行时纯投影(payment/authorization 回调补签在 dispatcher step7,
482
+ // effect 运行时纯投影(payment/authorization 回调补签在 dispatcher step7,
483
483
  // 客户端执行在 SDK host-effect-runner——模板零装配效果链)
484
484
  effects: createEffectRuntime(),
485
485
  extractScopeKey: (c) => assembly.extractScopeKey(c),
@@ -512,7 +512,7 @@ export async function start() {
512
512
  scopeSessions,
513
513
  ...(moduleActions ? { moduleActions } : {}),
514
514
  // 016:默认商圈兜底——无 URL 参数访问时服务端补 HELLO context(显式参数优先)
515
- // W3-1:defaultContext/enhanceContext 双钩内聚于域装配(mall-core;fail-soft 契约不变:
515
+ // defaultContext/enhanceContext 双钩内聚于域装配(mall-core;fail-soft 契约不变:
516
516
  // 增强是增益不是闸门——抛错/超时原 context 继续)
517
517
  ...(defaultContext ? { defaultContext } : {}),
518
518
  ...(assembly ? { enhanceContext: (c) => assembly.enhanceHelloContext(c) } : {}),
@@ -548,7 +548,7 @@ export async function start() {
548
548
  chatWss.emit('connection', ws, request);
549
549
  });
550
550
  } else if (pathname === '/ws/tts') {
551
- // 双层门 1(S5 修复,pre-101 鉴权):token 校验先行——TTS 代理原为全开放面。
551
+ // 双层门 1(修复,pre-101 鉴权):token 校验先行——TTS 代理原为全开放面。
552
552
  // 双形态载体(IP-2):Node 客户端 = Authorization Bearer;浏览器 WebSocket 无法
553
553
  // 自定义 header = ?token= query。无效/缺失 token 于 upgrade 前 destroy
554
554
  // (对齐 Terminal channel 先例)。
@@ -6,7 +6,7 @@
6
6
  * 旧 `config/deployments/development.json` 已退役,stale 防线在装载链 fail-fast
7
7
  * (mall 家族形态判定:含 malls 键;support 独立体系不受影响)。
8
8
  * - zod 单源 = SDK parseIntegrationsConfig(断言 → strict 校验;拼错键启动即报);
9
- * 控制平面投影归 module-mall-core(W3-1:消费 ctx.integrations.raw 自持计算)。
9
+ * 控制平面投影归 module-mall-core(消费 ctx.integrations.raw 自持计算)。
10
10
  * - 本壳只保留 I/O:占位展开(real-env 统一配置链——缺变量 fail-fast,错误含文件与
11
11
  * 缺失清单)+ DEFAULT_PATH 双态锚点探测(打包形态私有知识,不入 SDK)。
12
12
  * - 与 base 模板同构(双生无同步机制——公共能力先行落位,漂移由生成应用 verify 守护)。
@@ -5,8 +5,8 @@ import type { IntentRoute, HandlerResult, ServerContext } from '@tbox.cn/app-age
5
5
  * chat() 先 matchIntent(统一检索层 BM25 竞争:长词 OR ≥2 token 规则,score 降序 + id 字典序);
6
6
  * handler 缺省直接出卡/文字,也可用 continueWith 续接完整 Agent。
7
7
  *
8
- * W3-3(单一模板统一化):停车缴费硬路由迁 module-parking handler `intents` 声明
9
- * (意图与处理器同处定义,011 D7;collectIntentRoutes 装配端自动汇集)——
8
+ * 单一模板统一化:停车缴费硬路由迁 module-parking handler `intents` 声明
9
+ * (意图与处理器同处定义,;collectIntentRoutes 装配端自动汇集)——
10
10
  * 本表归零,业务方在此声明应用级意图路由(handlerId 对应已装模块的 handler id)。
11
11
  */
12
12
  export const INTENT_ROUTES: IntentRoute[] = [];
@@ -15,7 +15,7 @@ export const INTENT_ROUTES: IntentRoute[] = [];
15
15
  * 意图命中后的业务分发:经 ServerContext 的 HandlerRegistry.dispatch(组装端绑定 ctx)。
16
16
  * 命名 createAppIntentDispatcher(区别于 SDK 导出的 createIntentDispatcher:后者先 matchIntent
17
17
  * 再分发,本函数由 chat-engine 命中后直接分发)。
18
- * P2-3:用户原始输入以 payload.content 传入,handler 侧可经 payload.content 取用。
18
+ * 用户原始输入以 payload.content 传入,handler 侧可经 payload.content 取用。
19
19
  */
20
20
  export function createAppIntentDispatcher(ctx: ServerContext) {
21
21
  // 上下文统一化:第三参 reqCtx(引擎意图分发注入的运行上下文)透传 handlers.dispatch
@@ -14,8 +14,8 @@ import { serverModule as providerCustom } from '@app/provider-custom/server';
14
14
  // @tbox:imports-end
15
15
 
16
16
  // @tbox:register-begin
17
- // W4 单一模板统一化:缺省出厂 = 空装配(仅 provider-custom 自定义 API 落点 + contracts-mall shim)——
18
- // mall 能力(mall-core + 业务模块)经 profiles/mall 加装(tbox-app create --profile mall,W5 接线)
17
+ // 单一模板统一化:缺省出厂 = 空装配(仅 provider-custom 自定义 API 落点 + contracts-mall shim)——
18
+ // mall 能力(mall-core + 业务模块)经 profiles/mall 加装(tbox-app create --profile mall, 接线)
19
19
  // footer `] as const` 为空数组类型锚(CLI 增删模块时保留变体)
20
20
  const modules = [
21
21
  providerCustom,
@@ -13,7 +13,7 @@ import { clockTool } from './tools/clock.js';
13
13
  *
14
14
  * getCurrentTime —— 零参工程化演示(keywords 词表命中即执行,decide 恒 run 空参)。
15
15
  * 词表刻意排除「今天/时间」等泛词,防止与业务模块 preTool(如 member 的 always 预执行)语义叠加误触发。
16
- * W3-1:mall-info preTool 迁 module-mall-core(模块声明式 preTools 通道)。
16
+ * mall-info preTool 迁 module-mall-core(模块声明式 preTools 通道)。
17
17
  */
18
18
  export const APP_PRE_TOOLS = [
19
19
  definePreTool(clockTool, {
@@ -12,7 +12,7 @@ export const translateTool = createTool({
12
12
  '中英文互译工具。当用户需要翻译文本时调用此工具。自动检测源语言并翻译为目标语言:中文→英文,英文→中文。',
13
13
  inputSchema: z.object({
14
14
  text: z.string().describe('要翻译的文本'),
15
- // D11 参数规范:仅 string 形态(LLM 生成字符串最可靠);非法值工具内回落自动检测
15
+ // 参数规范:仅 string 形态(LLM 生成字符串最可靠);非法值工具内回落自动检测
16
16
  targetLang: z
17
17
  .string()
18
18
  .optional()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tbox.cn/app-template-agent",
3
- "version": "0.10.13",
3
+ "version": "0.10.14",
4
4
  "description": "tbox AI Agent 全栈模板(多包 pnpm workspace):apps/client + apps/server。唯一模板(W4 单一模板统一化:缺省空装配 chat 形态;mall 能力经 profiles/mall 加装),能力经 tbox-app module add 模块扩展(shopping-guide/member 等)。",
5
5
  "engines": {
6
6
  "node": ">=24.0.0 <25.0.0"
@@ -22,6 +22,7 @@
22
22
  ".gitignore",
23
23
  ".nvmrc",
24
24
  "AGENTS.md",
25
+ "INTEGRATION.md",
25
26
  "ENV.md",
26
27
  "LEGAL.md",
27
28
  "README.md",
@@ -36,7 +37,7 @@
36
37
  "typescript-eslint": "8.67.0",
37
38
  "eslint-plugin-react-hooks": "5.2.0",
38
39
  "vite": "6.4.3",
39
- "@tbox.cn/app-sdk-server": "0.24.0"
40
+ "@tbox.cn/app-sdk-server": "0.24.1"
40
41
  },
41
42
  "license": "MIT",
42
43
  "publishConfig": {