@tbox.cn/app-template-agent 0.8.0 → 0.10.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.
- package/AGENTS.md +88 -33
- package/ENV.md +9 -9
- package/README.md +6 -5
- package/apps/client/index.html +2 -2
- package/apps/client/package.json +2 -2
- package/apps/client/src/app.tsx +1 -1
- package/apps/client/src/cards/registry.ts +1 -1
- package/apps/client/src/main.tsx +1 -1
- package/apps/client/src/modules.ts +1 -1
- package/apps/client/src/platform/AgentChatApp.tsx +6 -5
- package/apps/client/src/platform/agent-runtime.ts +2 -2
- package/apps/client/src/store/chat.ts +2 -2
- package/apps/client/vite.config.ts +1 -3
- package/apps/server/package.json +2 -4
- package/apps/server/src/app-tools.ts +1 -1
- package/apps/server/src/app.ts +86 -18
- package/apps/server/src/cli/collect-registry.ts +1 -1
- package/apps/server/src/cli/plugin-doctor.ts +1 -1
- package/apps/server/src/cli/plugin-inspect.ts +1 -1
- package/apps/server/src/config/integration.ts +1 -1
- package/apps/server/src/dev.ts +2 -2
- package/apps/server/src/index.ts +1 -1
- package/apps/server/src/intent-routes.ts +1 -1
- package/apps/server/src/modules.ts +2 -2
- package/apps/server/src/pre-tools.ts +2 -2
- package/apps/server/src/tools/clock.ts +2 -2
- package/apps/server/src/tools/translate.ts +2 -2
- package/apps/server/tests/agent-prompt.test.ts +4 -4
- package/apps/server/tests/cards-registry.test.ts +1 -1
- package/apps/server/tests/intent-dispatcher.test.ts +1 -1
- package/apps/server/tests/tool-runtime.test.ts +2 -2
- package/package.json +3 -3
- package/packages/agent-ui-kit/package.json +2 -2
- package/packages/agent-ui-kit/src/ChatPage.tsx +1 -1
- package/packages/agent-ui-kit/src/chat-config.ts +1 -1
- package/packages/agent-ui-kit/src/components/ActionBar/DebugButton.tsx +1 -1
- package/packages/agent-ui-kit/src/components/ActionBar/index.tsx +2 -4
- package/packages/agent-ui-kit/src/components/CardRenderer.tsx +1 -1
- package/packages/agent-ui-kit/src/components/ChatInput/index.test.tsx +1 -1
- package/packages/agent-ui-kit/src/components/ChatInput/index.tsx +1 -1
- package/packages/agent-ui-kit/src/components/ChatInput/voice/useVoicePress.ts +2 -2
- package/packages/agent-ui-kit/src/components/MessageBubble/index.tsx +1 -3
- package/packages/agent-ui-kit/src/components/QuickCommands/index.test.tsx +1 -1
- package/packages/agent-ui-kit/src/components/ToolCallBlock/detail.test.ts +1 -1
- package/packages/agent-ui-kit/src/components/ToolCallBlock/detail.ts +1 -1
- package/packages/agent-ui-kit/src/hooks/useMediaUpload.ts +2 -2
- package/packages/agent-ui-kit/src/hooks/useTTSAutoPlay.ts +2 -2
- package/packages/agent-ui-kit/src/store-context.tsx +1 -1
- package/packages/agent-ui-kit/src/types.ts +2 -2
- package/packages/agent-ui-kit/src/utils/haptics.test.ts +1 -1
- package/packages/agent-ui-kit/src/utils/haptics.ts +1 -1
- package/packages/agent-ui-kit/src/utils/tool-call-display.test.ts +15 -15
- package/packages/agent-ui-kit/src/utils/tool-call-display.ts +1 -1
- package/packages/provider-custom/AGENTS.md +47 -21
- package/packages/provider-custom/README.md +1 -1
- package/packages/provider-custom/package.json +3 -2
- package/packages/provider-custom/src/server/index.ts +15 -12
- package/packages/provider-custom/tbox.module.json +8 -8
- package/pnpm-lock.template.yaml +114 -87
- package/pnpm-workspace.template.yaml +8 -4
- package/profiles/mall/TEMPLATE.md +42 -0
- package/profiles/mall.json +3 -2
- package/apps/client/src/shims/node-stub.ts +0 -14
package/apps/server/src/app.ts
CHANGED
|
@@ -4,15 +4,14 @@
|
|
|
4
4
|
* import 本模块即完成装配(与旧单文件入口时序等价:listen 仍在 start() 内最后发生)。
|
|
5
5
|
*/
|
|
6
6
|
import express from 'express';
|
|
7
|
-
import cors from 'cors';
|
|
8
7
|
import { createServer, type IncomingMessage } from 'http';
|
|
9
8
|
import type { Duplex } from 'node:stream';
|
|
10
9
|
import path from 'path';
|
|
11
10
|
import { existsSync } from 'node:fs';
|
|
12
11
|
import { fileURLToPath } from 'url';
|
|
13
12
|
import { registerAll } from './modules.js';
|
|
14
|
-
// ===== 模板日志(@tbox.cn/app-sdk
|
|
15
|
-
import { createLogger } from '@tbox.cn/app-sdk
|
|
13
|
+
// ===== 模板日志(@tbox.cn/app-agent-sdk-server createLogger:本地时间 + LEVEL + [tag] + req/conv 尾缀) =====
|
|
14
|
+
import { createLogger } from '@tbox.cn/app-agent-sdk-server';
|
|
16
15
|
const serverLogger = createLogger('server');
|
|
17
16
|
const authLogger = createLogger('AUTH');
|
|
18
17
|
const skillLogger = createLogger('SKILL');
|
|
@@ -25,6 +24,7 @@ import {
|
|
|
25
24
|
createEngineFromContext,
|
|
26
25
|
createIntegrationsRegistry,
|
|
27
26
|
loadProviderCatalog,
|
|
27
|
+
buildOwnershipMap,
|
|
28
28
|
tboxTraceExporter,
|
|
29
29
|
extractImageUrls,
|
|
30
30
|
TBOX_FILE_URL_PREFIX,
|
|
@@ -46,8 +46,8 @@ import {
|
|
|
46
46
|
loadAgentPromptConfig,
|
|
47
47
|
toWsChatConfig,
|
|
48
48
|
installTboxDev,
|
|
49
|
-
} from '@tbox.cn/app-sdk
|
|
50
|
-
import { installInspector } from '@tbox.cn/app-sdk/platform';
|
|
49
|
+
} from '@tbox.cn/app-agent-sdk-server';
|
|
50
|
+
import { installInspector } from '@tbox.cn/app-agent-sdk-server/platform';
|
|
51
51
|
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';
|
|
@@ -66,7 +66,7 @@ import {
|
|
|
66
66
|
createAuthStrategyRegistry,
|
|
67
67
|
createEnvironmentSecretProvider,
|
|
68
68
|
attachCardActionTokens,
|
|
69
|
-
} from '@tbox.cn/app-sdk
|
|
69
|
+
} from '@tbox.cn/app-agent-sdk-server';
|
|
70
70
|
|
|
71
71
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
72
72
|
|
|
@@ -115,7 +115,7 @@ const memory = {
|
|
|
115
115
|
// 模板无条件透传——读取一次,改文件需重启生效)
|
|
116
116
|
const AGENT_PROMPT = loadAgentPromptConfig(CONFIG_DIR);
|
|
117
117
|
|
|
118
|
-
// 平台能力装配(003/006 平台轴,已下沉 @tbox.cn/app-sdk
|
|
118
|
+
// 平台能力装配(003/006 平台轴,已下沉 @tbox.cn/app-agent-sdk-server)
|
|
119
119
|
// 011 L1 + F2/F3 + W3-1:装配序 integrations → authStrategies → auth → catalog → ctx——
|
|
120
120
|
// v4:部署拓扑并入 integrations.json(单文件真源);域投影/校验(deployment 语义)迁
|
|
121
121
|
// module-mall-core(ctx.domainAssemblies 惰性查表——auth 构造先于装配,动态判定经闭包后补)。
|
|
@@ -136,7 +136,7 @@ function mallAssembly(): MallScopeAssembly | undefined {
|
|
|
136
136
|
}
|
|
137
137
|
|
|
138
138
|
// 上下文统一化 Stage 2:validateContext 域校验注入(HTTP body.context 伪冒防线:
|
|
139
|
-
// mallId 形状校验(v4 恒动态)→ 403;只在全局面生效——login
|
|
139
|
+
// mallId 形状校验(v4 恒动态)→ 403;只在全局面生效——login 走 login-routes 独立归一化)。
|
|
140
140
|
// 与 WS validateScope 同核(isValidMallShape);无装配 → true(非 mall 部署放行)。
|
|
141
141
|
const auth = createAuthRuntime(undefined, {
|
|
142
142
|
validateContext: (attributes) => mallAssembly()?.validateScope(attributes) ?? true,
|
|
@@ -156,6 +156,10 @@ function appRoot(): string {
|
|
|
156
156
|
|
|
157
157
|
const providerCatalog = loadProviderCatalog(appRoot());
|
|
158
158
|
|
|
159
|
+
// integrations v6 所有权模型:服务归属表(service → moduleId,declare.owns 聚合单源)——
|
|
160
|
+
// modules[owner] 级绑定/配置求值的显式注入参(缺注入 + 文件含 modules 绑定 → fail-visible)
|
|
161
|
+
const ownershipMap = buildOwnershipMap(appRoot());
|
|
162
|
+
|
|
159
163
|
// provider 拆包 F2/F3:integrations 槽位解析轴(config/integrations.json 存在即生效;
|
|
160
164
|
// 缺席 → undefined,模块槽解析与换码链 fail-fast 显性暴露——旧 ProviderRegistry 链已拆除)
|
|
161
165
|
// instanceIdOf 注入 mall 语义(W3-1:沿域装配查表——mallId 派生归 module-mall-core)
|
|
@@ -164,6 +168,8 @@ const integrations = integrationsConfig
|
|
|
164
168
|
integrations: integrationsConfig.config,
|
|
165
169
|
// catalog 真源 = 应用根 .tbox/app.json(上方无条件装载)
|
|
166
170
|
catalog: providerCatalog,
|
|
171
|
+
// v6:归属表显式参(装配五行 → 六行)
|
|
172
|
+
ownerOf: ownershipMap,
|
|
167
173
|
authStrategies,
|
|
168
174
|
secretProvider: createEnvironmentSecretProvider({
|
|
169
175
|
source: process.env as Record<string, string | undefined>,
|
|
@@ -207,16 +213,46 @@ process.on('uncaughtException', (err) => {
|
|
|
207
213
|
});
|
|
208
214
|
|
|
209
215
|
export const app = express();
|
|
210
|
-
|
|
216
|
+
|
|
217
|
+
// ===== CORS allowlist(统一登录改造 T20:全开 cors() 退役) =====
|
|
218
|
+
// 双轴分离:iframe 嵌入走 CSP frame-ancestors(下方中间件),跨源 fetch 走本 allowlist。
|
|
219
|
+
// 三元组与 frame-ancestors 对齐(用户裁决 2026-09-13);credentials 恒 false(token 走
|
|
220
|
+
// Authorization 头,不依赖 cookie——跨源带凭据面直接关死)。
|
|
221
|
+
// 生成应用可编辑此常量(长尾 origin 逃生通道)——刻意不加 env(决策权归部署面代码)。
|
|
222
|
+
const CORS_ALLOWED_ORIGINS = ['https://tbox.cn', 'https://*.tbox.cn', 'http://localhost:3000'];
|
|
223
|
+
function originAllowed(origin: string): boolean {
|
|
224
|
+
return CORS_ALLOWED_ORIGINS.some((pattern) =>
|
|
225
|
+
pattern.includes('*')
|
|
226
|
+
? origin.endsWith(pattern.slice(pattern.indexOf('*') + 1))
|
|
227
|
+
: origin === pattern,
|
|
228
|
+
);
|
|
229
|
+
}
|
|
230
|
+
app.use((req, res, next) => {
|
|
231
|
+
const origin = req.headers.origin;
|
|
232
|
+
if (typeof origin === 'string' && originAllowed(origin)) {
|
|
233
|
+
res.setHeader('Access-Control-Allow-Origin', origin);
|
|
234
|
+
res.setHeader('Vary', 'Origin');
|
|
235
|
+
}
|
|
236
|
+
res.setHeader('Access-Control-Allow-Methods', 'GET,POST,DELETE,OPTIONS');
|
|
237
|
+
res.setHeader('Access-Control-Allow-Headers', 'Authorization,Content-Type,X-Request-ID');
|
|
238
|
+
res.setHeader('Access-Control-Allow-Credentials', 'false');
|
|
239
|
+
if (req.method === 'OPTIONS') {
|
|
240
|
+
res.sendStatus(204);
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
next();
|
|
244
|
+
});
|
|
245
|
+
|
|
211
246
|
app.use(express.json());
|
|
212
247
|
|
|
213
248
|
// 🔒 平台基础设施 — 禁止 AI 删除或修改(@infrastructure-locked)
|
|
214
249
|
installInspector(app);
|
|
215
250
|
|
|
216
|
-
//
|
|
217
|
-
|
|
251
|
+
// 浏览器登录形态提示:非 prod 裸跑(无 mall 控制面)默认开放 guest 登录(内置换码器
|
|
252
|
+
// allowsGuestLogin 声明);公网实例应以 NODE_ENV=production + 换码器档位收敛(browserLoginMode: off)
|
|
253
|
+
if (!isProduction) {
|
|
218
254
|
authLogger.warn(
|
|
219
|
-
'
|
|
255
|
+
'浏览器登录(browser 轴)按换码器档位开放:裸跑/demo 默认 guest。若本实例暴露公网,请设 NODE_ENV=production 并在登录槽 config 收敛 browserLoginMode。',
|
|
220
256
|
);
|
|
221
257
|
}
|
|
222
258
|
|
|
@@ -237,7 +273,7 @@ const ctx = createServerContext({
|
|
|
237
273
|
// 自动装配(W1-④:raw 派生 modules 资源节 + 源目录台账锚;无条件注册、与控制面正交,
|
|
238
274
|
// 防无控制面启动静默丢失)。模板显式注册已拆(W3-1:装配默认兜底覆盖同语义)。
|
|
239
275
|
|
|
240
|
-
// 全局 /api 鉴权(H2 挂载顺序契约):除 public(login/
|
|
276
|
+
// 全局 /api 鉴权(H2 挂载顺序契约):除 public(login/health)外一律要求 Bearer token;
|
|
241
277
|
// optional 模式缺失 token → 匿名身份(写通道仍被 action gateway 拒绝)
|
|
242
278
|
// ⚠️ 必须先于 /api/m、/api/action、createPlatformApiRouter 挂载,保证全 API 面受鉴权约束
|
|
243
279
|
app.use('/api', auth.middleware);
|
|
@@ -396,9 +432,9 @@ export async function start() {
|
|
|
396
432
|
// 默认商圈兜底/卡片动作授权/enhanceContext 全断——见 Agent Note 2026-09-17-mall-assembly-resolution-order)
|
|
397
433
|
const assembly = mallAssembly();
|
|
398
434
|
|
|
399
|
-
// 011 S6:mall 装配 + 生产环境缺动作授权密钥 →
|
|
435
|
+
// 011 S6:mall 装配 + 生产环境缺动作授权密钥 → 启动期提示(≥32B TBOX_API_KEY 在场回退 apiKey 档;整链空装配期 fail-fast)
|
|
400
436
|
if (assembly && isProduction && !process.env.ACTION_TOKEN_SECRET && !process.env.AUTH_TOKEN_SECRET) {
|
|
401
|
-
actionLogger.warn('生产环境未配置 ACTION_TOKEN_SECRET/AUTH_TOKEN_SECRET
|
|
437
|
+
actionLogger.warn('生产环境未配置 ACTION_TOKEN_SECRET/AUTH_TOKEN_SECRET——TBOX_API_KEY(≥32B) 缺席时装配将 fail-fast 拒绝启动;在场则回退 apiKey 档(平台运维可伪 action token)');
|
|
402
438
|
}
|
|
403
439
|
|
|
404
440
|
// 011 F2/E2:mall 装配(条件)——scope 会话 + 动作授权先行(engine attacher 依赖)
|
|
@@ -456,6 +492,19 @@ export async function start() {
|
|
|
456
492
|
const defaultContext = assembly?.defaultMallContext();
|
|
457
493
|
const chatWss = createWsServer(engine, {
|
|
458
494
|
auth: auth.wsAuth,
|
|
495
|
+
// 会话 β:会话建立服务(懒代理——TBOX_API_KEY 缺席时 NEW/RESUME 失败 notice,RUN 恒严格拒绝)
|
|
496
|
+
conversationService: {
|
|
497
|
+
createConversation: (agentId, userId) => {
|
|
498
|
+
const service = getConversationService();
|
|
499
|
+
if (!service) return Promise.reject(new Error('TBOX_API_KEY not configured'));
|
|
500
|
+
return service.createConversation(agentId, userId);
|
|
501
|
+
},
|
|
502
|
+
getOrCreateConversation: (agentId, userId) => {
|
|
503
|
+
const service = getConversationService();
|
|
504
|
+
if (!service) return Promise.reject(new Error('TBOX_API_KEY not configured'));
|
|
505
|
+
return service.getOrCreateConversation(agentId, userId);
|
|
506
|
+
},
|
|
507
|
+
},
|
|
459
508
|
...(scopeSessions
|
|
460
509
|
? {
|
|
461
510
|
scopeSessions,
|
|
@@ -487,7 +536,7 @@ export async function start() {
|
|
|
487
536
|
process.exit(1);
|
|
488
537
|
});
|
|
489
538
|
|
|
490
|
-
httpServer.on('upgrade', (request, socket, head) => {
|
|
539
|
+
httpServer.on('upgrade', async (request, socket, head) => {
|
|
491
540
|
socket.on('error', (e) => upgradeLogger.warn('socket error:', e.message));
|
|
492
541
|
if (upgradeDelegate?.(request, socket, head)) return;
|
|
493
542
|
const { pathname } = new URL(request.url || '/', 'http://localhost');
|
|
@@ -497,8 +546,27 @@ export async function start() {
|
|
|
497
546
|
chatWss.emit('connection', ws, request);
|
|
498
547
|
});
|
|
499
548
|
} else if (pathname === '/ws/tts') {
|
|
500
|
-
//
|
|
501
|
-
//
|
|
549
|
+
// 双层门 1(S5 修复,pre-101 鉴权):token 校验先行——TTS 代理原为全开放面。
|
|
550
|
+
// 双形态载体(IP-2):Node 客户端 = Authorization Bearer;浏览器 WebSocket 无法
|
|
551
|
+
// 自定义 header = ?token= query。无效/缺失 token 于 upgrade 前 destroy
|
|
552
|
+
// (对齐 Terminal channel 先例)。
|
|
553
|
+
const headerToken = (request.headers.authorization ?? '').replace(/^Bearer\s+/i, '');
|
|
554
|
+
const queryToken = new URL(request.url || '/', 'http://localhost').searchParams.get('token') ?? '';
|
|
555
|
+
const ttsToken = headerToken || queryToken;
|
|
556
|
+
if (!ttsToken) {
|
|
557
|
+
upgradeLogger.warn('TTS upgrade rejected: missing token');
|
|
558
|
+
socket.destroy();
|
|
559
|
+
return;
|
|
560
|
+
}
|
|
561
|
+
try {
|
|
562
|
+
await auth.tokenService.verify(ttsToken);
|
|
563
|
+
} catch {
|
|
564
|
+
upgradeLogger.warn('TTS upgrade rejected: invalid token');
|
|
565
|
+
socket.destroy();
|
|
566
|
+
return;
|
|
567
|
+
}
|
|
568
|
+
// 双层门 2(通道门与 UI 同值同源):chat.json enableTTS 单源——关态硬拒 upgrade,
|
|
569
|
+
// 防服务端开着 TTS 代理但 UI 已隐藏按钮的僵尸路径
|
|
502
570
|
if (!loadedChatConfig.enableTTS) {
|
|
503
571
|
upgradeLogger.warn('TTS disabled (chat.json enableTTS:false) — /ws/tts upgrade rejected');
|
|
504
572
|
socket.destroy();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createServerContext } from '@tbox.cn/app-sdk
|
|
1
|
+
import { createServerContext } from '@tbox.cn/app-agent-sdk-server';
|
|
2
2
|
import type { ToolCardBinding } from '@tbox.cn/agent-plugin/cards';
|
|
3
3
|
import { registerAll } from '../modules.js';
|
|
4
4
|
import { registerAppTools } from '../app-tools.js';
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
type PluginDiagnostic,
|
|
4
4
|
} from '@tbox.cn/agent-plugin/doctor';
|
|
5
5
|
import { loadMastraPluginTools } from '@tbox.cn/agent-plugin/mastra';
|
|
6
|
-
import { createPluginIntegration } from '@tbox.cn/app-sdk
|
|
6
|
+
import { createPluginIntegration } from '@tbox.cn/app-agent-sdk-server';
|
|
7
7
|
|
|
8
8
|
import { collectRegistryState } from './collect-registry.js';
|
|
9
9
|
|
|
@@ -2,7 +2,7 @@ import { inspectPluginTool } from '@tbox.cn/agent-plugin/inspect';
|
|
|
2
2
|
// 豁免:CLI 诊断工具(plugin:inspect)直接调 @tbox-dev-js/sdk 的 TboxPluginClient 做运行时检查,
|
|
3
3
|
// 非应用运行时平台能力路径(007 铁律针对平台能力调用;诊断工具保持直连)
|
|
4
4
|
import { TboxPluginClient } from '@tbox-dev-js/sdk';
|
|
5
|
-
import { createPluginIntegration } from '@tbox.cn/app-sdk
|
|
5
|
+
import { createPluginIntegration } from '@tbox.cn/app-agent-sdk-server';
|
|
6
6
|
|
|
7
7
|
import { collectRegistryState } from './collect-registry.js';
|
|
8
8
|
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
import { existsSync, readFileSync } from 'node:fs';
|
|
15
15
|
import path from 'node:path';
|
|
16
16
|
import { fileURLToPath } from 'node:url';
|
|
17
|
-
import { expandEnvVars, parseIntegrationsConfig } from '@tbox.cn/app-sdk
|
|
17
|
+
import { expandEnvVars, parseIntegrationsConfig } from '@tbox.cn/app-agent-sdk-server';
|
|
18
18
|
import type { IntegrationsConfig } from '@tbox.cn/app-contracts';
|
|
19
19
|
|
|
20
20
|
// 默认路径 = 应用根 config/integrations.json。双态锚点探测(bundle 打平后 import.meta.url 层级漂移):
|
package/apps/server/src/dev.ts
CHANGED
|
@@ -8,8 +8,8 @@ import path from 'path';
|
|
|
8
8
|
import { readFile } from 'node:fs/promises';
|
|
9
9
|
import { fileURLToPath } from 'url';
|
|
10
10
|
import { createServer as createViteServer } from 'vite';
|
|
11
|
-
import { injectScript, isReady } from '@tbox.cn/app-sdk/platform';
|
|
12
|
-
import { createLogger } from '@tbox.cn/app-sdk
|
|
11
|
+
import { injectScript, isReady } from '@tbox.cn/app-agent-sdk-server/platform';
|
|
12
|
+
import { createLogger } from '@tbox.cn/app-agent-sdk-server';
|
|
13
13
|
import { app, registerUpgradeDelegate, start } from './app.js';
|
|
14
14
|
|
|
15
15
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
package/apps/server/src/index.ts
CHANGED
|
@@ -7,7 +7,7 @@ import path from 'path';
|
|
|
7
7
|
import { existsSync } from 'node:fs';
|
|
8
8
|
import { fileURLToPath } from 'url';
|
|
9
9
|
import express from 'express';
|
|
10
|
-
import { createLogger } from '@tbox.cn/app-sdk
|
|
10
|
+
import { createLogger } from '@tbox.cn/app-agent-sdk-server';
|
|
11
11
|
import { app, start } from './app.js';
|
|
12
12
|
|
|
13
13
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
@@ -5,11 +5,11 @@
|
|
|
5
5
|
* 锚点区:@tbox:imports-begin/end(模块 import 行)+ @tbox:register-begin/end(模块数组)
|
|
6
6
|
* CLI 行为:增量插入/删除模块行,保留非标行。
|
|
7
7
|
*/
|
|
8
|
-
import type { ServerContext, InferModuleCards } from '@tbox.cn/app-sdk
|
|
8
|
+
import type { ServerContext, InferModuleCards } from '@tbox.cn/app-agent-sdk-server';
|
|
9
9
|
|
|
10
10
|
// @tbox:imports-begin
|
|
11
11
|
// SDK 装配框架(非模块行,CLI 增量维护保留非标行)
|
|
12
|
-
import { registerServerModules } from '@tbox.cn/app-sdk
|
|
12
|
+
import { registerServerModules } from '@tbox.cn/app-agent-sdk-server';
|
|
13
13
|
import { serverModule as providerCustom } from '@app/provider-custom/server';
|
|
14
14
|
// @tbox:imports-end
|
|
15
15
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
// 铁律:不直接 import @mastra/core,经 @tbox.cn/app-sdk
|
|
2
|
-
import { definePreTool } from '@tbox.cn/app-sdk
|
|
1
|
+
// 铁律:不直接 import @mastra/core,经 @tbox.cn/app-agent-sdk-server 的 definePreTool 入口(单例铁律)
|
|
2
|
+
import { definePreTool } from '@tbox.cn/app-agent-sdk-server';
|
|
3
3
|
import { clockTool } from './tools/clock.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
// 铁律:不直接 import @mastra/core,经 @tbox.cn/app-sdk
|
|
2
|
-
import { createTool } from '@tbox.cn/app-sdk
|
|
1
|
+
// 铁律:不直接 import @mastra/core,经 @tbox.cn/app-agent-sdk-server 的 createTool 入口(单例铁律)
|
|
2
|
+
import { createTool } from '@tbox.cn/app-agent-sdk-server';
|
|
3
3
|
import { z } from 'zod';
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
// 铁律:不直接 import @mastra/core,经 @tbox.cn/app-sdk
|
|
2
|
-
import { createTool } from '@tbox.cn/app-sdk
|
|
1
|
+
// 铁律:不直接 import @mastra/core,经 @tbox.cn/app-agent-sdk-server 的 createTool 入口(单例铁律)
|
|
2
|
+
import { createTool } from '@tbox.cn/app-agent-sdk-server';
|
|
3
3
|
import { z } from 'zod';
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, expect, it } from 'vitest';
|
|
2
|
-
import { loadAgentPromptConfig } from '@tbox.cn/app-sdk
|
|
2
|
+
import { loadAgentPromptConfig } from '@tbox.cn/app-agent-sdk-server';
|
|
3
3
|
import { existsSync } from 'node:fs';
|
|
4
4
|
import path from 'node:path';
|
|
5
5
|
import { fileURLToPath } from 'node:url';
|
|
@@ -11,14 +11,14 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
|
11
11
|
* W4 单一模板统一化双段语义:
|
|
12
12
|
* - 缺省出厂 = 空装配(config/ 无 agent.jsonc)→ loader 走 SDK 默认兜底单行(chat 形态零域广告);
|
|
13
13
|
* - mall 画像 = profiles/mall/config/agent.jsonc(--profile mall 经 --config-dir 通道注入)——
|
|
14
|
-
* 四章节/禁工具名/承接句/中立锚断言锚定画像资产文件(create 展开/
|
|
14
|
+
* 四章节/禁工具名/承接句/中立锚断言锚定画像资产文件(create 展开/stage mall 完整档消费)。
|
|
15
15
|
*
|
|
16
16
|
* 部署态让位(2026-09-10):--config-dir 注入真实厂商档(integrations.json root provider 为
|
|
17
17
|
* 真实厂商名而非 mock)时 agent.jsonc 为部署方品牌人设——中立锚仅守卫出厂/mock 态(mock 档
|
|
18
|
-
* 不注入 agent.jsonc,保持出厂中立)。
|
|
18
|
+
* 不注入 agent.jsonc,保持出厂中立)。stage 真实厂商档完整链依赖此让位。
|
|
19
19
|
*
|
|
20
20
|
* 装配态感知(2026-09-17 评审修复):第一段的 config/ 状态在生成应用是装配变量——mall 完整档
|
|
21
|
-
* 素材注入、support 自含 config(出厂在场)均使 agent.jsonc 在场,恒常量断言失配(
|
|
21
|
+
* 素材注入、support 自含 config(出厂在场)均使 agent.jsonc 在场,恒常量断言失配(stage
|
|
22
22
|
* 完整档 94/95 缺口)。用例改为形态感知:缺席 → 兜底断言(出厂守卫保持);在场 → 读文件断言。
|
|
23
23
|
*/
|
|
24
24
|
describe('agent.jsonc(兜底语义:空装配 → SDK 默认单行;装配态注入 → 读文件)', () => {
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// cards 字段运行期声明,registry 仅余 cardType 注册与 dataSchema 校验职责。
|
|
4
4
|
import { describe, it, expect } from 'vitest';
|
|
5
5
|
import { diagnosePlugins } from '@tbox.cn/agent-plugin/doctor';
|
|
6
|
-
import { createServerContext, createPluginIntegration } from '@tbox.cn/app-sdk
|
|
6
|
+
import { createServerContext, createPluginIntegration } from '@tbox.cn/app-agent-sdk-server';
|
|
7
7
|
import { registerAll } from '../src/modules.js';
|
|
8
8
|
|
|
9
9
|
describe('工具 / 卡片 registry 一致性(自注册闭环)', () => {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, expect, it } from 'vitest';
|
|
2
|
-
import { createServerContext } from '@tbox.cn/app-sdk
|
|
2
|
+
import { createServerContext } from '@tbox.cn/app-agent-sdk-server';
|
|
3
3
|
import type { RequestContext } from '@tbox.cn/app-contracts';
|
|
4
4
|
import { createAppIntentDispatcher } from '../src/intent-routes.js';
|
|
5
5
|
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
createEngineFromContext,
|
|
6
6
|
createInMemoryMemoryStore,
|
|
7
7
|
resolveMemoryStore,
|
|
8
|
-
} from '@tbox.cn/app-sdk
|
|
8
|
+
} from '@tbox.cn/app-agent-sdk-server';
|
|
9
9
|
import { registerAll } from '../src/modules.js';
|
|
10
10
|
import { translateTool } from '../src/tools/translate.js';
|
|
11
11
|
|
|
@@ -18,7 +18,7 @@ describe('tool runtime 宿主装配(自注册闭环)', () => {
|
|
|
18
18
|
loadPlugins: async () => ({ tools: {}, references: [] }),
|
|
19
19
|
});
|
|
20
20
|
|
|
21
|
-
//
|
|
21
|
+
// 缺省空装配:模块工具不存在,仅 app 级工具
|
|
22
22
|
expect(Object.keys(runtime.tools)).not.toEqual(
|
|
23
23
|
expect.arrayContaining(['getWeather']),
|
|
24
24
|
);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tbox.cn/app-template-agent",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
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"
|
|
@@ -32,11 +32,11 @@
|
|
|
32
32
|
"LICENSE"
|
|
33
33
|
],
|
|
34
34
|
"devDependencies": {
|
|
35
|
-
"@tbox.cn/app-sdk": "0.19.0",
|
|
36
35
|
"eslint": "9.39.5",
|
|
37
36
|
"typescript-eslint": "8.67.0",
|
|
38
37
|
"eslint-plugin-react-hooks": "5.2.0",
|
|
39
|
-
"vite": "6.4.3"
|
|
38
|
+
"vite": "6.4.3",
|
|
39
|
+
"@tbox.cn/app-sdk-server": "0.21.0"
|
|
40
40
|
},
|
|
41
41
|
"license": "MIT",
|
|
42
42
|
"publishConfig": {
|
|
@@ -27,13 +27,13 @@
|
|
|
27
27
|
"LICENSE"
|
|
28
28
|
],
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@tbox.cn/app-sdk": "catalog:",
|
|
31
30
|
"@tbox.cn/app-contracts": "catalog:",
|
|
32
31
|
"@phosphor-icons/react": "catalog:",
|
|
33
32
|
"antd-mobile": "catalog:",
|
|
34
33
|
"react-markdown": "catalog:",
|
|
35
34
|
"remark-gfm": "catalog:",
|
|
36
|
-
"zustand": "catalog:"
|
|
35
|
+
"zustand": "catalog:",
|
|
36
|
+
"@tbox.cn/app-agent-sdk-client": "catalog:"
|
|
37
37
|
},
|
|
38
38
|
"peerDependencies": {
|
|
39
39
|
"react": "catalog:",
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* - 域自持段(首屏数据/门禁/详情弹层/活动预热)经槽渲染函数自带——本页零域语义。
|
|
8
8
|
*/
|
|
9
9
|
import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
|
|
10
|
-
import { consumeAutoSendQuery, runAutoSend } from '@tbox.cn/app-sdk
|
|
10
|
+
import { consumeAutoSendQuery, runAutoSend } from '@tbox.cn/app-agent-sdk-client';
|
|
11
11
|
import { usePullDownHistory } from './hooks/use-pull-down-history';
|
|
12
12
|
import type { TboxCardPayload } from '@tbox.cn/app-contracts';
|
|
13
13
|
import { CardRenderer } from './components/CardRenderer';
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* - HELLO_ACK settings 水合:服务端单一真源(applyServerSettings;五键整组语义,禁部分水合)。
|
|
7
7
|
*/
|
|
8
8
|
import { create } from 'zustand';
|
|
9
|
-
import type { ChatUiSettings } from '@tbox.cn/app-sdk
|
|
9
|
+
import type { ChatUiSettings } from '@tbox.cn/app-agent-sdk-client';
|
|
10
10
|
|
|
11
11
|
export interface QuickCommand {
|
|
12
12
|
/** 纯文案;前导星标/图标由 QuickCommands 组件渲染,不要写进 label */
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { useEffect, useState, useSyncExternalStore } from 'react';
|
|
2
|
-
import { createLogger } from '@tbox.cn/app-sdk
|
|
2
|
+
import { createLogger } from '@tbox.cn/app-agent-sdk-client';
|
|
3
3
|
|
|
4
4
|
const ttsActionLogger = createLogger('tts');
|
|
5
5
|
import { Copy, SpeakerHigh, ThumbsDown, ThumbsUp } from '@phosphor-icons/react';
|
|
6
6
|
import { useChatStore } from '../../store-context';
|
|
7
7
|
import { useChatConfigStore } from '../../chat-config';
|
|
8
|
-
import { useFeedbackAdapter, useRefreshSession, useTTSAdapter } from '@tbox.cn/app-sdk
|
|
8
|
+
import { useFeedbackAdapter, useRefreshSession, useTTSAdapter } from '@tbox.cn/app-agent-sdk-client';
|
|
9
9
|
import type { ChatMessage } from '../../types';
|
|
10
10
|
import { copyText } from '../../utils/copyText';
|
|
11
11
|
import { toast } from '../../utils/toast';
|
|
@@ -58,7 +58,6 @@ export function ActionBar({ message }: { message: ChatMessage }) {
|
|
|
58
58
|
const refreshSession = useRefreshSession();
|
|
59
59
|
const tts = useTTSAdapter();
|
|
60
60
|
const enableTTS = useChatConfigStore((s) => s.enableTTS);
|
|
61
|
-
const conversationId = useChatStore((s) => s.conversationId);
|
|
62
61
|
const submitFeedback = useChatStore((s) => s.submitFeedback);
|
|
63
62
|
|
|
64
63
|
const [ttsState, setTtsState] = useState<'idle' | 'loading' | 'playing' | 'paused'>('idle');
|
|
@@ -151,7 +150,6 @@ export function ActionBar({ message }: { message: ChatMessage }) {
|
|
|
151
150
|
|
|
152
151
|
<DebugButton
|
|
153
152
|
requestId={message.requestId}
|
|
154
|
-
conversationId={conversationId ?? undefined}
|
|
155
153
|
messageId={message.id}
|
|
156
154
|
messageCreatedAt={new Date(message.createdAt).getTime()}
|
|
157
155
|
/>
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* - CardRenderer:聊天入口(组合层覆盖注册表 cards);
|
|
7
7
|
* - RawCardRenderer:原始形态(rawCards,无覆盖)——首页详情弹层 body 等防嵌套入口。
|
|
8
8
|
*/
|
|
9
|
-
import { CardRenderer as SdkCardRenderer } from '@tbox.cn/app-sdk
|
|
9
|
+
import { CardRenderer as SdkCardRenderer } from '@tbox.cn/app-agent-sdk-client';
|
|
10
10
|
import type { TboxCardPayload, UiAction } from '@tbox.cn/app-contracts';
|
|
11
11
|
import { useChatCards, useChatRawCards, useChatStore } from '../store-context';
|
|
12
12
|
|
|
@@ -8,7 +8,7 @@ const mocks = vi.hoisted(() => ({
|
|
|
8
8
|
interactionState: 'idle' as VoiceInteractionState,
|
|
9
9
|
}));
|
|
10
10
|
|
|
11
|
-
vi.mock('@tbox.cn/app-sdk
|
|
11
|
+
vi.mock('@tbox.cn/app-agent-sdk-client', () => ({
|
|
12
12
|
isInAlipayShell: () => false,
|
|
13
13
|
useASRAdapter: () => undefined,
|
|
14
14
|
}));
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useEffect, useRef, useState } from 'react';
|
|
2
2
|
import { useMediaUpload } from '../../hooks/useMediaUpload';
|
|
3
|
-
import { useASRAdapter, isInAlipayShell } from '@tbox.cn/app-sdk
|
|
3
|
+
import { useASRAdapter, isInAlipayShell } from '@tbox.cn/app-agent-sdk-client';
|
|
4
4
|
import { useChatConfigStore } from '../../chat-config';
|
|
5
5
|
|
|
6
6
|
import type { ChatInputMessage, InputMethod } from '../../types';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
2
|
-
import type { IASRAdapter } from '@tbox.cn/app-sdk
|
|
3
|
-
import { useRefreshSession } from '@tbox.cn/app-sdk
|
|
2
|
+
import type { IASRAdapter } from '@tbox.cn/app-agent-sdk-client';
|
|
3
|
+
import { useRefreshSession } from '@tbox.cn/app-agent-sdk-client';
|
|
4
4
|
import { isSessionExpiredError } from '../../../utils/session-error';
|
|
5
5
|
import { toast } from '../../../utils/toast';
|
|
6
6
|
import {
|
|
@@ -9,7 +9,7 @@ import ToolCallBlock from '../../components/ToolCallBlock';
|
|
|
9
9
|
import { ActionBar, CopyButton, getMessageCopyText } from '../../components/ActionBar';
|
|
10
10
|
import { DebugButton } from '../../components/ActionBar/DebugButton';
|
|
11
11
|
import { CardRenderer } from '../CardRenderer';
|
|
12
|
-
import { CardCarousel } from '@tbox.cn/app-sdk
|
|
12
|
+
import { CardCarousel } from '@tbox.cn/app-agent-sdk-client';
|
|
13
13
|
import { useChatStore, useInlineCardFilter } from '../../store-context';
|
|
14
14
|
import { copyText } from '../../utils/copyText';
|
|
15
15
|
import { toast } from '../../utils/toast';
|
|
@@ -20,7 +20,6 @@ const TBOX_FILE_URL = 'https://mdn.alipayobjects.com/tcmarket/afts/file/';
|
|
|
20
20
|
/** 消息气泡(对齐原模板):meta + 思考/工具/卡片 + 气泡 + 媒体 + 操作栏。 */
|
|
21
21
|
export function MessageBubble({ message }: { message: ChatMessage }) {
|
|
22
22
|
const cardsByMessageId = useChatStore((s) => s.cardsByMessageId);
|
|
23
|
-
const conversationId = useChatStore((s) => s.conversationId);
|
|
24
23
|
// 018 tool-debug:服务端旗标单源(HELLO_ACK;无 URL 逃逸——数据面信任锚点在服务端)
|
|
25
24
|
const toolDebug = useChatStore((s) => s.helloAck?.toolDebug === true);
|
|
26
25
|
const isUser = message.role === 'user';
|
|
@@ -164,7 +163,6 @@ export function MessageBubble({ message }: { message: ChatMessage }) {
|
|
|
164
163
|
{message.requestId && (
|
|
165
164
|
<DebugButton
|
|
166
165
|
requestId={message.requestId}
|
|
167
|
-
conversationId={conversationId ?? undefined}
|
|
168
166
|
messageId={message.id}
|
|
169
167
|
messageCreatedAt={new Date(message.createdAt).getTime()}
|
|
170
168
|
/>
|
|
@@ -8,7 +8,7 @@ import { createRoot } from 'react-dom/client';
|
|
|
8
8
|
import { flushSync } from 'react-dom';
|
|
9
9
|
import type { ReactNode } from 'react';
|
|
10
10
|
import { create } from 'zustand';
|
|
11
|
-
import type { CoreChatStore } from '@tbox.cn/app-sdk
|
|
11
|
+
import type { CoreChatStore } from '@tbox.cn/app-agent-sdk-client';
|
|
12
12
|
import { configureChatConfigDefaults, useChatConfigStore } from '../../chat-config';
|
|
13
13
|
import { KitChatProvider } from '../../store-context';
|
|
14
14
|
import { QuickCommands } from './index';
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
PRE_TOOL_CALL_NAME,
|
|
10
10
|
SKILL_TOOL_CALL_NAME,
|
|
11
11
|
} from '@tbox.cn/app-contracts';
|
|
12
|
-
import type { ToolCallInfo } from '@tbox.cn/app-sdk
|
|
12
|
+
import type { ToolCallInfo } from '@tbox.cn/app-agent-sdk-client';
|
|
13
13
|
import {
|
|
14
14
|
buildSummaryText,
|
|
15
15
|
deriveSummary,
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* debug 门控在渲染层(组件 debug prop)——视图模型保持纯数据投影,不感知环境。
|
|
6
6
|
*/
|
|
7
7
|
import { describeToolCall } from '../../utils/tool-call-display';
|
|
8
|
-
import type { ToolCallInfo } from '@tbox.cn/app-sdk
|
|
8
|
+
import type { ToolCallInfo } from '@tbox.cn/app-agent-sdk-client';
|
|
9
9
|
import {
|
|
10
10
|
MEMORY_TOOL_CALL_NAME,
|
|
11
11
|
parseMemoryToolCallArgs,
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { createLogger } from '@tbox.cn/app-sdk
|
|
1
|
+
import { createLogger } from '@tbox.cn/app-agent-sdk-client';
|
|
2
2
|
|
|
3
3
|
const mediaLogger = createLogger('media');
|
|
4
4
|
|
|
5
5
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
6
|
-
import { useUploadAdapter, useRefreshSession, chooseImage, chooseVideo } from '@tbox.cn/app-sdk
|
|
6
|
+
import { useUploadAdapter, useRefreshSession, chooseImage, chooseVideo } from '@tbox.cn/app-agent-sdk-client';
|
|
7
7
|
|
|
8
8
|
import { isSessionExpiredError } from '../utils/session-error';
|
|
9
9
|
import { toast } from '../utils/toast';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useEffect } from 'react';
|
|
2
|
-
import type { CoreChatState } from '@tbox.cn/app-sdk
|
|
2
|
+
import type { CoreChatState } from '@tbox.cn/app-agent-sdk-client';
|
|
3
3
|
import { useChatStoreApi } from '../store-context';
|
|
4
|
-
import { useTTSAdapter } from '@tbox.cn/app-sdk
|
|
4
|
+
import { useTTSAdapter } from '@tbox.cn/app-agent-sdk-client';
|
|
5
5
|
|
|
6
6
|
const FLUSH_MS = 300; // 累积 delta 后批量送,避免过多 WS 消息
|
|
7
7
|
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import { createContext, useContext, useMemo, type ReactNode } from 'react';
|
|
12
12
|
import type { CardComponent, TboxCardPayload } from '@tbox.cn/app-contracts';
|
|
13
|
-
import type { ClientSlotRegistry, CoreChatState, CoreChatStore } from '@tbox.cn/app-sdk
|
|
13
|
+
import type { ClientSlotRegistry, CoreChatState, CoreChatStore } from '@tbox.cn/app-agent-sdk-client';
|
|
14
14
|
|
|
15
15
|
export interface KitChatContextValue {
|
|
16
16
|
/** 应用注入的 chat store(zustand 绑定 hook + API) */
|