@tbox.cn/app-template-agent 0.7.5 → 0.9.0

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.
Files changed (152) hide show
  1. package/.gitignore +5 -0
  2. package/.tbox/app.json +9 -1
  3. package/AGENTS.md +12 -4
  4. package/ENV.md +105 -21
  5. package/README.md +40 -38
  6. package/apps/client/VISUAL_RESTORE.md +11 -11
  7. package/apps/client/index.html +3 -1
  8. package/apps/client/package.json +9 -8
  9. package/apps/client/src/business/App.tsx +4 -4
  10. package/apps/client/src/business/README.md +5 -11
  11. package/apps/client/src/cards/registry.ts +23 -8
  12. package/apps/client/src/main.tsx +36 -2
  13. package/apps/client/src/modules.ts +7 -4
  14. package/apps/client/src/pages/index/index.tsx +18 -162
  15. package/apps/client/src/platform/AgentChatApp.tsx +7 -6
  16. package/apps/client/src/platform/agent-runtime.ts +5 -0
  17. package/apps/client/src/store/chat.ts +47 -185
  18. package/apps/client/src/test/setup.ts +7 -0
  19. package/apps/client/vite.config.ts +16 -1
  20. package/apps/server/package.json +0 -3
  21. package/apps/server/src/app-tools.ts +2 -1
  22. package/apps/server/src/app.ts +248 -119
  23. package/apps/server/src/config/integration.ts +2 -6
  24. package/apps/server/src/dev.ts +0 -1
  25. package/apps/server/src/intent-routes.ts +3 -3
  26. package/apps/server/src/modules.ts +4 -4
  27. package/apps/server/src/pre-tools.ts +4 -3
  28. package/apps/server/tests/agent-prompt.test.ts +81 -0
  29. package/apps/server/tests/cards-registry.test.ts +1 -3
  30. package/apps/server/tests/deployment-loader.test.ts +35 -56
  31. package/apps/server/tests/tool-runtime.test.ts +25 -61
  32. package/package.json +5 -4
  33. package/packages/agent-ui-kit/LICENSE +21 -0
  34. package/packages/agent-ui-kit/README.md +17 -0
  35. package/packages/agent-ui-kit/package.json +58 -0
  36. package/packages/agent-ui-kit/src/ChatPage.less +62 -0
  37. package/packages/agent-ui-kit/src/ChatPage.tsx +305 -0
  38. package/packages/agent-ui-kit/src/chat-config.test.ts +82 -0
  39. package/packages/agent-ui-kit/src/chat-config.ts +62 -0
  40. package/{apps/client → packages/agent-ui-kit}/src/components/ActionBar/DebugButton.tsx +2 -2
  41. package/{apps/client → packages/agent-ui-kit}/src/components/ActionBar/index.less +19 -16
  42. package/{apps/client → packages/agent-ui-kit}/src/components/ActionBar/index.tsx +10 -15
  43. package/packages/agent-ui-kit/src/components/CardRenderer.tsx +36 -0
  44. package/packages/agent-ui-kit/src/components/ChatHeader/index.less +148 -0
  45. package/packages/agent-ui-kit/src/components/ChatHeader/index.test.tsx +74 -0
  46. package/{apps/client → packages/agent-ui-kit}/src/components/ChatHeader/index.tsx +27 -15
  47. package/{apps/client → packages/agent-ui-kit}/src/components/ChatInput/index.less +47 -39
  48. package/packages/agent-ui-kit/src/components/ChatInput/index.test.tsx +156 -0
  49. package/{apps/client → packages/agent-ui-kit}/src/components/ChatInput/index.tsx +13 -4
  50. package/{apps/client → packages/agent-ui-kit}/src/components/ChatInput/voice/useVoicePress.ts +2 -2
  51. package/packages/agent-ui-kit/src/components/HistoryEntry/index.less +49 -0
  52. package/packages/agent-ui-kit/src/components/HistoryEntry/index.tsx +42 -0
  53. package/{apps/client → packages/agent-ui-kit}/src/components/MediaList/index.less +3 -3
  54. package/{apps/client → packages/agent-ui-kit}/src/components/MediaList/index.tsx +6 -6
  55. package/{apps/client → packages/agent-ui-kit}/src/components/MessageBubble/index.less +25 -20
  56. package/packages/agent-ui-kit/src/components/MessageBubble/index.test.tsx +112 -0
  57. package/{apps/client → packages/agent-ui-kit}/src/components/MessageBubble/index.tsx +22 -17
  58. package/{apps/client → packages/agent-ui-kit}/src/components/PullDownIndicator/index.less +2 -2
  59. package/{apps/client → packages/agent-ui-kit}/src/components/PullDownIndicator/index.tsx +2 -2
  60. package/packages/agent-ui-kit/src/components/QuickCommands/index.less +63 -0
  61. package/packages/agent-ui-kit/src/components/QuickCommands/index.test.tsx +99 -0
  62. package/packages/agent-ui-kit/src/components/QuickCommands/index.tsx +52 -0
  63. package/{apps/client → packages/agent-ui-kit}/src/components/ScrollToBottomButton/index.less +1 -1
  64. package/packages/agent-ui-kit/src/components/ToolCallBlock/detail.test.ts +346 -0
  65. package/packages/agent-ui-kit/src/components/ToolCallBlock/detail.ts +204 -0
  66. package/packages/agent-ui-kit/src/components/ToolCallBlock/index.less +312 -0
  67. package/packages/agent-ui-kit/src/components/ToolCallBlock/index.test.tsx +261 -0
  68. package/packages/agent-ui-kit/src/components/ToolCallBlock/index.tsx +212 -0
  69. package/packages/agent-ui-kit/src/components/ToolCallBlock/titles.ts +102 -0
  70. package/packages/agent-ui-kit/src/hooks/use-drag-gesture.test.ts +66 -0
  71. package/packages/agent-ui-kit/src/hooks/use-drag-gesture.ts +129 -0
  72. package/packages/agent-ui-kit/src/hooks/use-pull-down-history.ts +241 -0
  73. package/packages/agent-ui-kit/src/hooks/use-pull-down-wheel-native.test.ts +64 -0
  74. package/{apps/client → packages/agent-ui-kit}/src/hooks/useMediaUpload.ts +3 -3
  75. package/{apps/client → packages/agent-ui-kit}/src/hooks/useTTSAutoPlay.ts +7 -5
  76. package/packages/agent-ui-kit/src/index.ts +69 -0
  77. package/packages/agent-ui-kit/src/store-context.tsx +92 -0
  78. package/packages/agent-ui-kit/src/test/setup.ts +7 -0
  79. package/packages/agent-ui-kit/src/theme/contract.json +72 -0
  80. package/packages/agent-ui-kit/src/theme/global.less +99 -0
  81. package/packages/agent-ui-kit/src/theme/motion.less +19 -0
  82. package/packages/agent-ui-kit/src/theme/theme-contract.test.ts +69 -0
  83. package/packages/agent-ui-kit/src/theme/theme.ts +17 -0
  84. package/packages/agent-ui-kit/src/theme/tokens.less +79 -0
  85. package/packages/agent-ui-kit/src/utils/haptics.test.ts +51 -0
  86. package/packages/agent-ui-kit/src/utils/haptics.ts +44 -0
  87. package/packages/agent-ui-kit/src/utils/pull-down-machine.test.ts +188 -0
  88. package/packages/agent-ui-kit/src/utils/pull-down-machine.ts +157 -0
  89. package/packages/agent-ui-kit/src/utils/tool-call-display.test.ts +240 -0
  90. package/packages/agent-ui-kit/src/utils/tool-call-display.ts +146 -0
  91. package/packages/agent-ui-kit/src/vite-env.d.ts +1 -0
  92. package/packages/agent-ui-kit/tsconfig.json +8 -0
  93. package/packages/agent-ui-kit/vitest.config.ts +7 -0
  94. package/pnpm-lock.template.yaml +177 -111
  95. package/pnpm-workspace.template.yaml +12 -4
  96. package/profiles/mall/config/agent.jsonc +33 -0
  97. package/profiles/mall/config/chat.json +21 -0
  98. package/profiles/mall/config/knowledge.json +5 -0
  99. package/profiles/mall/config/llm_provider.json +5 -0
  100. package/profiles/mall/config/plugins.json +3 -0
  101. package/profiles/mall.json +16 -0
  102. package/scripts/check-workspace.mjs +3 -2
  103. package/apps/client/assets/copy@2x.png +0 -0
  104. package/apps/client/assets/debug.png +0 -0
  105. package/apps/client/assets/dislike@2x.png +0 -0
  106. package/apps/client/assets/like@2x.png +0 -0
  107. package/apps/client/assets/speaker@2x.png +0 -0
  108. package/apps/client/src/cards/CardRenderer.tsx +0 -20
  109. package/apps/client/src/components/ChatHeader/index.less +0 -104
  110. package/apps/client/src/components/ErrorBoundary.tsx +0 -2
  111. package/apps/client/src/components/QuickCommands/index.less +0 -48
  112. package/apps/client/src/components/QuickCommands/index.tsx +0 -29
  113. package/apps/client/src/components/ToolCallBlock/index.less +0 -131
  114. package/apps/client/src/components/ToolCallBlock/index.tsx +0 -125
  115. package/apps/client/src/examples/tourism/TourismLanding.tsx +0 -96
  116. package/apps/client/src/examples/tourism/index.less +0 -192
  117. package/apps/client/src/pages/index/index.less +0 -43
  118. package/apps/client/src/store/chat-config.ts +0 -40
  119. package/apps/client/src/styles/global.less +0 -60
  120. package/apps/client/src/styles/tokens.less +0 -60
  121. package/apps/server/src/config/deployment.ts +0 -47
  122. package/packages/module-weather/package.json +0 -36
  123. package/packages/module-weather/skills/weather-guide/SKILL.md +0 -22
  124. package/packages/module-weather/skills/weather-guide/references/dressing-tips.md +0 -5
  125. package/packages/module-weather/src/client/cards/weather/index.less +0 -22
  126. package/packages/module-weather/src/client/cards/weather/index.tsx +0 -14
  127. package/packages/module-weather/src/client/index.ts +0 -19
  128. package/packages/module-weather/src/index.ts +0 -2
  129. package/packages/module-weather/src/server/cards/weather/meta.ts +0 -27
  130. package/packages/module-weather/src/server/index.ts +0 -45
  131. package/packages/module-weather/src/server/pre-tools.ts +0 -20
  132. package/packages/module-weather/src/server/tool.ts +0 -29
  133. package/packages/module-weather/tbox.module.json +0 -27
  134. package/packages/module-weather/tsconfig.json +0 -14
  135. /package/{apps/client → packages/agent-ui-kit}/assets/keyboard-circle.svg +0 -0
  136. /package/{apps/client → packages/agent-ui-kit}/assets/more-circle.svg +0 -0
  137. /package/{apps/client → packages/agent-ui-kit}/assets/new-chat.svg +0 -0
  138. /package/{apps/client → packages/agent-ui-kit}/assets/quick-command-star.svg +0 -0
  139. /package/{apps/client → packages/agent-ui-kit}/assets/send-gradient.svg +0 -0
  140. /package/{apps/client → packages/agent-ui-kit}/assets/stop@2x.png +0 -0
  141. /package/{apps/client → packages/agent-ui-kit}/assets/voice-circle.svg +0 -0
  142. /package/{apps/client → packages/agent-ui-kit}/src/components/ChatInput/voice/VoicePressField.tsx +0 -0
  143. /package/{apps/client → packages/agent-ui-kit}/src/components/ChatInput/voice/VoiceRecordingOverlay.tsx +0 -0
  144. /package/{apps/client → packages/agent-ui-kit}/src/components/ChatInput/voice/machine.ts +0 -0
  145. /package/{apps/client → packages/agent-ui-kit}/src/components/ReasoningBlock/index.less +0 -0
  146. /package/{apps/client → packages/agent-ui-kit}/src/components/ReasoningBlock/index.tsx +0 -0
  147. /package/{apps/client → packages/agent-ui-kit}/src/components/ScrollToBottomButton/index.tsx +0 -0
  148. /package/{apps/client/src/types/chat.ts → packages/agent-ui-kit/src/types.ts} +0 -0
  149. /package/{apps/client → packages/agent-ui-kit}/src/utils/copyText.ts +0 -0
  150. /package/{apps/client → packages/agent-ui-kit}/src/utils/imagePreview.ts +0 -0
  151. /package/{apps/client → packages/agent-ui-kit}/src/utils/session-error.ts +0 -0
  152. /package/{apps/client → packages/agent-ui-kit}/src/utils/toast.ts +0 -0
