@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.
- package/.gitignore +5 -0
- package/.tbox/app.json +9 -1
- package/AGENTS.md +12 -4
- package/ENV.md +105 -21
- package/README.md +40 -38
- 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 +7 -6
- 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 -3
- package/apps/server/src/app-tools.ts +2 -1
- package/apps/server/src/app.ts +248 -119
- 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 -15
- 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 -17
- 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 -111
- 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,202 +1,64 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* 对话状态(Zustand
|
|
3
|
-
*
|
|
4
|
-
*
|
|
2
|
+
* 对话状态(Zustand)薄壳(单一模板统一化 W2-5):
|
|
3
|
+
* 会话泳道/历史分页/凭证升级调度全部下沉 SDK createCoreChatState——
|
|
4
|
+
* 本壳只做域参数注入(HELLO context 采集)+ 排水订阅装配(应用侧一行)。
|
|
5
5
|
*/
|
|
6
6
|
import { create } from 'zustand';
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
7
|
+
import {
|
|
8
|
+
createCoreChatState,
|
|
9
|
+
getWsUrl,
|
|
10
|
+
getLocation,
|
|
11
|
+
configureHelloContext,
|
|
12
|
+
subscribeSessionUpgradeDrain,
|
|
13
|
+
} from '@tbox.cn/app-sdk/client';
|
|
13
14
|
import type { CoreChatState } from '@tbox.cn/app-sdk/client';
|
|
14
|
-
import {
|
|
15
|
-
import
|
|
16
|
-
import type { ChatMessage } from '@/types/chat';
|
|
17
|
-
import type { IFeedbackAdapter } from '@tbox.cn/app-sdk/client';
|
|
18
|
-
import type { AdapterContextValue } from '@tbox.cn/app-sdk/client';
|
|
19
|
-
import { isSessionExpiredError } from '@/utils/session-error';
|
|
20
|
-
import { toast } from '@/utils/toast';
|
|
15
|
+
import { toast } from '@app/agent-ui-kit';
|
|
16
|
+
import { readMallIdFromUrl, readMiniAppIdFromUrl } from '@app/contracts-mall';
|
|
21
17
|
import { authClient, platformApi } from '@/platform/agent-runtime';
|
|
22
18
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
//
|
|
26
|
-
let newConversationInFlight = false;
|
|
27
|
-
// ── 终态阻断重试 in-flight 标志(模块级):防并发重试 ──
|
|
28
|
-
let retryBootstrapInFlight: Promise<void> | null = null;
|
|
29
|
-
|
|
30
|
-
interface ChatState extends CoreChatState {
|
|
31
|
-
historyMessages: ChatMessage[];
|
|
32
|
-
historyHasMore: boolean;
|
|
33
|
-
isLoadingHistory: boolean;
|
|
34
|
-
initConversation: () => Promise<void>;
|
|
35
|
-
/** 新建会话:清会话态(连接复用)+ 重置历史态 + create 新会话 */
|
|
36
|
-
newConversation: () => Promise<void>;
|
|
37
|
-
loadMoreHistory: () => Promise<void>;
|
|
38
|
-
/** 终态阻断后重试:清匿名降级缓存 → 拆除连接 → 重走 initConversation(重复点击防抖) */
|
|
39
|
-
retryBootstrap: () => Promise<void>;
|
|
40
|
-
submitFeedback: (
|
|
41
|
-
messageId: string,
|
|
42
|
-
type: 'like' | 'dislike' | 'cancel',
|
|
43
|
-
adapter: IFeedbackAdapter,
|
|
44
|
-
refreshSession?: () => Promise<AdapterContextValue>,
|
|
45
|
-
) => Promise<void>;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export const useChatStore = create<ChatState>((set, get) => ({
|
|
49
|
-
// 核心状态:所有 set/get 闭包绑定到此 store(006:不再创建客户端 sessionId)
|
|
19
|
+
export const useChatStore = create<CoreChatState>()((set, get) => ({
|
|
20
|
+
// 核心状态:所有 set/get 闭包绑定到此 store(006:不再创建客户端 sessionId);
|
|
21
|
+
// 会话泳道 deps(platformApi/authClient)注入 SDK 默认实现
|
|
50
22
|
...createCoreChatState(
|
|
51
|
-
{
|
|
23
|
+
{
|
|
24
|
+
getWsUrl: () => getWsUrl(),
|
|
25
|
+
toast,
|
|
26
|
+
platformApi,
|
|
27
|
+
authClient,
|
|
28
|
+
// session.credentials-refreshed effect → 升级调度(清缓存冷登 + 幂等重连;守卫在 scheduleSessionUpgrade 内)
|
|
29
|
+
onSessionCredentialsRefreshed: () => void get().scheduleSessionUpgrade(),
|
|
30
|
+
},
|
|
52
31
|
set as (partial: any) => void,
|
|
53
32
|
get as () => any,
|
|
54
|
-
),
|
|
55
|
-
historyMessages: [],
|
|
56
|
-
historyHasMore: true,
|
|
57
|
-
isLoadingHistory: false,
|
|
58
|
-
|
|
59
|
-
initConversation: async () => {
|
|
60
|
-
const userId = await authClient.resolveUserId();
|
|
61
|
-
set({ userId });
|
|
62
|
-
try {
|
|
63
|
-
let conversationId: string | null = null;
|
|
64
|
-
// 006:create 的 userId 只来自 token 身份(body 废弃);匿名(无 token)不可建会话 → 直接走 no-conv 分支
|
|
65
|
-
if (!authClient.getAuthState()?.token) {
|
|
66
|
-
conversationLogger.warn('anonymous: skip create conversation (no-conv)');
|
|
67
|
-
} else {
|
|
68
|
-
for (let i = 0; i < 2 && !conversationId; i++) {
|
|
69
|
-
try {
|
|
70
|
-
const { status, data } = await platformApi.createConversation();
|
|
71
|
-
if (status === 200 && data?.conversationId) conversationId = data.conversationId;
|
|
72
|
-
} catch (e) {
|
|
73
|
-
conversationLogger.warn(`createConversation 失败(重试 ${i + 1}/2):err=${(e as Error).message}`);
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
if (conversationId) set({ conversationId });
|
|
78
|
-
get().init();
|
|
79
|
-
} catch (err) {
|
|
80
|
-
conversationLogger.error('init error:', err);
|
|
81
|
-
get().init();
|
|
82
|
-
}
|
|
83
|
-
},
|
|
84
|
-
|
|
85
|
-
// 终态阻断(登录失败/scope 拒绝)后重试:清匿名降级缓存(不清则必复败)→ 拆连接 → 重走完整引导
|
|
86
|
-
retryBootstrap: () => {
|
|
87
|
-
if (retryBootstrapInFlight) return retryBootstrapInFlight; // 并发重试防抖
|
|
88
|
-
const task = (async () => {
|
|
89
|
-
authClient.clearAuth(); // 匿名降级结果被缓存,不清则重试必然复败
|
|
90
|
-
get().destroy();
|
|
91
|
-
await get().initConversation();
|
|
92
|
-
})();
|
|
93
|
-
const tracked = task.finally(() => {
|
|
94
|
-
if (retryBootstrapInFlight === tracked) retryBootstrapInFlight = null;
|
|
95
|
-
});
|
|
96
|
-
retryBootstrapInFlight = tracked;
|
|
97
|
-
return tracked;
|
|
98
|
-
},
|
|
99
|
-
|
|
100
|
-
// 新建会话:连接复用(clearChat 不断连——连接/身份是身份域),create 拿新会话键
|
|
101
|
-
newConversation: async () => {
|
|
102
|
-
if (newConversationInFlight) return; // 双击防双建会话
|
|
103
|
-
newConversationInFlight = true;
|
|
104
|
-
try {
|
|
105
|
-
historyEpoch++; // 作废在途历史加载(stale 响应整段丢弃,含 isLoadingHistory 复位)
|
|
106
|
-
get().clearChat(); // SDK:内聚取消运行中 run + 清会话态
|
|
107
|
-
set({ historyMessages: [], historyHasMore: true, isLoadingHistory: false });
|
|
108
|
-
await get().initConversation(); // create 新会话;init 对 OPEN 连接幂等早返
|
|
109
|
-
} finally {
|
|
110
|
-
newConversationInFlight = false;
|
|
111
|
-
}
|
|
112
|
-
},
|
|
113
|
-
|
|
114
|
-
loadMoreHistory: async () => {
|
|
115
|
-
const { isLoadingHistory, historyHasMore, historyMessages } = get();
|
|
116
|
-
if (isLoadingHistory || !historyHasMore) return;
|
|
117
|
-
const epoch = historyEpoch; // 快照:newConversation 递增后本响应作废
|
|
118
|
-
set({ isLoadingHistory: true });
|
|
119
|
-
|
|
120
|
-
const pageSize = 5;
|
|
121
|
-
const earliestRequestId =
|
|
122
|
-
historyMessages.length > 0
|
|
123
|
-
? historyMessages[0].requestId
|
|
124
|
-
: get().messages.find((m) => m.requestId)?.requestId;
|
|
125
|
-
|
|
126
|
-
// 006:有 token 身份时服务端按 token 取归属;无 token(匿名/兼容)保留 query userId
|
|
127
|
-
try {
|
|
128
|
-
const { status, data } = await platformApi.listMessages({
|
|
129
|
-
pageSize,
|
|
130
|
-
...(authClient.getAuthState()?.token
|
|
131
|
-
? {}
|
|
132
|
-
: { userId: get().userId }),
|
|
133
|
-
...(earliestRequestId ? { beforeId: earliestRequestId } : {}),
|
|
134
|
-
});
|
|
135
|
-
// stale 响应(newConversation 已重置态):整段丢弃——含 isLoadingHistory 复位也不落
|
|
136
|
-
if (epoch !== historyEpoch) return;
|
|
137
|
-
if (status === 200 && data) {
|
|
138
|
-
const rawList: PlatformHistoryMessage[] = (data.data as PlatformHistoryMessage[]) || [];
|
|
139
|
-
const currentRequestIds = new Set(get().messages.map((m) => m.requestId).filter(Boolean));
|
|
140
|
-
const filtered = rawList.filter(
|
|
141
|
-
(item) => !item.outerBusinessId || !currentRequestIds.has(item.outerBusinessId),
|
|
142
|
-
);
|
|
143
|
-
// SDK 单真源:消息对 + 历史卡片桶同 key 派生(平台 id 字段归一;isHistory 已由服务端标记)
|
|
144
|
-
const { messages: newMessages, cardsByMessageId } = convertHistoryMessages(filtered.reverse());
|
|
145
|
-
set((s) => ({
|
|
146
|
-
historyMessages: [...newMessages, ...s.historyMessages],
|
|
147
|
-
historyHasMore: rawList.length >= pageSize,
|
|
148
|
-
isLoadingHistory: false,
|
|
149
|
-
cardsByMessageId: { ...s.cardsByMessageId, ...cardsByMessageId },
|
|
150
|
-
}));
|
|
151
|
-
} else {
|
|
152
|
-
set({ isLoadingHistory: false });
|
|
153
|
-
}
|
|
154
|
-
} catch (err) {
|
|
155
|
-
historyLogger.error('load more error:', err);
|
|
156
|
-
if (epoch !== historyEpoch) return; // stale:newConversation 已重置 isLoadingHistory
|
|
157
|
-
set({ isLoadingHistory: false });
|
|
158
|
-
}
|
|
159
|
-
},
|
|
160
|
-
|
|
161
|
-
submitFeedback: async (messageId, type, adapter, refreshSession) => {
|
|
162
|
-
const oldMsg = get().messages.find((m) => m.id === messageId);
|
|
163
|
-
const oldFeedbackState = oldMsg?.feedbackState ?? 'none';
|
|
164
|
-
const feedbackRequestId = oldMsg?.requestId;
|
|
165
|
-
if (!feedbackRequestId) {
|
|
166
|
-
feedbackLogger.warn('no requestId for message', messageId);
|
|
167
|
-
return;
|
|
168
|
-
}
|
|
169
|
-
const newFeedbackState = type === 'cancel' ? 'none' : type;
|
|
170
|
-
get().updateMessage(messageId, { feedbackState: newFeedbackState as 'none' | 'like' | 'dislike' });
|
|
171
|
-
|
|
172
|
-
const feedbackMap = { like: 'LIKE' as const, dislike: 'DISLIKE' as const, cancel: 'CANCEL' as const };
|
|
173
|
-
try {
|
|
174
|
-
const result = await adapter.addTag(feedbackRequestId, feedbackMap[type]);
|
|
175
|
-
if (!result.success) get().updateMessage(messageId, { feedbackState: oldFeedbackState });
|
|
176
|
-
} catch (err) {
|
|
177
|
-
if (isSessionExpiredError(err) && refreshSession) {
|
|
178
|
-
try {
|
|
179
|
-
const newAdapters = await refreshSession();
|
|
180
|
-
if (newAdapters.feedback) {
|
|
181
|
-
const retry = await newAdapters.feedback.addTag(feedbackRequestId, feedbackMap[type]);
|
|
182
|
-
if (!retry.success) get().updateMessage(messageId, { feedbackState: oldFeedbackState });
|
|
183
|
-
return;
|
|
184
|
-
}
|
|
185
|
-
} catch (retryErr) {
|
|
186
|
-
feedbackLogger.error('retry failed:', retryErr);
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
get().updateMessage(messageId, { feedbackState: oldFeedbackState });
|
|
190
|
-
}
|
|
191
|
-
},
|
|
33
|
+
),
|
|
192
34
|
}));
|
|
193
35
|
|
|
194
36
|
// 011 L4:HELLO context 采集——mallId 经 URL query 采集(mall 部署;无 mallId 时不携带 context)
|
|
37
|
+
// 停车缴费按用户就近车场查(服务端 #ensureParkingId 用 lbs 反查 cityId→最近车场),
|
|
38
|
+
// 故伴采集实时 lbs(best-effort:H5/无定位权限时静默丢弃,服务端自行降级 plaza)。
|
|
39
|
+
// getter 同步签名,不能现 await getLocation() → 装配期先发起,缓存供 getter 同步读取。
|
|
40
|
+
let cachedLbs: { latitude: string; longitude: string } | undefined;
|
|
41
|
+
void getLocation()
|
|
42
|
+
.then((loc) => {
|
|
43
|
+
if (Number.isFinite(loc.latitude) && Number.isFinite(loc.longitude)) {
|
|
44
|
+
cachedLbs = { latitude: String(loc.latitude), longitude: String(loc.longitude) };
|
|
45
|
+
}
|
|
46
|
+
})
|
|
47
|
+
.catch(() => {
|
|
48
|
+
// 定位不可用(H5 沙箱/未授权)→ 不带 location,服务端走 plaza 降级
|
|
49
|
+
});
|
|
195
50
|
configureHelloContext(() => {
|
|
196
|
-
|
|
197
|
-
const
|
|
51
|
+
// 读源收敛(CS-8):mallId ?? plazaId 单一 helper(contracts-mall runtime 唯一真源)
|
|
52
|
+
const mallId = readMallIdFromUrl();
|
|
53
|
+
const miniAppId = readMiniAppIdFromUrl();
|
|
198
54
|
if (!mallId) return undefined;
|
|
199
|
-
return {
|
|
55
|
+
return {
|
|
56
|
+
mall: { mallId, ...(miniAppId ? { miniAppId } : {}) },
|
|
57
|
+
...(cachedLbs ? { location: cachedLbs } : {}),
|
|
58
|
+
};
|
|
200
59
|
});
|
|
201
60
|
|
|
202
61
|
// 4002 scope 拒绝 / 4001 鉴权耗尽的终态提示与禁用由 SDK 统一出站(chat-store configureWsFatalCloseHandler)
|
|
62
|
+
|
|
63
|
+
// 凭证升级排水(W2-2 SDK 装配位):生成中排队的升级在 isGenerating true→false 跃迁时执行
|
|
64
|
+
subscribeSessionUpgradeDrain(useChatStore);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/// <reference types="vitest" />
|
|
1
2
|
import { defineConfig, type Plugin } from 'vite';
|
|
2
3
|
import react from '@vitejs/plugin-react';
|
|
3
4
|
import pxToRem from 'postcss-pxtorem';
|
|
@@ -31,7 +32,9 @@ export default defineConfig(async ({ command }) => {
|
|
|
31
32
|
// __dirname 基准 = apps/client:构件区在模板根(上一级×2)
|
|
32
33
|
const devOverridePath = resolve(__dirname, '../../.tbox-dev.local/vite-override.mjs');
|
|
33
34
|
const devPlugins: Plugin[] = [];
|
|
34
|
-
|
|
35
|
+
// 作用域门:override 仅 dev-serve 生效——build/vitest 不受 dev 会话残留影响
|
|
36
|
+
// (G2 防线;门与探针标记同文件,guard 另断言门条件在场)
|
|
37
|
+
if (command === 'serve' && !process.env.VITEST && existsSync(devOverridePath)) {
|
|
35
38
|
const { default: tboxDevOverride } = await import(pathToFileURL(devOverridePath).href);
|
|
36
39
|
devPlugins.push(tboxDevOverride());
|
|
37
40
|
}
|
|
@@ -48,6 +51,18 @@ export default defineConfig(async ({ command }) => {
|
|
|
48
51
|
fs: resolve(__dirname, 'src/shims/node-stub.ts'),
|
|
49
52
|
path: resolve(__dirname, 'src/shims/node-stub.ts'),
|
|
50
53
|
},
|
|
54
|
+
// dev 域 React 单实例(G1/G2 防线):双 dev 入口经本文件合并生效(middleware
|
|
55
|
+
// dev 加载本文件且 command==='serve');build 恒不继承——产物位稳定性。
|
|
56
|
+
...(command === 'serve' ? { dedupe: ['react', 'react-dom'] } : {}),
|
|
57
|
+
},
|
|
58
|
+
// vitest 并入同一 config(vitest 无专属 config 文件时本就加载本文件):
|
|
59
|
+
// act() 环境声明统一入口——此前散落各用例内联、多数漏声明 → act 告警刷屏 CI 日志。
|
|
60
|
+
// environment 保持每文件 @vitest-environment pragma(纯逻辑用例不付 DOM 开销)。
|
|
61
|
+
test: {
|
|
62
|
+
setupFiles: ['src/test/setup.ts'],
|
|
63
|
+
// W3-2:client 测试随域迁 module-mall-home(页级集成测试 = 模块 tests/index.test.tsx);
|
|
64
|
+
// 模板仅留薄页装配,零测试文件合法(新增客户端测试时移除本旗标)
|
|
65
|
+
passWithNoTests: true,
|
|
51
66
|
},
|
|
52
67
|
css: {
|
|
53
68
|
postcss: { plugins: [pxToRemPlugin] },
|
package/apps/server/package.json
CHANGED
|
@@ -11,19 +11,16 @@
|
|
|
11
11
|
"typecheck": "tsc --noEmit"
|
|
12
12
|
},
|
|
13
13
|
"dependencies": {
|
|
14
|
-
"@app/module-weather": "workspace:*",
|
|
15
14
|
"@tbox.cn/agent-plugin": "catalog:",
|
|
16
15
|
"@tbox.cn/app-sdk": "catalog:",
|
|
17
16
|
"@tbox.cn/app-contracts": "catalog:",
|
|
18
17
|
"@app/contracts-mall": "workspace:*",
|
|
19
18
|
"@tbox-dev-js/sdk": "catalog:",
|
|
20
|
-
"cors": "catalog:",
|
|
21
19
|
"express": "catalog:",
|
|
22
20
|
"zod": "catalog:",
|
|
23
21
|
"@app/provider-custom": "workspace:*"
|
|
24
22
|
},
|
|
25
23
|
"devDependencies": {
|
|
26
|
-
"@types/cors": "catalog:",
|
|
27
24
|
"@types/express": "catalog:",
|
|
28
25
|
"@types/node": "catalog:",
|
|
29
26
|
"tsx": "catalog:",
|
|
@@ -3,9 +3,10 @@ import { translateTool } from './tools/translate.js';
|
|
|
3
3
|
import { clockTool } from './tools/clock.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* apps
|
|
6
|
+
* apps 级工具统一注册面(010:双注册面同步):
|
|
7
7
|
* start()(运行时)与 cli/collect-registry.ts(doctor/inspect 视图)两处同调本函数,
|
|
8
8
|
* 未来新增 apps 级工具只改此处,避免两处注册面失同步(R 评审修正)。
|
|
9
|
+
* W3-1:mall-info(含 preTool/缓存)迁 module-mall-core(模块注册面自持)。
|
|
9
10
|
*/
|
|
10
11
|
export function registerAppTools(ctx: ServerContext): void {
|
|
11
12
|
ctx.tools.register(translateTool);
|