@tbox.cn/app-template-agent 0.7.5 → 0.8.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/.gitignore +5 -0
- package/.tbox/app.json +9 -1
- package/AGENTS.md +12 -4
- package/ENV.md +102 -17
- package/README.md +36 -34
- package/apps/client/VISUAL_RESTORE.md +11 -11
- package/apps/client/index.html +3 -1
- package/apps/client/package.json +9 -8
- package/apps/client/src/business/App.tsx +4 -4
- package/apps/client/src/business/README.md +5 -11
- package/apps/client/src/cards/registry.ts +23 -8
- package/apps/client/src/main.tsx +36 -2
- package/apps/client/src/modules.ts +7 -4
- package/apps/client/src/pages/index/index.tsx +18 -162
- package/apps/client/src/platform/AgentChatApp.tsx +3 -3
- package/apps/client/src/platform/agent-runtime.ts +5 -0
- package/apps/client/src/store/chat.ts +47 -185
- package/apps/client/src/test/setup.ts +7 -0
- package/apps/client/vite.config.ts +16 -1
- package/apps/server/package.json +0 -1
- package/apps/server/src/app-tools.ts +2 -1
- package/apps/server/src/app.ts +178 -110
- package/apps/server/src/config/integration.ts +2 -6
- package/apps/server/src/dev.ts +0 -1
- package/apps/server/src/intent-routes.ts +3 -3
- package/apps/server/src/modules.ts +4 -4
- package/apps/server/src/pre-tools.ts +4 -3
- package/apps/server/tests/agent-prompt.test.ts +81 -0
- package/apps/server/tests/cards-registry.test.ts +1 -3
- package/apps/server/tests/deployment-loader.test.ts +35 -56
- package/apps/server/tests/tool-runtime.test.ts +25 -61
- package/package.json +5 -4
- package/packages/agent-ui-kit/LICENSE +21 -0
- package/packages/agent-ui-kit/README.md +17 -0
- package/packages/agent-ui-kit/package.json +58 -0
- package/packages/agent-ui-kit/src/ChatPage.less +62 -0
- package/packages/agent-ui-kit/src/ChatPage.tsx +305 -0
- package/packages/agent-ui-kit/src/chat-config.test.ts +82 -0
- package/packages/agent-ui-kit/src/chat-config.ts +62 -0
- package/{apps/client → packages/agent-ui-kit}/src/components/ActionBar/DebugButton.tsx +2 -2
- package/{apps/client → packages/agent-ui-kit}/src/components/ActionBar/index.less +19 -16
- package/{apps/client → packages/agent-ui-kit}/src/components/ActionBar/index.tsx +10 -13
- package/packages/agent-ui-kit/src/components/CardRenderer.tsx +36 -0
- package/packages/agent-ui-kit/src/components/ChatHeader/index.less +148 -0
- package/packages/agent-ui-kit/src/components/ChatHeader/index.test.tsx +74 -0
- package/{apps/client → packages/agent-ui-kit}/src/components/ChatHeader/index.tsx +27 -15
- package/{apps/client → packages/agent-ui-kit}/src/components/ChatInput/index.less +47 -39
- package/packages/agent-ui-kit/src/components/ChatInput/index.test.tsx +156 -0
- package/{apps/client → packages/agent-ui-kit}/src/components/ChatInput/index.tsx +13 -4
- package/{apps/client → packages/agent-ui-kit}/src/components/ChatInput/voice/useVoicePress.ts +2 -2
- package/packages/agent-ui-kit/src/components/HistoryEntry/index.less +49 -0
- package/packages/agent-ui-kit/src/components/HistoryEntry/index.tsx +42 -0
- package/{apps/client → packages/agent-ui-kit}/src/components/MediaList/index.less +3 -3
- package/{apps/client → packages/agent-ui-kit}/src/components/MediaList/index.tsx +6 -6
- package/{apps/client → packages/agent-ui-kit}/src/components/MessageBubble/index.less +25 -20
- package/packages/agent-ui-kit/src/components/MessageBubble/index.test.tsx +112 -0
- package/{apps/client → packages/agent-ui-kit}/src/components/MessageBubble/index.tsx +22 -15
- package/{apps/client → packages/agent-ui-kit}/src/components/PullDownIndicator/index.less +2 -2
- package/{apps/client → packages/agent-ui-kit}/src/components/PullDownIndicator/index.tsx +2 -2
- package/packages/agent-ui-kit/src/components/QuickCommands/index.less +63 -0
- package/packages/agent-ui-kit/src/components/QuickCommands/index.test.tsx +99 -0
- package/packages/agent-ui-kit/src/components/QuickCommands/index.tsx +52 -0
- package/{apps/client → packages/agent-ui-kit}/src/components/ScrollToBottomButton/index.less +1 -1
- package/packages/agent-ui-kit/src/components/ToolCallBlock/detail.test.ts +346 -0
- package/packages/agent-ui-kit/src/components/ToolCallBlock/detail.ts +204 -0
- package/packages/agent-ui-kit/src/components/ToolCallBlock/index.less +312 -0
- package/packages/agent-ui-kit/src/components/ToolCallBlock/index.test.tsx +261 -0
- package/packages/agent-ui-kit/src/components/ToolCallBlock/index.tsx +212 -0
- package/packages/agent-ui-kit/src/components/ToolCallBlock/titles.ts +102 -0
- package/packages/agent-ui-kit/src/hooks/use-drag-gesture.test.ts +66 -0
- package/packages/agent-ui-kit/src/hooks/use-drag-gesture.ts +129 -0
- package/packages/agent-ui-kit/src/hooks/use-pull-down-history.ts +241 -0
- package/packages/agent-ui-kit/src/hooks/use-pull-down-wheel-native.test.ts +64 -0
- package/{apps/client → packages/agent-ui-kit}/src/hooks/useMediaUpload.ts +3 -3
- package/{apps/client → packages/agent-ui-kit}/src/hooks/useTTSAutoPlay.ts +7 -5
- package/packages/agent-ui-kit/src/index.ts +69 -0
- package/packages/agent-ui-kit/src/store-context.tsx +92 -0
- package/packages/agent-ui-kit/src/test/setup.ts +7 -0
- package/packages/agent-ui-kit/src/theme/contract.json +72 -0
- package/packages/agent-ui-kit/src/theme/global.less +99 -0
- package/packages/agent-ui-kit/src/theme/motion.less +19 -0
- package/packages/agent-ui-kit/src/theme/theme-contract.test.ts +69 -0
- package/packages/agent-ui-kit/src/theme/theme.ts +17 -0
- package/packages/agent-ui-kit/src/theme/tokens.less +79 -0
- package/packages/agent-ui-kit/src/utils/haptics.test.ts +51 -0
- package/packages/agent-ui-kit/src/utils/haptics.ts +44 -0
- package/packages/agent-ui-kit/src/utils/pull-down-machine.test.ts +188 -0
- package/packages/agent-ui-kit/src/utils/pull-down-machine.ts +157 -0
- package/packages/agent-ui-kit/src/utils/tool-call-display.test.ts +240 -0
- package/packages/agent-ui-kit/src/utils/tool-call-display.ts +146 -0
- package/packages/agent-ui-kit/src/vite-env.d.ts +1 -0
- package/packages/agent-ui-kit/tsconfig.json +8 -0
- package/packages/agent-ui-kit/vitest.config.ts +7 -0
- package/pnpm-lock.template.yaml +177 -83
- package/pnpm-workspace.template.yaml +12 -4
- package/profiles/mall/config/agent.jsonc +33 -0
- package/profiles/mall/config/chat.json +21 -0
- package/profiles/mall/config/knowledge.json +5 -0
- package/profiles/mall/config/llm_provider.json +5 -0
- package/profiles/mall/config/plugins.json +3 -0
- package/profiles/mall.json +16 -0
- package/scripts/check-workspace.mjs +3 -2
- package/apps/client/assets/copy@2x.png +0 -0
- package/apps/client/assets/debug.png +0 -0
- package/apps/client/assets/dislike@2x.png +0 -0
- package/apps/client/assets/like@2x.png +0 -0
- package/apps/client/assets/speaker@2x.png +0 -0
- package/apps/client/src/cards/CardRenderer.tsx +0 -20
- package/apps/client/src/components/ChatHeader/index.less +0 -104
- package/apps/client/src/components/ErrorBoundary.tsx +0 -2
- package/apps/client/src/components/QuickCommands/index.less +0 -48
- package/apps/client/src/components/QuickCommands/index.tsx +0 -29
- package/apps/client/src/components/ToolCallBlock/index.less +0 -131
- package/apps/client/src/components/ToolCallBlock/index.tsx +0 -125
- package/apps/client/src/examples/tourism/TourismLanding.tsx +0 -96
- package/apps/client/src/examples/tourism/index.less +0 -192
- package/apps/client/src/pages/index/index.less +0 -43
- package/apps/client/src/store/chat-config.ts +0 -40
- package/apps/client/src/styles/global.less +0 -60
- package/apps/client/src/styles/tokens.less +0 -60
- package/apps/server/src/config/deployment.ts +0 -47
- package/packages/module-weather/package.json +0 -36
- package/packages/module-weather/skills/weather-guide/SKILL.md +0 -22
- package/packages/module-weather/skills/weather-guide/references/dressing-tips.md +0 -5
- package/packages/module-weather/src/client/cards/weather/index.less +0 -22
- package/packages/module-weather/src/client/cards/weather/index.tsx +0 -14
- package/packages/module-weather/src/client/index.ts +0 -19
- package/packages/module-weather/src/index.ts +0 -2
- package/packages/module-weather/src/server/cards/weather/meta.ts +0 -27
- package/packages/module-weather/src/server/index.ts +0 -45
- package/packages/module-weather/src/server/pre-tools.ts +0 -20
- package/packages/module-weather/src/server/tool.ts +0 -29
- package/packages/module-weather/tbox.module.json +0 -27
- package/packages/module-weather/tsconfig.json +0 -14
- /package/{apps/client → packages/agent-ui-kit}/assets/keyboard-circle.svg +0 -0
- /package/{apps/client → packages/agent-ui-kit}/assets/more-circle.svg +0 -0
- /package/{apps/client → packages/agent-ui-kit}/assets/new-chat.svg +0 -0
- /package/{apps/client → packages/agent-ui-kit}/assets/quick-command-star.svg +0 -0
- /package/{apps/client → packages/agent-ui-kit}/assets/send-gradient.svg +0 -0
- /package/{apps/client → packages/agent-ui-kit}/assets/stop@2x.png +0 -0
- /package/{apps/client → packages/agent-ui-kit}/assets/voice-circle.svg +0 -0
- /package/{apps/client → packages/agent-ui-kit}/src/components/ChatInput/voice/VoicePressField.tsx +0 -0
- /package/{apps/client → packages/agent-ui-kit}/src/components/ChatInput/voice/VoiceRecordingOverlay.tsx +0 -0
- /package/{apps/client → packages/agent-ui-kit}/src/components/ChatInput/voice/machine.ts +0 -0
- /package/{apps/client → packages/agent-ui-kit}/src/components/ReasoningBlock/index.less +0 -0
- /package/{apps/client → packages/agent-ui-kit}/src/components/ReasoningBlock/index.tsx +0 -0
- /package/{apps/client → packages/agent-ui-kit}/src/components/ScrollToBottomButton/index.tsx +0 -0
- /package/{apps/client/src/types/chat.ts → packages/agent-ui-kit/src/types.ts} +0 -0
- /package/{apps/client → packages/agent-ui-kit}/src/utils/copyText.ts +0 -0
- /package/{apps/client → packages/agent-ui-kit}/src/utils/imagePreview.ts +0 -0
- /package/{apps/client → packages/agent-ui-kit}/src/utils/session-error.ts +0 -0
- /package/{apps/client → packages/agent-ui-kit}/src/utils/toast.ts +0 -0
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* integrations
|
|
3
|
-
*
|
|
4
|
-
*
|
|
2
|
+
* integrations 装载链单测(W3-1 收窄:控制平面投影/域装配段随 mall 语义迁
|
|
3
|
+
* modules/module-mall-core/tests/assembly.test.ts——本文件只测模板装载壳)。
|
|
4
|
+
* 覆盖:strict 校验 fail-fast / 占位展开(env 通道)/ defaultInstanceId 引用完整性 /
|
|
5
|
+
* stale 防线(deployments/development.json 含 malls → error 迁移指引)。
|
|
5
6
|
*/
|
|
6
7
|
import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from 'node:fs';
|
|
7
8
|
import { tmpdir } from 'node:os';
|
|
8
9
|
import { join } from 'node:path';
|
|
9
10
|
import { afterAll, describe, expect, it } from 'vitest';
|
|
10
11
|
import { loadIntegrations, assertNoStaleDeploymentControlPlane } from '../src/config/integration.js';
|
|
11
|
-
import { deploymentFromIntegrations, buildDefaultMallContext } from '../src/config/deployment.js';
|
|
12
12
|
|
|
13
13
|
const dir = mkdtempSync(join(tmpdir(), 'tbox-deploy-loader-'));
|
|
14
14
|
afterAll(() => rmSync(dir, { recursive: true, force: true }));
|
|
@@ -19,6 +19,7 @@ function writeConfig(name: string, data: unknown): string {
|
|
|
19
19
|
return p;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
+
/** 模拟 real-env 素材形态:root instances 注册表 + defaultInstanceId + services */
|
|
22
23
|
const fullIntegrations = {
|
|
23
24
|
provider: 'acme',
|
|
24
25
|
instances: [
|
|
@@ -36,39 +37,29 @@ const fullIntegrations = {
|
|
|
36
37
|
services: { 'member.account': {} },
|
|
37
38
|
};
|
|
38
39
|
|
|
39
|
-
describe('loadIntegrations
|
|
40
|
-
it('
|
|
40
|
+
describe('loadIntegrations:装载链(strict + 占位展开 + 缺席语义)', () => {
|
|
41
|
+
it('全量素材可载入(config 停留原样;投影消费方 = module-mall-core)', () => {
|
|
41
42
|
const loaded = loadIntegrations(writeConfig('full.json', fullIntegrations));
|
|
42
|
-
expect(loaded?.
|
|
43
|
-
|
|
44
|
-
name: '示例商场',
|
|
45
|
-
miniAppId: 'demo-app',
|
|
46
|
-
contactPhone: '0571-88888888',
|
|
47
|
-
location: { lat: 30.2741, lon: 120.1551, address: '湖滨示范点' },
|
|
48
|
-
});
|
|
49
|
-
expect(loaded?.controlPlane.defaultMallId).toBe('mall-demo');
|
|
43
|
+
expect(loaded?.config.defaultInstanceId).toBe('mall-demo');
|
|
44
|
+
expect(loaded?.source.endsWith('full.json')).toBe(true);
|
|
50
45
|
});
|
|
51
46
|
|
|
52
|
-
it('
|
|
47
|
+
it('attributes 严格校验归投影(W3-1:loader 不过滤——拼错键由 mall-core register 期 fail-fast)', () => {
|
|
53
48
|
const p = writeConfig('typo-attr.json', {
|
|
54
49
|
instances: [{ id: 'm1', name: 'x', attributes: { miniAppid: 'typo' } }],
|
|
55
50
|
services: {},
|
|
56
51
|
});
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
it('无参考表 → 空平面;defaultInstanceId 独立在场 = 动态默认(env 注入形态)', () => {
|
|
61
|
-
const loaded = loadIntegrations(writeConfig('no-table.json', { provider: 'globex', defaultInstanceId: '42020300520', services: {} }));
|
|
62
|
-
expect(loaded?.controlPlane.malls).toEqual([]);
|
|
63
|
-
expect(loaded?.controlPlane.defaultMallId).toBe('42020300520');
|
|
52
|
+
// 装载壳只做展开+parse;投影(含允许键清单 strict)在 module-mall-core 装配期
|
|
53
|
+
// (module tests/assembly.test.ts 覆盖 fail-fast 语义——启动链同点报错)
|
|
54
|
+
expect(loadIntegrations(p)?.config.instances?.length).toBe(1);
|
|
64
55
|
});
|
|
65
56
|
|
|
66
|
-
it('defaultInstanceId 占位 ${DEFAULT_MALL_ID} → 展开后载入;缺 env fail-fast', () => {
|
|
57
|
+
it('defaultInstanceId 占位 ${DEFAULT_MALL_ID} → loader 展开后载入;缺 env fail-fast', () => {
|
|
67
58
|
const p = writeConfig('env-placeholder.json', { defaultInstanceId: '${DEFAULT_MALL_ID}', services: {} });
|
|
68
59
|
const saved = process.env.DEFAULT_MALL_ID;
|
|
69
60
|
process.env.DEFAULT_MALL_ID = '1102588';
|
|
70
61
|
try {
|
|
71
|
-
expect(loadIntegrations(p)?.
|
|
62
|
+
expect(loadIntegrations(p)?.config.defaultInstanceId).toBe('1102588');
|
|
72
63
|
delete process.env.DEFAULT_MALL_ID;
|
|
73
64
|
expect(() => loadIntegrations(p)).toThrow(/DEFAULT_MALL_ID/);
|
|
74
65
|
} finally {
|
|
@@ -76,6 +67,19 @@ describe('loadIntegrations:投影穿透', () => {
|
|
|
76
67
|
else process.env.DEFAULT_MALL_ID = saved;
|
|
77
68
|
}
|
|
78
69
|
});
|
|
70
|
+
|
|
71
|
+
it('defaultInstanceId ∉ instances ids → zod 拒载(SDK 单源防线)', () => {
|
|
72
|
+
const p = writeConfig('bad-default.json', {
|
|
73
|
+
instances: [{ id: 'm1', name: 'x' }],
|
|
74
|
+
defaultInstanceId: '99999',
|
|
75
|
+
services: {},
|
|
76
|
+
});
|
|
77
|
+
expect(() => loadIntegrations(p)).toThrow(/defaultInstanceId/);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('文件缺席 → undefined(槽位解析不启用)', () => {
|
|
81
|
+
expect(loadIntegrations(join(dir, 'absent.json'))).toBeUndefined();
|
|
82
|
+
});
|
|
79
83
|
});
|
|
80
84
|
|
|
81
85
|
describe('stale 防线(v4:deployments/development.json 含 malls → error 迁移指引)', () => {
|
|
@@ -103,38 +107,13 @@ describe('stale 防线(v4:deployments/development.json 含 malls → error
|
|
|
103
107
|
rmSync(root, { recursive: true, force: true });
|
|
104
108
|
}
|
|
105
109
|
});
|
|
106
|
-
});
|
|
107
110
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
mall: { mallId: 'mall-demo', miniAppId: 'demo-app' },
|
|
116
|
-
});
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
it('双缺 miniAppId → mallId-only 注入(v4:不再 warn-refuse 静默失效)', () => {
|
|
120
|
-
const loaded = loadIntegrations(writeConfig('ctx-nomini.json', { defaultInstanceId: 'm9', services: {} }))!;
|
|
121
|
-
expect(buildDefaultMallContext(loaded.controlPlane)).toEqual({ mall: { mallId: 'm9' } });
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
it('无 defaultMallId → undefined(不兜底)', () => {
|
|
125
|
-
const loaded = loadIntegrations(writeConfig('ctx-nodefault.json', { services: {} }))!;
|
|
126
|
-
expect(buildDefaultMallContext(loaded.controlPlane)).toBeUndefined();
|
|
127
|
-
});
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
describe('deploymentFromIntegrations:装配活性', () => {
|
|
131
|
-
it('assembly 三函数派生自投影控制平面', () => {
|
|
132
|
-
const loaded = loadIntegrations(writeConfig('asm.json', fullIntegrations))!;
|
|
133
|
-
const d = deploymentFromIntegrations(loaded);
|
|
134
|
-
expect(d.controlPlane).toBe(loaded.controlPlane);
|
|
135
|
-
expect(d.assembly.validateScope({ mall: { mallId: 'mall-demo' } })).toBe(true);
|
|
136
|
-
expect(d.assembly.validateScope({ mall: { miniAppId: 'a' } })).toBe(false);
|
|
137
|
-
expect(d.assembly.extractScopeKey({ identity: { userId: 'u', source: 'external' }, attributes: { mall: { mallId: 'mall-demo' } } })).toBe('mall-demo');
|
|
138
|
-
expect(d.assembly.buildScope({ mall: { mallId: 'mall-demo' } })).toEqual({ mallId: 'mall-demo' });
|
|
111
|
+
it('文件缺席 → 不阻断', () => {
|
|
112
|
+
const root = mkdtempSync(join(tmpdir(), 'tbox-stale-absent-'));
|
|
113
|
+
try {
|
|
114
|
+
expect(() => assertNoStaleDeploymentControlPlane(root)).not.toThrow();
|
|
115
|
+
} finally {
|
|
116
|
+
rmSync(root, { recursive: true, force: true });
|
|
117
|
+
}
|
|
139
118
|
});
|
|
140
119
|
});
|
|
@@ -10,7 +10,7 @@ import { registerAll } from '../src/modules.js';
|
|
|
10
10
|
import { translateTool } from '../src/tools/translate.js';
|
|
11
11
|
|
|
12
12
|
describe('tool runtime 宿主装配(自注册闭环)', () => {
|
|
13
|
-
it('
|
|
13
|
+
it('空装配(mall 模板):无模块工具,app 级工具正常注册', async () => {
|
|
14
14
|
const ctx = createServerContext();
|
|
15
15
|
await registerAll(ctx);
|
|
16
16
|
|
|
@@ -18,31 +18,13 @@ describe('tool runtime 宿主装配(自注册闭环)', () => {
|
|
|
18
18
|
loadPlugins: async () => ({ tools: {}, references: [] }),
|
|
19
19
|
});
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
// mall 模板空装配:模块工具(如 weather 系)不存在,仅 app 级工具
|
|
22
|
+
expect(Object.keys(runtime.tools)).not.toEqual(
|
|
22
23
|
expect.arrayContaining(['getWeather']),
|
|
23
24
|
);
|
|
24
25
|
});
|
|
25
26
|
|
|
26
|
-
it('
|
|
27
|
-
const ctx = createServerContext();
|
|
28
|
-
await registerAll(ctx);
|
|
29
|
-
|
|
30
|
-
const runtime = await createSdkToolRuntime(ctx, {
|
|
31
|
-
loadPlugins: async () => ({ tools: {}, references: [] }),
|
|
32
|
-
});
|
|
33
|
-
const weather = runtime.tools.getWeather as unknown as {
|
|
34
|
-
execute: (input: { city: string }, context: unknown) => Promise<Record<string, unknown>>;
|
|
35
|
-
};
|
|
36
|
-
const out = await weather.execute({ city: '杭州' }, {} as never);
|
|
37
|
-
// 顶层答话事实
|
|
38
|
-
expect(out).toMatchObject({ city: '杭州', temp: expect.any(Number), weather: expect.any(String) });
|
|
39
|
-
// cards 出卡声明(capture 前原始形态:data = 顶层事实本体,不含 cards 键自身)
|
|
40
|
-
// W7 note 契约:主体+关键事实(城市/天气/温度)
|
|
41
|
-
const { cards, ...facts } = out;
|
|
42
|
-
expect(cards).toEqual([{ cardType: 'weather', data: facts, note: `杭州 ${facts.weather} ${facts.temp}℃` }]);
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
it('未注册的 tool 不进运行时工具集(仅作为模型上下文面之外)', async () => {
|
|
27
|
+
it('未注册的 tool 不进运行时工具集(v2:无 cardResolver——出卡由工具出参 cards 运行期声明)', async () => {
|
|
46
28
|
const ctx = createServerContext();
|
|
47
29
|
await registerAll(ctx);
|
|
48
30
|
|
|
@@ -81,45 +63,30 @@ describe('tool runtime 宿主装配(自注册闭环)', () => {
|
|
|
81
63
|
});
|
|
82
64
|
});
|
|
83
65
|
|
|
84
|
-
describe('长期记忆装配(017
|
|
66
|
+
describe('长期记忆装配(017:mall 域默认 inmemory + mallId 隔离 scope)', () => {
|
|
85
67
|
it('resolveMemoryStore 缺省 → inmemory(默认开启)', () => {
|
|
86
68
|
const m = resolveMemoryStore({});
|
|
87
69
|
expect(m.enabled).toBe(true);
|
|
88
70
|
expect(m.mode).toBe('inmemory');
|
|
89
71
|
expect(m.store).toBeDefined();
|
|
90
|
-
expect(m.store!.capabilities).toBeUndefined(); // 缺省全真
|
|
91
72
|
});
|
|
92
73
|
|
|
93
|
-
it('resolveMemoryStore off → 关闭(enabled=false
|
|
74
|
+
it('resolveMemoryStore off → 关闭(enabled=false,路由面与工具零装配)', () => {
|
|
94
75
|
const m = resolveMemoryStore({ store: 'off' });
|
|
95
76
|
expect(m.enabled).toBe(false);
|
|
96
77
|
expect(m.mode).toBe('off');
|
|
97
78
|
expect(m.store).toBeUndefined();
|
|
98
79
|
});
|
|
99
80
|
|
|
100
|
-
it('resolveMemoryStore knowledge
|
|
101
|
-
|
|
102
|
-
expect(
|
|
103
|
-
expect(m.mode).toBe('inmemory');
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
it('resolveMemoryStore knowledge 三件套齐备 → knowledge 模式(2026-09-01 翻转:caps 缺省全 true——平台已发布生产)', () => {
|
|
81
|
+
it('resolveMemoryStore knowledge 三缺一回退;齐备 → knowledge(caps 缺省全 true——2026-09-01 翻转)', () => {
|
|
82
|
+
expect(resolveMemoryStore({ store: 'knowledge' }).mode).toBe('inmemory');
|
|
83
|
+
expect(resolveMemoryStore({ store: 'knowledge', kbId: 'kb-1', apiKey: 'k' }).mode).toBe('inmemory');
|
|
107
84
|
const m = resolveMemoryStore({ store: 'knowledge', kbId: 'kb-1', kbDocId: 'doc-1', apiKey: 'k' });
|
|
108
85
|
expect(m.mode).toBe('knowledge');
|
|
109
86
|
expect(m.store!.capabilities).toEqual({ save: true, search: true, list: true, delete: true });
|
|
110
87
|
});
|
|
111
88
|
|
|
112
|
-
it('
|
|
113
|
-
const m = resolveMemoryStore({ store: 'knowledge', kbId: 'kb-1', apiKey: 'k' });
|
|
114
|
-
expect(m.mode).toBe('inmemory');
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
it('resolveMemoryStore 非法值 → warn 回退 inmemory', () => {
|
|
118
|
-
const m = resolveMemoryStore({ store: 'bogus' });
|
|
119
|
-
expect(m.mode).toBe('inmemory');
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
it('装配态(inmemory)→ 引擎装配链路无异常(chat 完成 + 本地 skills 不受影响)', async () => {
|
|
89
|
+
it('装配态(inmemory)→ 引擎装配链路无异常 + 本地 skills 不受影响', async () => {
|
|
123
90
|
const ctx = createServerContext();
|
|
124
91
|
await registerAll(ctx);
|
|
125
92
|
const engine = await createEngineFromContext(ctx, {
|
|
@@ -127,25 +94,22 @@ describe('长期记忆装配(017:默认 inmemory 开启 + off 逃生舱)',
|
|
|
127
94
|
model: {} as never,
|
|
128
95
|
memory: { store: createInMemoryMemoryStore() },
|
|
129
96
|
});
|
|
130
|
-
// 触发一轮 chat 使装配链路完整执行(无 runCtx → 匿名 → 零 recall
|
|
131
|
-
|
|
132
|
-
//
|
|
133
|
-
|
|
97
|
+
// 触发一轮 chat 使装配链路完整执行(无 runCtx → 匿名 → 零 recall)。
|
|
98
|
+
// skills/preTools 面不做形状断言:模板源空装配为 [],生成应用(module add 后)非空——
|
|
99
|
+
// 属装配环境差异而非记忆特性;本用例只锁记忆装配链路无异常(chat 完成即通过)。
|
|
100
|
+
await engine.chat('t-mem-mall', 'hi', () => {});
|
|
134
101
|
});
|
|
135
102
|
|
|
136
|
-
it('
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
const
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
{
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
);
|
|
148
|
-
await engine.chat('t-mem-off', 'hi', () => {});
|
|
149
|
-
expect(m.enabled).toBe(false);
|
|
103
|
+
it('mall 域 resolveScope 语义:attributes.mall → { mallId };无 mall → undefined(用户级全局)', () => {
|
|
104
|
+
// resolveScope 闭包形态对齐模板装配(buildScope 单点);此处按语义直测:
|
|
105
|
+
// 模板内 resolveScope = buildScope(attributes) 取 mallId 单键
|
|
106
|
+
const resolveScope = (attributes: Record<string, unknown>) => {
|
|
107
|
+
const raw = attributes?.mall as { mallId?: unknown } | undefined;
|
|
108
|
+
const mallId = typeof raw?.mallId === 'string' && raw.mallId ? raw.mallId : undefined;
|
|
109
|
+
return mallId ? { mallId } : undefined;
|
|
110
|
+
};
|
|
111
|
+
expect(resolveScope({ mall: { mallId: 'mall-demo', miniAppId: 'demo-app' } })).toEqual({ mallId: 'mall-demo' });
|
|
112
|
+
expect(resolveScope({})).toBeUndefined();
|
|
113
|
+
expect(resolveScope({ mall: { mallId: '' } })).toBeUndefined();
|
|
150
114
|
});
|
|
151
115
|
});
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tbox.cn/app-template-agent",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "tbox AI Agent 全栈模板(多包 pnpm workspace):apps/client + apps/server
|
|
3
|
+
"version": "0.8.0",
|
|
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"
|
|
7
7
|
},
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
"!apps/**/node_modules",
|
|
14
14
|
"!apps/**/*.tsbuildinfo",
|
|
15
15
|
"config",
|
|
16
|
+
"profiles",
|
|
16
17
|
"packages",
|
|
17
18
|
"!packages/**/node_modules",
|
|
18
19
|
"!packages/**/*.tsbuildinfo",
|
|
@@ -31,7 +32,7 @@
|
|
|
31
32
|
"LICENSE"
|
|
32
33
|
],
|
|
33
34
|
"devDependencies": {
|
|
34
|
-
"@tbox.cn/app-sdk": "0.
|
|
35
|
+
"@tbox.cn/app-sdk": "0.19.0",
|
|
35
36
|
"eslint": "9.39.5",
|
|
36
37
|
"typescript-eslint": "8.67.0",
|
|
37
38
|
"eslint-plugin-react-hooks": "5.2.0",
|
|
@@ -47,7 +48,7 @@
|
|
|
47
48
|
"build:client": "pnpm check && pnpm --filter ./apps/client build",
|
|
48
49
|
"typecheck": "pnpm -r --filter \"./{apps,packages}/*\" typecheck",
|
|
49
50
|
"test": "pnpm -r --filter \"./{apps,packages}/*\" test",
|
|
50
|
-
"lint": "eslint apps packages",
|
|
51
|
+
"lint": "eslint apps $(find packages -mindepth 1 -maxdepth 1 -type d -print -quit 2>/dev/null | grep -q . && echo packages)",
|
|
51
52
|
"verify": "pnpm typecheck && pnpm test && pnpm lint && pnpm build && pnpm verify:generated && pnpm check:inspector",
|
|
52
53
|
"verify:generated": "node scripts/verify-generated.mjs",
|
|
53
54
|
"check": "pnpm check:workspace && pnpm check:inspector",
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 tbox.cn
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# @app/agent-ui-kit
|
|
2
|
+
|
|
3
|
+
Agent 对话壳 UI 组件包(源码发布)——单一模板统一化 W2-1 自 mall 模板抽取。
|
|
4
|
+
|
|
5
|
+
- **真源**:本包(`packages/agent-ui-kit`)。模板出厂副本经 `scripts/sync-agent-ui-kit.mjs` 派生
|
|
6
|
+
(name 改写 `@app/agent-ui-kit` → `@app/agent-ui-kit`),guard identity 锁定一致。
|
|
7
|
+
- **消费面**:应用 `<ChatPage store={useChatStore} cards={CHAT_REGISTRY} slots={clientCtx.slots}/>`
|
|
8
|
+
单点装配;域 UI(如商圈主屏)经 home 槽渲染函数自带。
|
|
9
|
+
- **主题**:kit 默认 tokens(`src/theme/tokens.less`);品牌资产包经 `html[data-theme]` 级联覆写 +
|
|
10
|
+
接线三行(`import '<pkg>/index.css'` + `import '<pkg>/brand.js'`[可选] + `applyTheme(id)`;见 docs/reference/templates.md)。
|
|
11
|
+
|
|
12
|
+
## 验证
|
|
13
|
+
|
|
14
|
+
```sh
|
|
15
|
+
pnpm --filter @app/agent-ui-kit typecheck
|
|
16
|
+
pnpm --filter @app/agent-ui-kit test
|
|
17
|
+
```
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@app/agent-ui-kit",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Agent 对话壳 UI 组件包(源码发布,单一模板统一化 W2-1):ChatPage/壳组件族/主题 tokens。",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": {
|
|
8
|
+
"types": "./src/index.ts",
|
|
9
|
+
"import": "./src/index.ts"
|
|
10
|
+
},
|
|
11
|
+
"./theme": {
|
|
12
|
+
"types": "./src/theme/theme.ts",
|
|
13
|
+
"import": "./src/theme/theme.ts"
|
|
14
|
+
},
|
|
15
|
+
"./package.json": "./package.json",
|
|
16
|
+
"./theme/global.less": "./src/theme/global.less",
|
|
17
|
+
"./theme/contract": "./src/theme/contract.json"
|
|
18
|
+
},
|
|
19
|
+
"scripts": {
|
|
20
|
+
"typecheck": "tsc --noEmit",
|
|
21
|
+
"test": "vitest run"
|
|
22
|
+
},
|
|
23
|
+
"files": [
|
|
24
|
+
"src",
|
|
25
|
+
"assets",
|
|
26
|
+
"README.md",
|
|
27
|
+
"LICENSE"
|
|
28
|
+
],
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"@tbox.cn/app-sdk": "catalog:",
|
|
31
|
+
"@tbox.cn/app-contracts": "catalog:",
|
|
32
|
+
"@phosphor-icons/react": "catalog:",
|
|
33
|
+
"antd-mobile": "catalog:",
|
|
34
|
+
"react-markdown": "catalog:",
|
|
35
|
+
"remark-gfm": "catalog:",
|
|
36
|
+
"zustand": "catalog:"
|
|
37
|
+
},
|
|
38
|
+
"peerDependencies": {
|
|
39
|
+
"react": "catalog:",
|
|
40
|
+
"react-dom": "catalog:"
|
|
41
|
+
},
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"@types/node": "catalog:",
|
|
44
|
+
"@types/react": "catalog:",
|
|
45
|
+
"@types/react-dom": "catalog:",
|
|
46
|
+
"happy-dom": "catalog:",
|
|
47
|
+
"less": "catalog:",
|
|
48
|
+
"react": "catalog:",
|
|
49
|
+
"react-dom": "catalog:",
|
|
50
|
+
"typescript": "catalog:",
|
|
51
|
+
"vite": "catalog:",
|
|
52
|
+
"vitest": "catalog:"
|
|
53
|
+
},
|
|
54
|
+
"engines": {
|
|
55
|
+
"node": ">=20.0.0"
|
|
56
|
+
},
|
|
57
|
+
"license": "MIT"
|
|
58
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
.chat-page {
|
|
2
|
+
position: relative;
|
|
3
|
+
display: flex;
|
|
4
|
+
flex-direction: column;
|
|
5
|
+
width: 100%;
|
|
6
|
+
height: 100vh;
|
|
7
|
+
height: 100dvh;
|
|
8
|
+
min-height: 0;
|
|
9
|
+
overflow: hidden;
|
|
10
|
+
background: var(--tbox-bg-page);
|
|
11
|
+
|
|
12
|
+
&__bg {
|
|
13
|
+
position: absolute;
|
|
14
|
+
inset: 0;
|
|
15
|
+
z-index: 0;
|
|
16
|
+
background: var(--tbox-bg-page);
|
|
17
|
+
pointer-events: none;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
&__body-wrapper {
|
|
21
|
+
position: relative;
|
|
22
|
+
z-index: 1;
|
|
23
|
+
display: flex;
|
|
24
|
+
flex: 1;
|
|
25
|
+
flex-direction: column;
|
|
26
|
+
min-height: 0;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
&__body {
|
|
30
|
+
flex: 1;
|
|
31
|
+
width: 100%;
|
|
32
|
+
max-width: var(--tbox-content-max-width);
|
|
33
|
+
min-height: 0;
|
|
34
|
+
margin: 0 auto;
|
|
35
|
+
padding: calc(12PX + env(safe-area-inset-top, 0PX)) 0 24PX;
|
|
36
|
+
overflow-y: auto;
|
|
37
|
+
overflow-x: hidden;
|
|
38
|
+
overflow-anchor: none;
|
|
39
|
+
overscroll-behavior: contain;
|
|
40
|
+
scrollbar-width: none;
|
|
41
|
+
-webkit-overflow-scrolling: touch;
|
|
42
|
+
|
|
43
|
+
&::-webkit-scrollbar {
|
|
44
|
+
display: none;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
&__orphan-card {
|
|
49
|
+
margin-right: var(--tbox-page-gutter);
|
|
50
|
+
margin-left: var(--tbox-page-gutter);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/* 顶部历史入口在场时欢迎区不再叠加自身顶部留白:胶囊到标题区留 4PX(= 欢迎区自带上边距)。 */
|
|
54
|
+
.history-entry ~ .mall-home {
|
|
55
|
+
padding-top: 0;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/* 对话开始后首页仍保留,消息接在联单主卡下方。 */
|
|
59
|
+
&--conversation &__body {
|
|
60
|
+
padding-top: calc(12PX + env(safe-area-inset-top, 0PX));
|
|
61
|
+
}
|
|
62
|
+
}
|