package/.gitignore CHANGED
@@ -8,6 +8,11 @@ dist-ssr
8
8
  *.log
9
9
  .pnpm-store
10
10
 
11
+ # IDE
12
+ .idea
13
+ .vscode
14
+ *.iml
15
+
11
16
  # 环境变量(含密钥,勿提交;用 .env.example 提供模板)
12
17
  .env
13
18
  .env.*
package/.tbox/app.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "templateVersion": "7.1.0",
2
+ "templateVersion": "1.3.0",
3
3
  "npmModules": [
4
4
  {
5
5
  "id": "provider-custom",
@@ -7,6 +7,14 @@
7
7
  "version": "0.1.0",
8
8
  "mode": "codegen",
9
9
  "baseVersion": "0.1.0"
10
+ },
11
+ {
12
+ "id": "agent-ui-kit",
13
+ "package": "@tbox.cn/app-agent-ui-kit",
14
+ "version": "0.1.0",
15
+ "mode": "codegen",
16
+ "baseVersion": "0.1.0",
17
+ "kind": "ui-kit"
10
18
  }
11
19
  ],
12
20
  "miniappContainers": []
package/AGENTS.md CHANGED
@@ -2,6 +2,9 @@
2
2
 
3
3
  template-agent 是多包 pnpm workspace:`apps/` 薄组装端 + `packages/` 模块。客户端同时运行在浏览器和支付宝小程序 web-view 壳中。
4
4
 
5
+ > **唯一模板(W4 单一模板统一化)**:缺省出厂 = 空装配(chat 形态);商圈形态经 `profiles/mall.json` 画像加装
6
+ > (`tbox-app create --profile mall`:mall-core/mall-home + 六业务模块 + config 叠加)。历史 base/mall 双生约定退役。
7
+
5
8
  > **工作区上下文(发布态消费,005 v0.4.0)**:仓库内本目录是**根 workspace 成员子树**(无独立 `pnpm-workspace.yaml`),
6
9
  > 平台引用 `catalog:` + 根 `pnpm-workspace.yaml` `overrides: workspace:*` 回指根 `packages/` 真源;`pnpm` 命令在根上下文执行。
7
10
  > `tbox-app create` 从模板源(目录或 pack tgz)展开生成应用——**不拼接平台真源**:生成应用 `packages/` 仅业务/local 模块,
@@ -13,12 +16,15 @@ template-agent 是多包 pnpm workspace:`apps/` 薄组装端 + `packages/` 模
13
16
  | 包 | 职责 |
14
17
  |---|---|
15
18
  | `apps/server` | Express + WS 装配入口,HTTP 路由,TTS 代理;业务工具/卡片由模块自注册(自注册闭环) |
16
- | `apps/client` | React/Vite 装配入口,业务页面/组件/adapters/bridge |
17
- | `packages/module-weather` | 示例业务模块(双端单包,本目录内源码;根 workspace 内平台真源在根 `packages/`) |
19
+ | `apps/client` | React/Vite 装配入口,业务页面/组件/adapters/bridge(家页 MallHome 由 mall-home 模块经 home 槽供给) |
20
+ | `packages/` | 模块目录(空装配起点:`tbox-app new module <name>` 或 `module add` 生成 `@app/<id>` 成员;根 workspace 内平台真源在根 `packages/`) |
21
+
22
+ > **画像供能(017 家族)**:mall 形态 = profiles/mall.json 声明的模块序列(mall-core 域装配 + mall-home 家页 + 六业务模块)
23
+ > + profiles/mall/config 叠加;公共能力(协议/机制/配置链)沉淀 SDK/CLI——新增通用能力先落 SDK/kit 再被模板/模块消费。
18
24
 
19
25
  ## 模块开发(双端自注册闭环,逐行同构)
20
26
 
21
- `packages/module-*` 是双端单包,两端入口导出**模块描述对象**并自注册:
27
+ `packages/module-*`(经 `tbox-app module add` 生成)是双端单包,两端入口导出**模块描述对象**并自注册:
22
28
 
23
29
  - server 入口 `src/server/index.ts`:`export const serverModule = { cards, register(ctx) {...} } satisfies ServerModule`;
24
30
  `register` 内经 `ctx.tools/cards.registerMap/handlers/routes/services/bus` 自注册;只注册不解析(resolveService 仅 handle/事件回调内)。
@@ -53,6 +59,7 @@ apps/client/src/modules.ts # 客户端模块装配(与 serv
53
59
  apps/client/src/cards/registry.ts # 卡片注册表快照(CardType → CardComponent)
54
60
  apps/server/src/index.ts # 服务端入口(HTTP + WS + Vite middleware + createServerContext + createEngineFromContext)
55
61
  apps/server/src/modules.ts # 服务端模块装配(registerAll)
62
+ apps/server/src/module-ports.ts # 模块 ports 动态装配(LinkedPanel/bumpin 数据源;契约派生 + 漂移守卫)
56
63
  packages/app-sdk/src/server/chat-engine.ts # ChatEngine 工厂
57
64
  packages/app-sdk/src/server/context.ts # ServerContext(注册表聚合 + createServerContext)
58
65
  packages/app-sdk/src/server/build-engine.ts # createEngineFromContext / createSdkToolRuntime(出卡 capture 在 engine 构造期包装,见 tool-cards.ts)
@@ -75,7 +82,7 @@ pnpm plugin:doctor
75
82
  pnpm plugin:inspect <pluginId> <toolId>
76
83
  ```
77
84
 
78
- starter 文档:`tbox-app starter --type agent`;可用类型:`tbox-app starter --list`。在沙箱中使用 `tbox-app create . --name <app-name> --source @tbox.cn/app-template-agent` 原地初始化,应用模板的 `AGENTS.md` 会覆盖 starter seed。模块安装/装配由 `tbox-app` CLI(`@tbox.cn/app-cli`)管理:`module add --mode local|codegen|sdk --source <路径|tgz|registry包> / remove / list / sync / diff / doctor / update / publish`。add/remove/sync 后需 `pnpm install`。未安装 CLI 时:`pnpm add -g @tbox.cn/app-cli`(registry 安装)。
85
+ starter 文档:`tbox-app starter --type agent-mall`;可用类型:`tbox-app starter --list`。在沙箱中使用 `tbox-app create . --name <app-name> --source @tbox.cn/app-template-agent --profile mall` 原地初始化(缺省不带 --profile = 空装配 chat 形态),应用模板的 `AGENTS.md` 会覆盖 starter seed。模块安装/装配由 `tbox-app` CLI(`@tbox.cn/app-cli`)管理:`new <module|provider|theme> <name>`(应用内脚手架)/ `module add --mode local|codegen|sdk --source <路径|tgz|registry包> / remove / list / sync / diff / doctor / update / publish`。add/remove/sync 后需 `pnpm install`。未安装 CLI 时:`pnpm add -g @tbox.cn/app-cli`(registry 安装)。
79
86
 
80
87
  ## 平台基础设施
81
88
 
@@ -99,6 +106,7 @@ starter 文档:`tbox-app starter --type agent`;可用类型:`tbox-app star
99
106
 
100
107
  客户端同时跑浏览器与支付宝小程序 web-view 壳(组件挂载于 H5 视口,非小程序原生渲染),样式遵守:
101
108
 
109
+ 0. **视觉体系 = mall-vis 蓝系**(视觉真源:仓库 `docs/reference/templates.md`——换肤面四级级联/域色矩阵 member 金 · parking 藏蓝 · sg 蓝 · promotion 红/UI 模式);视觉值只住 kit tokens / 模块域变量块 / 素材变量消费三层(品牌视觉经主题包覆写——出厂接线 `@tbox.cn/app-theme-tbox` 三行,见 `apps/client/src/main.tsx`),平台 token 名字零增减。
102
110
  1. **长度单位 PX 大写**(如 `800PX`)——web-view 内联字体放大:小写 `px` 被浏览器 rem 缩放改写,大写跳过改写保持视觉尺寸。
103
111
  2. **flex 子项设 `flex-shrink: 0`**——壳内内容宽度不定,防元素被压缩变形。
104
112
  3. **滚动容器隐藏滚动条**(`::-webkit-scrollbar { display: none }`)——web-view 无原生滚动条,出现即破相。
package/ENV.md CHANGED
@@ -6,25 +6,85 @@
6
6
 
7
7
  - **本地开发**:shell export 注入(每次新终端需重新执行;见文末命令块)。生成应用请直接 shell export 或平台配置。
8
8
  - **生产**:建议在 tbox 平台页面上配置环境变量(平台托管 env,密钥不进代码仓库、不进 git)。
9
- 生产部署必须 `NODE_ENV=production`(dev-login 强制关闭 + JWT 密钥链 fail-fast 的依据)。
9
+ 生产部署必须 `NODE_ENV=production`(JWT 密钥链 fail-fast + real hardening 的依据)。
10
10
  入口分离后 dist 恒静态供给(vite dev 仅存在于源码 `src/dev.ts` 本地开发入口);`NODE_ENV` 不再决定
11
- 客户端供给形态——测试环境可用 `node dist/index.js`(不设 NODE_ENV)获得「静态产物 + dev-login」。
11
+ 客户端供给形态——测试环境可用 `node dist/index.js`(不设 NODE_ENV)获得「静态产物 + 开发档登录语义」。
12
12
  - 以下变量缺失时服务可启动,但对话/会话/上传链路会 503。
13
13
 
14
- ## 配置文件:config/chat.json(会话 UI 设置)
15
-
16
- 六字段(`quickCommands`/`enableImageUpload`/`enableVideoUpload`/`enableTTS`/`enableVoiceInput`/
17
- `defaultInputMode`)由 server 经 `loadChatConfig` 读取(zod fail-soft),WS HELLO chatConfig
18
- **服务端运行时下发单一真源**:`quickCommands` 映射 query→prompt,其余五键经 `settings` 下发 →
19
- client 水合覆盖构建期快照;`/ws/tts` 通道门同源(`enableTTS:false` 时 upgrade 硬拒)。
20
- dev 态 `TBOX_CONFIG_DIR` 可指档位目录替换默认 `config/`。**改 chat.json 需重启 server,新连接生效**
21
- (client 构建期静态 import 仅作 ack 未达/键缺席的回落快照)。
22
-
23
- ## 配置文件:config/agent.jsonc(agent 提示词)
24
-
25
- `instructions` 业务段行数组(首行身份句)+ `memoryInstructions` 可选(装配长期记忆时由 SDK 追加)。
26
- 未配置时 SDK 默认提示词兜底;解析失败 ERROR 日志 + 兜底。改文件需重启 server。(本模板出厂不携带
27
- 该文件——即 SDK 默认形态)
14
+ ## 默认商圈(integrations v4)
15
+
16
+ 无 URL 参数访问时服务端可自动补入默认商圈 HELLO context(免每次手拼 `?mallId=`):
17
+
18
+ - 唯一真源 = `config/integrations.json` 顶层 `"defaultInstanceId"`(旧
19
+ `config/deployments/development.json` 已退役——在场会启动 fail-fast 提示迁移),两种形态——
20
+ - 静态参考表:`"instances": [{"id": "mall-demo", "name": "...", "attributes": {"miniAppId": "..."}}]`
21
+ + `"defaultInstanceId": "mall-demo"`(单实例可免填——唯一解)。
22
+ - env 注入:`"defaultInstanceId": "${DEFAULT_MALL_ID}"`(loader expandEnvVars 先行展开),
23
+ 无 `instances` 键 = 无参考表(动态形态);env 未注入 → 占位 fail-fast 显性暴露。
24
+ - 注入形态:mallId-only(miniAppId 尽力回填——root config `miniAppId` 优先、参考表
25
+ attributes 兜底;双缺仍注入,不阻断默认商圈)。URL 显式参数 `?mallId=` 优先级更高。
26
+ - 本地 mock 链:`tbox-app module add` 装 provider-mock → 生成器派生零拓扑 integrations.json →
27
+ 裸跑免 mallId 全局会话或任意 `?mallId=` 均可演示。零拓扑形态下 provider-mock 于 register 期
28
+ 声明隐式默认单实例(mall-demo / 星河 Mock 小镇)——无 URL 参数访问时默认商圈回显照常生效
29
+ (显式 instances/defaultInstanceId 恒赢,声明仅兜底)。
30
+
31
+ ## URL 参数契约(mall 接入)
32
+
33
+ | 参数 | 语义 | 优先级 / 纪律 |
34
+ |---|---|---|
35
+ | `mallId` | 商场标识(契约键) | 优先;空串视为缺席 |
36
+ | `plazaId` | 商场别名(正式壳词汇兼容,非厂商特判) | `mallId` 缺席时兜底生效 |
37
+ | `miniAppId` | 承载小程序 appId | 可缺省——服务端按 root config `miniAppId` 回填(HELLO enhanceContext) |
38
+ | `query` | 深链首条消息(`?query=` 优先) | 读取即剥离(replaceState);trim 空值视为缺席 |
39
+ | `prompt` | 深链首条消息(`query` 缺席时兜底) | 同上;search-only,hash 内不读 |
40
+
41
+ - **search-only**:只读 `window.location.search`——hash 内参数不读(壳 URL 改写层移参进 hash 即失效)。
42
+ - 深链自动发送(query/prompt)由 SDK `consumeAutoSendQuery` 单点消费:读取即从 URL 剥离——刷新/分享
43
+ 不重发;socket 5s 未就绪静默放弃。
44
+ - 读源单一 helper:`apps/client/src/platform/mall-scope-url.ts`(`mallId ?? plazaId`)——
45
+ HELLO context 采集、scopeKey 会话守卫、member-gate 三处共用,禁止散落裸 `URLSearchParams`。
46
+ - 恒动态(v4):`mallId` 无需 ∈ instances 参考表(参考表纯元数据,永不充当闸门——
47
+ 任意 mallId 均可建会话;实例集限制由各 provider 槽激活形态在数据面表达);
48
+ 品牌区 mallName 由 mall.info 槽按 mallId 动态拉取(TTL 缓存,失败降级不阻断会话)。
49
+ 商场基本信息 agent tool(`mall-info`,silent preTool + 会话内 dedup)同经该槽(共用 resolveMallInfo 缓存)。
50
+
51
+ ## 应用配置(config/,非 env)
52
+
53
+ `config/` 为应用配置目录(真实值经 `tbox-app create --config-dir <目录>` 合并注入,生成应用自包含;
54
+ 模板内为 demo 占位形态)。配置目录由 server entry 锚定解析(`__dirname` 3 级上溯 = 应用根,
55
+ dev/src 与 prod/dist bundle 形态恒等):
56
+
57
+ - `config/integrations.json`:provider 绑定与部署拓扑唯一真源(integrations v4:绑定组
58
+ provider+implementation 从最特异层整组继承(instance > slot > domain > root),组内
59
+ implementation 缺席经 catalog 派生;部署拓扑 = 顶层 `instances` 注册表 + `defaultInstanceId`;
60
+ 槽 `instances` 键缺席 = 通配激活)。模板不内置——`tbox-app module add` 装入 local 供给
61
+ (provider-mock)时由 CLI mock 绑定生成器自动派生零拓扑形态(root.provider + 全 local 槽
62
+ 空对象);真厂商绑定经 `tbox-app provider use/bind` 或 `--config-dir` 真实素材注入。
63
+ - `config/integrations.json` 顶层 `modules` 节:模块资源绑定(键 = 模块 install id,如
64
+ `module-customer-service`;`resources.<resourceId> = { type: 'knowledge', datasetId | ref, topK?, scoreThreshold? }`)。
65
+ 经 SDK `createModuleResourceResolver`(zod discriminatedUnion + 无内联密钥断言)→ `app-config` 服务
66
+ (无条件注册)→ 模块按 install id 消费(缺服务/缺键回退占位等值);`ref` 经 integrations.json
67
+ 同目录 `knowledge.json` 台账展开(datasetId 直填免台账)。改配置需重启 server。
68
+ - `config/bumpin.json`:碰出惊喜配置面(`gateway`/`actSchemeId`/`linkedCardBackgroundUrl`?/
69
+ `credentialRef`?;fail-soft——缺文件该面静默关闭)。
70
+
71
+ - `config/chat.json`:会话 UI 设置六字段(`quickCommands`/`enableImageUpload`/`enableVideoUpload`/
72
+ `enableTTS`/`enableVoiceInput`/`defaultInputMode`)。server 经 `loadChatConfig` 读取(zod fail-soft),
73
+ WS HELLO chatConfig **服务端运行时下发单一真源**:`quickCommands` 映射 query→prompt(剥离扩展字段),
74
+ 其余五键经 `settings` 下发 → client 水合覆盖构建期快照;`/ws/tts` 通道门同源(`enableTTS:false` 时
75
+ upgrade 硬拒)。**改 chat.json 需重启 server,新连接生效**(client 构建期静态 import 仅作 ack 未达
76
+ /键缺席的回落快照,保留但不需为改配置重建 client)。
77
+ - `config/agent.jsonc`:agent 提示词(`instructions` 业务段行数组——首行身份句;`memoryInstructions`
78
+ 可选,装配长期记忆时由 SDK 追加)。未配置时 SDK 默认提示词兜底;解析失败 ERROR 日志 + 兜底。
79
+ 改文件需重启 server。
80
+ - `config/llm_provider.json`:模型名 + thinking 控制(`modelName` 优先于 `APP_AI_MODEL_NAME`;
81
+ `thinking`:`false`(缺省默认关闭)/`true`(开启)/`"auto"`(不注入,严格端点逃生舱)/object
82
+ 字面量合并进请求体顶层(可覆盖 `model`/`messages` 等键,慎用)——缺省即关闭为**代码级默认**,
83
+ 删除文件≠开启;每请求热读(改配置即生效,无需重启);env `APP_AI_THINKING` 优先级低于文件字段)。
84
+
85
+ **chat.json 通道分工**(已统一):六字段全部经 server WS HELLO chatConfig 运行时下发(`settings`
86
+ 五键 + `quickCommands`);client 构建期静态 import 仅为回落快照(ack 未达/键缺席/旧 server 场景)。
87
+ 对比 `llm_provider.json` 的**每请求热读**:chat.json 为**启动读一次**(进程内缓存,改文件需重启 server)。
28
88
 
29
89
  ## 必需
30
90
 
@@ -55,15 +115,14 @@ dev 态 `TBOX_CONFIG_DIR` 可指档位目录替换默认 `config/`。**改 chat.
55
115
  | `TBOX_LLM_CONN_BIND` | per-session 连接绑定旋钮(缺省 on;`=off` 关闭——LLM fetch 回退全局连接池。连接=网关缓存池路由单位:per-session 单连接(120s keep-alive)钉死集群分配,保活跨 run 提升前缀缓存命中;排障时可关) |
56
116
  | `TBOX_LLM_COOKIE_AFFINITY` | 网关 cookie 亲和旋钮(缺省 on;`=off` 关闭——不回传网关 set-cookie。回传激活 LB 粘性:连接重建后恢复原集群的通道;best-effort) |
57
117
 
58
- ## 统一鉴权(006)
118
+ ## 统一鉴权
59
119
 
60
120
  | 变量 | 说明 |
61
121
  |---|---|
62
122
  | `AUTH_TOKEN_SECRET` | 自有 JWT 密钥(≥32 字节随机串),生产由平台注入。006 鉴权与 011 模块动作授权(action-grant)共用统一密钥链:未配置回退 `TBOX_API_KEY`(须 ≥32 字节)→ dev 临时随机;prod 整链空则 fail-fast(拒绝启动)。011 另有 `ACTION_TOKEN_SECRET` 覆盖档。本地一般无需设置 |
63
123
  | `AUTH_MODE` | `required`(默认,缺失 token 一律 401)/ `optional`(缺失 token → 匿名,写通道仍拒绝) |
64
- | `AUTH_DEV_LOGIN_DISABLED` | 非生产环境需关闭 dev-login 时设 `true`(dev-login 非 production 默认开启,生产强制关闭) |
65
124
  | `AUTH_TOKEN_TTL_MS` | token 有效期(毫秒,默认 2h) |
66
- | `AUTH_TOKEN_ISSUER` | token issuer(默认 `agent`) |
125
+ | `AUTH_TOKEN_ISSUER` | token issuer(默认 `agent`;如需 mall 独立身份可显式设 `agent-mall`) |
67
126
  | `AUTH_EMBED_EXTERNAL_TOKEN` | 是否把外部原始 token 内嵌进自有 JWT(external claim,默认 `true`;`false` 则上游调用需另取) |
68
127
  | `AUTH_EXTERNAL_TOKEN_MAX_BYTES` | external 原始 token 上限(bytes,默认 16KB=Node http header 上限)。external claim 使自有 JWT 膨胀 ~1.4x,生产网关 header 上限需 ≥16KB |
69
128
  | `AUTH_EXTERNAL_EXCHANGE_URL` | 外部 provider 换发地址;配置后 `/api/auth/login(platform=external)` 走 HMAC 转发换发 |
@@ -72,6 +131,21 @@ dev 态 `TBOX_CONFIG_DIR` 可指档位目录替换默认 `config/`。**改 chat.
72
131
  | `AUTH_EXTERNAL_JWT_PUBLIC_KEY` | 外部已签 JWT 验签公钥(PEM,RS256):外部返回 `{ jwt }` 且无 identity 时解 `sub`;未配置则解码 `payload.sub` |
73
132
  | `AUTH_EXTERNAL_TIMEOUT_MS` | 外部换发请求超时(毫秒,默认 3000) |
74
133
 
134
+ ### 真实支付宝登录链路(provider 包换码器自注册)
135
+
136
+ `config/integrations.json` 登录槽(`auth.alipay-login`)配置且装配了对应 provider 包时,壳内
137
+ `my.getAuthCode` → `/api/auth/login` → 换码器注册表按登录 context 的 mallId 路由:命中某厂商
138
+ 登录槽实例 → 该厂商换码器出马;未命中 mall 由兜底厂商接管(F2 注册制,机制详见 docs/reference/providers.md):
139
+
140
+ - 前提:登录槽实例的 provider 必须装配对应 provider 包(漏装 → 登录落内置 alipay,
141
+ 未配凭据 503 局部降级);实例 config 的厂商 appId 字段已配(漏配 → 该 mall 503,字段名见各 provider 包)。
142
+ - 登录双形态与复合凭证语义由各 provider 包承载;`AUTH_TOKEN_TTL_MS` 保守建议 ≤2h
143
+ (上游 Token 寿命未知;自有 JWT 过期即重登换新)。
144
+ - ⚠️ 与 `VITE_AUTH_PROVIDER=external` **互斥**:设 external 走 `AUTH_EXTERNAL_*` HMAC 转发旁路,
145
+ 换码器被 platform 路由绕过,两者勿同时启用。
146
+ - 裸跑(无登录槽配置):无换码器注册 → 内置 alipay(未配 → 503)或 browser 轴 guest(内置换码器 allowsGuestLogin),匿名降级属预期行为。
147
+ - 跨 mall 切换(URL `mallId` 变更)由 SDK `scopeKey` 守卫自动清 token 重登,无需手工登出。
148
+
75
149
  ## 客户端(Vite 注入)
76
150
 
77
151
  > 注意:`VITE_*` 由 Vite 在开发/构建时注入(读取 `apps/client/.env` 或启动 shell 中已 export 的环境变量),
@@ -91,8 +165,9 @@ dev 态 `TBOX_CONFIG_DIR` 可指档位目录替换默认 `config/`。**改 chat.
91
165
  | `TTS_AUTH_URL` / `TTS_APPKEY` | TTS 鉴权必需:AUTH_URL 为鉴权网关端点(POST `{appkey}` → `timestamp+digest`);APPKEY 为 TTS 应用密钥。**缺失时 TTS 播放直接 CONFIGURATION_ERROR(无「走平台」回退)**,前端报 `[TTS] server error` |
92
166
  | `TBOX_SKILL_MODE` | 本地 Skill 模式(009):`accelerated`(默认,本地路由命中 → SOP 注入当前轮 user 消息,零额外 LLM 轮次)/ `progressive`(全量注册 InlineSkill,模型渐进 skill_read)。非法值回退默认 |
93
167
  | `TBOX_PRE_TOOL_TIMEOUT_MS` | 前置工具(010)单工具总预算 ms(decide+execute 共享):默认 `2000`;`0` = 整体禁用(预执行全关,行为与未启用逐字节一致)。非法值回退默认 |
94
- | `TBOX_TOOL_DEBUG` | 工具调试视图(018):`1` 开 / `0` 关;缺省 = 非 `NODE_ENV=production` 开启。开启时 memory 召回/silent 前置工具以伪工具事件下发前端(不持久化)且 HELLO_ACK 携带旗标解锁客户端 dev 工具视图(出入参展开+紧凑格式)。**生产勿开**——测试环境开启会使 silent 检索 query 与用户记忆预览(截断 200 字符)对页面访问者可见。非法值回退缺省 |
168
+ | `TBOX_TOOL_DEBUG` | 工具调试视图(018):`1` 开 / `0` 关;缺省 = 非 `NODE_ENV=production` 开启。开启时 memory 召回/silent 前置工具以伪工具事件下发前端(不持久化)且 HELLO_ACK 携带旗标解锁客户端 dev 工具视图(出入参展开+技术名+紧凑格式)。**生产勿开**——测试环境开启会使 silent 检索 query 与用户记忆预览(截断 200 字符)对页面访问者可见。非法值回退缺省 |
95
169
  | `TBOX_EARLY_TOOL_EXECUTION` | 尽早工具执行(缺省 `off`):`1`/`true` 开启。模型流中白名单工具(只读查询类,`withEarlyExecution` 标记)参数流完即预执行,多工具轮延迟优化;收益依赖 `parallelToolCalls` 开启;参数漂移自动作废重执行(正确性无损);单工具轮行为等价现状。仅显式 opt-in,观测 journal `tool_preexec` |
170
+ | `MALL_HOME_DEV_SERVICES` | 首页「常用服务」开发测试入口展示开关:`true`/`1` 展示,`false`/`0`/缺席隐藏(fail-closed,正式用户零透出;生产部署不配置即隐藏态)。server 启动期解析,经 `GET /api/m/mall-home/config` 下发前端(响应 `{ showDevServices: boolean }`);env 变更需重启进程。注入走外层 source(档位 env 文件/启动器 scripts/app-dev.mjs),`tbox-app dev` 不注入 env 值 |
96
171
  | `HOST` | 服务监听地址(默认 `0.0.0.0`) |
97
172
  | `PORT` | 服务监听端口(默认 `8000`) |
98
173
 
@@ -101,10 +176,19 @@ dev 态 `TBOX_CONFIG_DIR` 可指档位目录替换默认 `config/`。**改 chat.
101
176
  ```sh
102
177
  export APP_AI_BASE_URL=https://...
103
178
  export APP_AI_API_KEY=...
104
- export APP_AI_MODEL_NAME=...
179
+ export APP_AI_MODEL_NAME=... # 兜底模型名:config/llm_provider.json 的 modelName 优先于此(文件缺席才生效)
105
180
  export TBOX_API_KEY=...
106
181
  export TBOX_APP_ID=...
107
182
  # TTS(可选;缺失时 TTS 播放报 CONFIGURATION_ERROR):
108
183
  export TTS_AUTH_URL=https://open.tbox.alipay.com/agent/v1/homepage/secret/get
109
184
  export TTS_APPKEY=your-tts-appkey # 敏感值勿提交;本地 shell export 注入(生产由平台注入)
185
+ # 首页开发测试入口(可选;缺省隐藏,本地联调需要时打开):
186
+ export MALL_HOME_DEV_SERVICES=true
110
187
  ```
188
+
189
+ # tbox-app dev 配置面
190
+
191
+ - `TBOX_CONFIG_DIR`:dev 命令注入的配置目录覆盖(real-env 档位绝对路径);未设时使用默认 `config/`。
192
+ 覆盖面含 `llm_provider.json`(`modelName`/`thinking`):注入时 LLM 装配读档位目录文件,
193
+ 其 `modelName` 优先于 `APP_AI_MODEL_NAME`;档目录缺该文件 → 链式回退 env(config-dir 独占
194
+ 注入语义:缺文件 = 显式不指定,不落回模板默认 config)。
package/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # template-agent
2
2
 
3
- tbox AI Agent 全栈模板(npm 包名 `@tbox.cn/app-template-agent`),多包 pnpm workspace:`apps/` 薄组装端 + `packages/` 模块。
3
+ tbox AI Agent 全栈模板(npm 包名 `@tbox.cn/app-template-agent`,唯一模板——W4 单一模板统一化),多包 pnpm workspace:`apps/` 薄组装端 + `packages/` 模块。
4
+ 缺省出厂 = 空装配(chat 形态);**商圈形态经 `profiles/mall` 画像加装**(`tbox-app create --profile mall`:mall-core/mall-home + 六业务模块 + 商圈配置叠加)。
4
5
  客户端同时支持浏览器和支付宝小程序 web-view;平台能力(鉴权/会话/TTS/ASR/上传/反馈)经 `@tbox.cn/app-sdk` 统一提供(007 下沉)。
5
6
 
6
7
  ## 快速开始
@@ -11,6 +12,19 @@ pnpm dev # 单进程 http://localhost:8000(API + WS + 页面 + HMR)
11
12
  pnpm verify # typecheck + test + build
12
13
  ```
13
14
 
15
+ **能力加装**(空装配起点,能力即模块;mall 全套可改用 `create --profile mall` 一步到位):
16
+
17
+ ```sh
18
+ tbox-app module add shopping-guide # 导购/找店/业态/客服(模块级 intents + LLM 工具 + 卡片)
19
+ tbox-app module add member # 会员卡/积分/优惠券(queryPoints preTool always 身份预执行)
20
+ tbox-app module add parking promotion # 停车/活动(可选)
21
+ tbox-app module doctor # 26 条结构校验
22
+ ```
23
+
24
+ **MallHome 服务域**(015;`--profile mall` 加装 mall-home 后生效):家页 `packages/module-mall-home` 四域开箱——导购/会员/活动优惠(promotion)/停车服务(parking);域 query 走工具与意图路由链(模块 add/remove 即增删能力,无部署级门控)。
25
+
26
+ **宿主效果链**(015):支付/支付宝授权效果由 SDK 自动执行(host-effect-runner:壳内拉起收银台/授权、浏览器环境自动降级),结果经补签 grant 回传收口——模板零装配;停车场次/入会 pending 收口均为显式按钮交互。
27
+
14
28
  > 环境变量:本地开发用 shell export 注入(见 `ENV.md`,含必需变量命令块;每次新终端需重新执行),
15
29
  > 生产建议在 tbox 平台页面上配置(平台托管 env,密钥不进代码仓库)。
16
30
 
@@ -21,20 +35,21 @@ pnpm verify # typecheck + test + build
21
35
  > 依赖链说明(007):`@tbox.cn/app-sdk` 新增 dependencies `@tbox-dev-js/sdk`(平台能力客户端)、`@ai-sdk/openai-compatible`(LLM)——
22
36
  > 生成应用 install 时由 pnpm 自动解析(`@tbox-dev-js/sdk` 已发布 npm;内网/离线环境需 registry 镜像或 store 缓存兜底)。
23
37
 
24
- > 🔐 鉴权(006):非 production 默认开启 dev-login(浏览器 H5 测试登录,开箱即用);
25
- > 生产部署必须 `NODE_ENV=production`(dev-login 强制关闭)。非生产环境如需关闭设
26
- > `AUTH_DEV_LOGIN_DISABLED=true`。
38
+ > 🔐 鉴权(统一登录):登录面 = `POST /api/auth/login`(`method:'code'|'browser'` 判别);
39
+ > 浏览器档位(guest/mock/off/auto)经换码器 `browserLoginMode` 能力口治理(登录槽 config,
40
+ > 支持 `${VAR:-default}` 展开经 env 分档);生产部署必须 `NODE_ENV=production`。
27
41
 
28
42
  ## 工程结构
29
43
 
30
44
  ```text
31
45
  template-agent/
46
+ profiles/ 模板画像(mall.json 加装计划 + config 叠加;create --profile 消费)
32
47
  apps/
33
48
  client/ React/Vite 装配端(业务页面/组件/hooks/样式;平台能力经 @tbox.cn/app-sdk/client)
34
49
  server/ Express + WS 装配端(~120 行装配:auth 中间件 + 模块挂载 + 平台路由面/TTS/WS)
35
50
  server/skills/ 本地 Skill(SKILL.md 目录格式,随模板复制/pack)
36
51
  packages/
37
- module-weather/ 示例业务模块(双端单包)
52
+ 模块目录(空装配:能力经 `tbox-app module add` 扩展——`@app/<id>` 成员在此生成)
38
53
  config/ chat/model/plugin 配置
39
54
  scripts/ 构建、检查和平台脚本
40
55
  pnpm-workspace.template.yaml 应用 workspace 模板(create 生成应用 pnpm-workspace.yaml 的来源)
@@ -61,25 +76,25 @@ apps/server/skills/<skill-name>/
61
76
 
62
77
  模板已内置 `shopping-guide` 示例(含子目录 references)。新增步骤:建目录 → 写 SKILL.md(`name` 须匹配 `^[a-z0-9-]{1,64}$`)→ references 可选 → 启动加载(无需改代码)。
63
78
 
64
- ### 模块级 Skill(文件加载,推荐示例)
79
+ ### 模块级 Skill(文件加载)
65
80
 
66
81
  模块包内放 `skills/` 目录(与 `src/` 平级),顶层 await 加载后填回 `serverModule.skills` 声明式通道(装配端 `registerAll` 自动注册,register 内零代码):
67
82
 
68
83
  ```text
69
- packages/module-weather/
70
- ├── skills/weather-guide/
84
+ packages/<module-id>/
85
+ ├── skills/<skill-name>/
71
86
  │ ├── SKILL.md # frontmatter(name/description/metadata.routingTerms)+ SOP
72
- │ └── references/dressing-tips.md
87
+ │ └── references/*.md
73
88
  ├── src/server/index.ts
74
89
  └── package.json # exports 须含 "./package.json": "./package.json"
75
90
  ```
76
91
 
77
92
  ```ts
78
- // packages/module-weather/src/server/index.ts
93
+ // packages/<module-id>/src/server/index.ts
79
94
  import { loadModuleSkills } from '@tbox.cn/app-sdk/server';
80
95
 
81
96
  const skills = Object.fromEntries(
82
- (await loadModuleSkills('@app/module-weather', import.meta.url)).map((s) => [s.name, s]),
97
+ (await loadModuleSkills('@app/<module-id>', import.meta.url)).map((s) => [s.name, s]),
83
98
  ) satisfies Record<string, LocalSkill>;
84
99
 
85
100
  export const serverModule = { cards, skills, register(ctx) { /* ... */ } } satisfies ServerModule;
@@ -93,8 +108,8 @@ inline 声明(`serverModule.skills` 直接内联 instructions/references)仍
93
108
 
94
109
  ```sh
95
110
  # 启动日志会打印装配结果:mode + skill 名列表(不含内容)
96
- [SKILL] mode=accelerated skills=weather-guide,shopping-guide
97
- # 提问触发词(accelerated):"今天天气怎么样"(weather-guide → getWeather 工具+卡片)/ "3楼有什么"(shopping-guide → SOP)
111
+ [SKILL] mode=accelerated skills=shopping-guide-demo
112
+ # 提问触发词(accelerated):"商场里有什么值得逛"(shopping-guide-demo SOP)→ 商圈工具/卡片
98
113
  # 切换模式:TBOX_SKILL_MODE=progressive
99
114
  ```
100
115
 
@@ -109,11 +124,11 @@ inline 声明(`serverModule.skills` 直接内联 instructions/references)仍
109
124
  // 应用:BuildEngineOptions.preTools(apps/server/src/pre-tools.ts)
110
125
  // 统一经 definePreTool(tool, spec) 构造——tool 实例引用 = 单一真源(id/description 派生)
111
126
  import { definePreTool } from '@tbox.cn/app-sdk/server';
112
- definePreTool(weatherTool, {
113
- routing: { mode: 'keywords', terms: ['天气', '气温'] }, // ② 结构化路由:词表打分 / { mode:'always' } 必选
127
+ definePreTool(findStoreTool, {
128
+ routing: { mode: 'keywords', terms: ['找店', '门店', '哪里有'] }, // ② 结构化路由:词表打分 / { mode:'always' } 必选
114
129
  decide: ({ text, identity }) => { // ③ 决策即构造:run(args) = 预执行 / skip = 不生效
115
- const city = CITIES.find((c) => text.includes(c));
116
- return city ? { decision: 'run', args: { city } } : { decision: 'skip' };
130
+ const store = STORES.find((s) => text.includes(s.name));
131
+ return store ? { decision: 'run', args: { storeId: store.id } } : { decision: 'skip' };
117
132
  },
118
133
  });
119
134
  ```
@@ -131,36 +146,23 @@ definePreTool(weatherTool, {
131
146
 
132
147
  | 示例 | 位置 | 形态 |
133
148
  |---|---|---|
134
- | `getWeather` | `packages/module-weather/src/server/pre-tools.ts` | 文本抽取(城市词表,抽不到 skip)——与 weather-guide skill SOP 共存,单轮完成 |
135
149
  | `getCurrentTime` | `apps/server/src/pre-tools.ts` + `tools/clock.ts` | 零参工程化(词表命中即执行) |
136
- | `queryPoints` | `modules/module-member`(`tbox-app module add` 后) | `always` 必选 + 身份门控(identity 取 userId,匿名 skip) |
150
+ | `mall-info` | `modules/module-mall-core`(W3-1 自模板迁入;`--profile mall`/module add 后经模块声明式 preTools 通道生效) | always + mall scope 入参化(每轮背景注入;会话内 dedup 一次) |
151
+ | `queryPoints` | `modules/module-member`(`tbox-app module add member` 后) | `always` 必选 + 身份门控(identity 取 userId,匿名 skip) |
137
152
  | `translate` | 反例(不改代码) | 参数依赖语义抽取,不适配——保持 LLM 工具路径 |
138
153
 
139
154
  ### 冒烟
140
155
 
141
156
  ```sh
142
157
  # 启动日志:timeout + 预执行工具清单
143
- [PRETOOL] timeoutMs=2000 preTools=getCurrentTime,getWeather
144
- # ①"杭州天气怎么样" → thinking 气泡出现「自动查询 查询城市天气信息」(label = 工具自身 description 派生)→ 直接作答(单轮 1 次模型请求,无 getWeather 二次调用)
145
- # ②"现在几点了" → 「自动查询 查询当前日期和时间」→ 作答(零参形态)
158
+ [PRETOOL] timeoutMs=2000 preTools=getCurrentTime
159
+ # ①"现在几点了" → 「自动查询 查询当前日期和时间」→ 作答(零参形态)
160
+ # ② 安装 member 后(tbox-app module add member)"我的积分有多少" → 「自动查询」徽标(always + 身份门控)→ 积分卡
146
161
  # ③"帮我翻译 hello" → 无「自动查询」徽标(反例:正常 LLM 工具路径)
147
162
  # ④ TBOX_PRE_TOOL_TIMEOUT_MS=0 复测① → 回退为模型调用工具两轮(对比基准)
148
163
  # ⑤ 刷新页面 → 历史消息仍显示「已自动获取」徽标(inputs.preTools 重建)
149
- # ⑥"杭州天气怎么样"后再问"那纽约呢"(词表外城市) → decide 不命中 → 模型正常调用 getWeather(city=纽约)(无合成工具消息,跨轮不再泛化「已调用过」)
150
- ```
151
-
152
- ## 深链自动发送
153
-
154
- 打开页面时 URL 携带 `?query=...`(或 `?prompt=...` 兜底,`query` 优先)即自动发送该消息一次,
155
- 与手动输入同通道。参数读取后立即从地址栏剥离(replaceState):刷新不重发、分享不带参;
156
- socket 5 秒内未就绪则静默放弃。SDK 单点实现(`@tbox.cn/app-sdk/client` 的
157
- `consumeAutoSendQuery`/`runAutoSend`),模板侧仅 3 行接线(IndexPage init effect)。
158
-
159
- ### 冒烟
160
-
161
- ```sh
162
- # 浏览器访问 http://127.0.0.1:8000/?query=今天天气怎么样
163
- # 预期:自动发送一次;地址栏 query 消失(其余参数保留);刷新不重发;dev 模式(StrictMode)不双发
164
+ # ⑥"现在几点了"后再问"那纽约时间呢" → decide 不命中 → 模型正常调用(无合成工具消息,跨轮不再泛化「已调用过」)
165
+ # ⑦(装配 mall.info 供给后)"这个商场叫什么名字/在哪儿" → mall-info 注入块背景供数(silent 零前端事件;模型直调时显示「查询商场信息」)
164
166
  ```
165
167
 
166
168
  ## 平台能力定制(007 扩展点)
@@ -173,7 +175,7 @@ socket 5 秒内未就绪则静默放弃。SDK 单点实现(`@tbox.cn/app-sdk/c
173
175
  | `getToolRequestContext` / `requireToolRequestContext` | `@tbox.cn/app-sdk/server` | 工具 execute 第二参读取运行上下文(fail-soft / 缺失抛 AUTH_FORBIDDEN;上下文统一化) |
174
176
  | `createToolExecContext(reqCtx)` | `@tbox.cn/app-sdk/server` | 测试/直调助手:构造工具 execute 第二参(散键与引擎同构) |
175
177
  | `createPlatformAdapters(session, overrides)` | `@tbox.cn/app-sdk/client` | 自定义 ASR/TTS/upload/feedback 实现(contracts 接口,UI 零改动) |
176
- | `createAuthClient({ loginPlatform, devUser })` | `@tbox.cn/app-sdk/client` | 客户端登录配置(`main.tsx`/`platform/agent-runtime.ts`);**应用级单例**——重复调用幂等返回首建实例,首建选项生效 |
178
+ | `createAuthClient({ loginPlatform, scopeKey })` | `@tbox.cn/app-sdk/client` | 客户端登录配置(`main.tsx`/`platform/agent-runtime.ts`);**应用级单例**——重复调用幂等返回首建实例,首建选项生效 |
177
179
  | `configureRuntime({ apiBaseUrl })` | `@tbox.cn/app-sdk/client` | API/WS 地址注入(`main.tsx`;对应 `VITE_API_URL`) |
178
180
  | bridge 透传 | `@tbox.cn/app-sdk/client` 的 `callJsapi` | 业务新能力(扫码/导航/分享等,壳子补 JSAPI 白名单) |
179
181
 
@@ -6,7 +6,7 @@
6
6
 
7
7
  1. **解析图片** → 按下方「设计指南输出模板」产出完整文档(颜色给 `#xxxxxx`、文案给完整原文、尺寸给具体 px)。
8
8
  2. **用户确认** → 等确认或调整。
9
- 3. **按指南开发** → 遵守下方「还原硬规则」+ `client/AGENTS.md`(组件/图标/图片策略)+ `server/src/cards/AGENTS.md`(卡片)。
9
+ 3. **按指南开发** → 遵守下方「还原硬规则」+ `../../AGENTS.md`(模板根:web-view 样式约定/组件策略/工程边界)。
10
10
 
11
11
  ---
12
12
 
@@ -24,29 +24,29 @@
24
24
  ## 平台固定组件:不碰、不另画、不挪位
25
25
 
26
26
  对话基础设施是平台封装好的——**识别到就跳过,只还原它们之间的业务内容区**:
27
- - `ChatInput`(输入框/上传/语音)、`MessageBubble`(气泡/Markdown/思考)、`ActionBar`(朗读/复制/赞踩/调试)、`ChatHeader`、`ScrollToBottomButton` / `PullDownIndicator`、`CardRenderer`。
27
+ - `ChatInput`(输入框/上传/语音)、`MessageBubble`(气泡/Markdown/思考)、`ActionBar`(朗读/复制/赞踩/调试)、`ChatHeader`、`ScrollToBottomButton` / `PullDownIndicator` / `HistoryEntry`(顶部历史入口胶囊)、`CardRenderer`。
28
28
  - **快捷指令 = `QuickCommands`**:不管设计稿里它在哪个位置、标题叫什么(千问/推荐/常见问题),**都只配 `client/config/chat.json` 的 `quickCommands`,绝不在页面里再画一份**(否则和底部重复成两排);`label` 只写纯文字、图案走 `icon` 字段(别把 ✦/emoji 写进 label)。
29
- - 详见 `client/AGENTS.md`「平台标准组件」。
29
+ - 详见 `../../AGENTS.md`(模板根:「双运行时与插件」与工程边界)。
30
30
 
31
31
  ## 技术路线判断(判错全盘皆错)
32
32
 
33
- - **整屏 App 页**(带状态栏 / 导航 / 输入框的一整屏,如智能体首页)→ 改 `client/src/pages/index`,**复用现成模块**(欢迎/轮播/宫格/猜你想问)改数据,**禁止做成卡片**。
34
- - **对话气泡里的一块结构化内容**(点单/天气/确认/推荐)→ 走**卡片(C 方案)**:server `cards/<type>/meta.ts` 数据契约 + client `cards/<type>/index.tsx` React 渲染。见 `server/src/cards/AGENTS.md`。
33
+ - **整屏 App 页**(带状态栏 / 导航 / 输入框的一整屏,如智能体首页)→ 改 `client/src/pages/index`,**复用现成模块**(欢迎/轮播/宫格/提问建议)改数据,**禁止做成卡片**。
34
+ - **对话气泡里的一块结构化内容**(点单/确认/推荐)→ 走**卡片(C 方案)**:server `cards/<type>/meta.ts` 数据契约 + client `cards/<type>/index.tsx` React 渲染。见 `../../AGENTS.md`「模块开发」(卡片双端形态与铁律)。
35
35
 
36
36
  ## 素材
37
37
 
38
38
  - **图标**:`@phosphor-icons/react`——**线性用默认、设计稿是实心图标就 `weight="fill"`**(别再退回 `<img>`);具名导出,名字按语义猜、拼错会编译报错。`size` 偏大就取小(16–24、宫格/导航 28)。只有**品牌/插画/定制图标**(图库字体都给不了的)才用 `<img>` 素材槽位。
39
- - **图片**:除 icon 外(含品牌 / 立绘 / logo 等,不区分)一律**先取一张 Unsplash 真图**(有 key 走 API、无 key 拼 `images.unsplash.com/photo-<id>?w=800&q=80`;精确词不行就用泛词、示意到位即可)、**必须 `curl` 验证 `200 + image/ + 体积` 通过才用**,验不过换 id/换词、多次不行才降级成渐变块——**完整规则见 `client/AGENTS.md`「图片素材策略」**。**别用孤零零小 emoji 充当主视觉**。
39
+ - **图片**:除 icon 外(含品牌 / 立绘 / logo 等,不区分)一律**先取一张 Unsplash 真图**(有 key 走 API、无 key 拼 `images.unsplash.com/photo-<id>?w=800&q=80`;精确词不行就用泛词、示意到位即可)、**必须 `curl` 验证 `200 + image/ + 体积` 通过才用**,验不过换 id/换词、多次不行才降级成渐变块。**别用孤零零小 emoji 充当主视觉**。
40
40
 
41
41
  ## 卡片还原(C 方案的落地路线)
42
42
 
43
43
  判断为卡片后(见上「技术路线判断」),按这条链走,各步细节指向真源、不在此复述:
44
44
 
45
- 1. **拆解** → 按下面「图片解析」「设计指南输出模板」出设计指南。含 tab / 步进 / 表单 / 派生值的交互卡,额外列 **source / derived / emit**:source→`useState`、derived→渲染时由 state 算、emit→`sendUiAction(cardId, …)` 的 payload 读当前 state(完整见 `server/src/cards/AGENTS.md`「交互卡片的设计纪律」)。
46
- 2. **落地** → 严格按 `server/src/cards/AGENTS.md`「新增卡片步骤」:server `meta.ts`(dataSchema 字段全 `.default` / `.optional`)+ 两端 `registry` 注册 + 触发 tool 接 `TOOL_CARD_MAP`;client `index.tsx`(`data` 用 `import type` 从 meta 推导)。
45
+ 1. **拆解** → 按下面「图片解析」「设计指南输出模板」出设计指南。含 tab / 步进 / 表单 / 派生值的交互卡,额外列 **source / derived / emit**:source→`useState`、derived→渲染时由 state 算、emit→`sendUiAction(cardId, …)` 的 payload 读当前 state(交互卡纪律见 `../../AGENTS.md`「模块开发」)。
46
+ 2. **落地** → 按 `../../AGENTS.md`「模块开发」:server `meta.ts`(dataSchema 字段全 `.default` / `.optional`)+ 两端 `registry` 注册 + 触发 tool 接 `TOOL_CARD_MAP`;client `index.tsx`(`data` 用 `import type` 从 meta 推导)。
47
47
  3. **数据** → 还原出的文案 **1:1 落进 `sampleData` 和 dataSchema `.default`**(真实文案,default 不能是占位词——它是兜底展示值)。
48
- 4. **样式** → 字号按 2x 梯度;圆角 / 阴影 / 默认白底走 `.tbox-card` 卡框(已裁圆角)、**内边距和宽度自己写**;整卡换底色 / 出血图就在卡片 root 设 `background` / 铺满图(会裁进圆角、不出白边),**别再套一层带圆角容器**;宽度占满整列。详见 `server/src/cards/AGENTS.md`。
49
- 5. **图片** → 除 icon 外先取 Unsplash 直链(有 key 走 API、无 key 拼 `images.unsplash.com/photo-<id>`)+ `curl` 验证 `200 + image/ + 体积` 通过才用,`<img>` 加 `onError` 占位(见上「素材」与 `client/AGENTS.md`「图片素材策略」)。
48
+ 4. **样式** → 字号按 2x 梯度;圆角 / 阴影 / 默认白底走 `.tbox-card` 卡框(已裁圆角)、**内边距和宽度自己写**;整卡换底色 / 出血图就在卡片 root 设 `background` / 铺满图(会裁进圆角、不出白边),**别再套一层带圆角容器**;宽度占满整列。详见 `../../AGENTS.md`「模块开发」(卡片双端形态与铁律)。
49
+ 5. **图片** → 除 icon 外先取 Unsplash 直链(有 key 走 API、无 key 拼 `images.unsplash.com/photo-<id>`)+ `curl` 验证 `200 + image/ + 体积` 通过才用,`<img>` 加 `onError` 占位(见上「素材」)。
50
50
 
51
51
  **收尾自检**:模块 / 文案 1:1?折叠区没补全?字号已 ×2(没照抄 1x 截图)?容器没重画?图片都校验过 + 带 `onError`?`sampleData` / `.default` 是真实文案?server `build` 与 client `typecheck` / `build` 通过?
52
52
 
@@ -56,7 +56,7 @@
56
56
 
57
57
  - **深度拆解**:不要只描述整体外观,**逐层拆解内部结构**——子元素组成、排列(水平/垂直/网格)、对齐、嵌套。如一张卡:左图标+右文字还是上图下文?文字有无主标题+副标题层级?有无右侧箭头/标签?
58
58
  - **尺寸精度**:所有尺寸给**具体 px**(以屏宽 375 或设计稿标注宽为基准按比例反推),禁止"较大/适中/紧凑"。必标:整体宽高、内边距(上右下左)、子元素间距 gap、圆角、图标/头像尺寸、行高。判断不准的给估计值并标"(估计值)"。
59
- - ⚠️ **量出来的是屏上(1x)px**;写进卡片 `.less` 时是 **2x 源码 px(CSS px 会折半渲染),一律 ×2**;字号别自定、直接用 `server/src/cards/AGENTS.md` 的 2x 字号梯度。图标 `size`(屏幕 px)与热区 44 不折半、不 ×2。
59
+ - ⚠️ **量出来的是屏上(1x)px**;写进卡片 `.less` 时是 **2x 源码 px(CSS px 会折半渲染),一律 ×2**;字号别自定、直接用 `src/styles/tokens.less` 的字号梯度注释(2x 真源)。图标 `size`(屏幕 px)与热区 44 不折半、不 ×2。
60
60
  - **完整文案提取**:所有可见文字逐字抄录(标题/副标题/按钮/placeholder/提示/标签/声明),不可"类似 xxx"。
61
61
 
62
62
  ## 设计指南输出模板(每节必填,占位符替换成真实值)
@@ -7,6 +7,7 @@
7
7
  name="viewport"
8
8
  content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover"
9
9
  />
10
+ <meta name="theme-color" content="#fbfcfe" />
10
11
  <!-- rem 弹性根字号(对齐原模板 hd.ts:threshold 450 / designWidth 750)。
11
12
  在 CSS 前同步执行,避免首屏字号闪动。
12
13
  - 移动端(clientWidth<=450):动态 (100/750)*clientWidth;
@@ -25,7 +26,8 @@
25
26
  window.addEventListener('orientationchange', setRootFontSize);
26
27
  })();
27
28
  </script>
28
- <title>AI Agent</title>
29
+ <!-- 出厂标题 = 此处静态值(theme-tbox brand.js 出厂不覆写标题);租户主题经其 brand.js 运行时覆写 document.title -->
30
+ <title>AI 助手</title>
29
31
  <!-- 平台微调(inspector) runtime:由 server 提供 GET /__vs_inspector__.js;dev 下经 Vite 代理到 server。-->
30
32
  <script src="/__vs_inspector__.js" defer></script>
31
33
  </head>
@@ -7,20 +7,19 @@
7
7
  "scripts": {
8
8
  "dev": "vite",
9
9
  "build": "tsc --noEmit && vite build",
10
- "typecheck": "tsc --noEmit"
10
+ "typecheck": "tsc --noEmit",
11
+ "test": "vitest run"
11
12
  },
12
13
  "dependencies": {
13
- "@app/module-weather": "workspace:*",
14
- "@phosphor-icons/react": "catalog:",
15
14
  "@tbox.cn/app-sdk": "catalog:",
16
15
  "@tbox.cn/app-contracts": "catalog:",
17
- "antd-mobile": "catalog:",
16
+ "@tbox.cn/app-theme-tbox": "catalog:",
18
17
  "react": "catalog:",
19
18
  "react-dom": "catalog:",
20
- "react-markdown": "catalog:",
21
- "remark-gfm": "catalog:",
22
19
  "zustand": "catalog:",
23
- "@app/provider-custom": "workspace:*"
20
+ "@app/provider-custom": "workspace:*",
21
+ "@app/agent-ui-kit": "workspace:*",
22
+ "@app/contracts-mall": "workspace:*"
24
23
  },
25
24
  "devDependencies": {
26
25
  "@types/node": "catalog:",
@@ -30,6 +29,8 @@
30
29
  "less": "catalog:",
31
30
  "postcss-pxtorem": "catalog:",
32
31
  "typescript": "catalog:",
33
- "vite": "catalog:"
32
+ "vite": "catalog:",
33
+ "vitest": "catalog:",
34
+ "happy-dom": "catalog:"
34
35
  }
35
36
  }
@@ -1,11 +1,11 @@
1
1
  import AgentChatApp from '@/platform/AgentChatApp';
2
- import TourismLanding from '@/examples/tourism/TourismLanding';
3
2
 
4
3
  /**
5
4
  * 业务应用唯一入口。
6
- * 新应用替换本组件;需要对话能力时组合 AgentChatApp 和自己的业务 landing。
7
- * @tbox-template-example-active tourism
5
+ * mall 模板:空态首屏由 IndexPage 内 MallHome 呈现(商圈主屏),无需 landing 注入;
6
+ * 业务能力经 `tbox-app module add` 扩展(shopping-guide/member 等)。
7
+ * 新应用替换本组件;需要定制首屏时组合 AgentChatApp 或改 pages/index。
8
8
  */
9
9
  export default function BusinessApp() {
10
- return <AgentChatApp landing={TourismLanding} />;
10
+ return <AgentChatApp />;
11
11
  }