@agent-native/core 0.193.0 → 0.193.1-nightly-20260926224948
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/corpus/README.md +1 -1
- package/corpus/templates/assets/changelog/2026-09-26-builder-is-the-primary-first-run-setup.md +6 -0
- package/corpus/templates/chat/app/components/chat/ChatRouteContent.tsx +93 -0
- package/corpus/templates/chat/app/i18n/en-US.ts +2 -0
- package/corpus/templates/chat/changelog/2026-09-26-builder-setup-retry.md +6 -0
- package/corpus/templates/clips/changelog/2026-09-26-builder-is-the-primary-first-run-setup.md +6 -0
- package/corpus/templates/content/app/hooks/use-content-recent.ts +137 -16
- package/corpus/templates/content/changelog/2026-09-26-empty-recent-list.md +6 -0
- package/corpus/templates/design/changelog/2026-09-26-builder-is-the-primary-first-run-setup.md +6 -0
- package/corpus/templates/mail/app/components/layout/AppLayout.tsx +9 -8
- package/corpus/templates/mail/app/components/layout/HeaderActions.tsx +2 -2
- package/corpus/templates/mail/changelog/2026-09-26-fixed-an-inbox-crash-when-the-sidebar-is-pinned.md +6 -0
- package/corpus/templates/slides/changelog/2026-09-26-builder-is-the-primary-first-run-setup.md +6 -0
- package/dist/automation/index.d.ts +1 -1
- package/dist/client/AgentPanel.js +3 -2
- package/dist/client/agent-chat/index.d.ts +1 -1
- package/dist/client/agent-chat/index.js +1 -1
- package/dist/client/chat/agentkit-protocol.js +18 -1
- package/dist/client/chat/run-recovery.d.ts +1 -0
- package/dist/client/chat/run-recovery.js +1 -1
- package/dist/client/onboarding/FirstRunOnboarding.js +59 -22
- package/dist/client/ui/AppSidebar.d.ts +2 -1
- package/dist/client/ui/AppSidebar.js +11 -2
- package/dist/client/ui/index.d.ts +1 -1
- package/dist/client/ui/index.js +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/localization/core-messages/ar-SA.js +1 -0
- package/dist/localization/core-messages/de-DE.js +1 -0
- package/dist/localization/core-messages/en-US.d.ts +1 -0
- package/dist/localization/core-messages/en-US.js +1 -0
- package/dist/localization/core-messages/es-ES.js +1 -0
- package/dist/localization/core-messages/fr-FR.js +1 -0
- package/dist/localization/core-messages/hi-IN.js +1 -0
- package/dist/localization/core-messages/ja-JP.js +1 -0
- package/dist/localization/core-messages/ko-KR.js +1 -0
- package/dist/localization/core-messages/pt-BR.js +1 -0
- package/dist/localization/core-messages/zh-CN.js +1 -0
- package/dist/localization/core-messages/zh-TW.js +1 -0
- package/dist/localization/core-messages.d.ts +1 -0
- package/dist/observability/routes.d.ts +1 -1
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/server/agent-engine-ollama-models-route.d.ts +1 -1
- package/dist/server/core-routes-plugin.d.ts +1 -1
- package/dist/templates/chat/app/components/chat/ChatRouteContent.tsx +93 -0
- package/dist/templates/chat/app/i18n/ar-SA.ts +1 -0
- package/dist/templates/chat/app/i18n/de-DE.ts +2 -0
- package/dist/templates/chat/app/i18n/en-US.ts +2 -0
- package/dist/templates/chat/app/i18n/es-ES.ts +2 -0
- package/dist/templates/chat/app/i18n/fr-FR.ts +2 -0
- package/dist/templates/chat/app/i18n/hi-IN.ts +2 -0
- package/dist/templates/chat/app/i18n/ja-JP.ts +2 -0
- package/dist/templates/chat/app/i18n/ko-KR.ts +2 -0
- package/dist/templates/chat/app/i18n/pt-BR.ts +2 -0
- package/dist/templates/chat/app/i18n/zh-CN.ts +1 -0
- package/dist/templates/chat/app/i18n/zh-TW.ts +1 -0
- package/dist/templates/chat/changelog/2026-09-26-builder-setup-retry.md +6 -0
- package/package.json +1 -1
- package/src/templates/chat/app/components/chat/ChatRouteContent.tsx +93 -0
- package/src/templates/chat/app/i18n/ar-SA.ts +1 -0
- package/src/templates/chat/app/i18n/de-DE.ts +2 -0
- package/src/templates/chat/app/i18n/en-US.ts +2 -0
- package/src/templates/chat/app/i18n/es-ES.ts +2 -0
- package/src/templates/chat/app/i18n/fr-FR.ts +2 -0
- package/src/templates/chat/app/i18n/hi-IN.ts +2 -0
- package/src/templates/chat/app/i18n/ja-JP.ts +2 -0
- package/src/templates/chat/app/i18n/ko-KR.ts +2 -0
- package/src/templates/chat/app/i18n/pt-BR.ts +2 -0
- package/src/templates/chat/app/i18n/zh-CN.ts +1 -0
- package/src/templates/chat/app/i18n/zh-TW.ts +1 -0
- package/src/templates/chat/changelog/2026-09-26-builder-setup-retry.md +6 -0
package/corpus/README.md
CHANGED
|
@@ -3,6 +3,8 @@ import type {
|
|
|
3
3
|
AgentMessage,
|
|
4
4
|
} from "@agent-native/agentkit";
|
|
5
5
|
import {
|
|
6
|
+
AgentMessageView,
|
|
7
|
+
AgentRunFailure,
|
|
6
8
|
AgentConnectionRequestCard,
|
|
7
9
|
AgentKitChat,
|
|
8
10
|
} from "@agent-native/agentkit/react/components";
|
|
@@ -10,9 +12,14 @@ import {
|
|
|
10
12
|
useAgentKit,
|
|
11
13
|
useAgentKitControl,
|
|
12
14
|
useAgentThread,
|
|
15
|
+
type AgentRunFailureRenderProps,
|
|
13
16
|
type AgentKitRenderProps,
|
|
14
17
|
} from "@agent-native/agentkit/react/context";
|
|
15
18
|
import { AgentKitRoot } from "@agent-native/agentkit/react/root";
|
|
19
|
+
import {
|
|
20
|
+
BuilderSetupCard,
|
|
21
|
+
isMissingLlmProviderRunError,
|
|
22
|
+
} from "@agent-native/core/client/agent-chat";
|
|
16
23
|
import { CoreComposerRuntimeProvider } from "@agent-native/core/client/agentkit-chat/composer";
|
|
17
24
|
import {
|
|
18
25
|
McpAgentKitConnectionRequestCard,
|
|
@@ -120,7 +127,9 @@ function ChatThreadRouteContent({
|
|
|
120
127
|
labels={{ composerPlaceholder: t("chat.composerPlaceholder") }}
|
|
121
128
|
slots={{
|
|
122
129
|
emptyState: ChatEmptyState,
|
|
130
|
+
message: ChatMessage,
|
|
123
131
|
messageSupplement: ChatMcpConnectionSuggestion,
|
|
132
|
+
runFailure: ChatRunFailure,
|
|
124
133
|
connectionRequest: ChatMcpConnectionRequest,
|
|
125
134
|
footer: ChatAgentFooter,
|
|
126
135
|
}}
|
|
@@ -153,6 +162,90 @@ function ChatThreadRouteContent({
|
|
|
153
162
|
);
|
|
154
163
|
}
|
|
155
164
|
|
|
165
|
+
function ChatMessage({ value, threadId }: AgentKitRenderProps<AgentMessage>) {
|
|
166
|
+
const metadata = value.metadata as
|
|
167
|
+
| { custom?: { agentNativeRecoveryAction?: unknown } }
|
|
168
|
+
| undefined;
|
|
169
|
+
const recoveryAction = metadata?.custom?.agentNativeRecoveryAction;
|
|
170
|
+
if (
|
|
171
|
+
value.role === "user" &&
|
|
172
|
+
(recoveryAction === "continue" || recoveryAction === "retry")
|
|
173
|
+
) {
|
|
174
|
+
return null;
|
|
175
|
+
}
|
|
176
|
+
return <AgentMessageView value={value} threadId={threadId} />;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function ChatRunFailure({
|
|
180
|
+
error,
|
|
181
|
+
runId,
|
|
182
|
+
threadId,
|
|
183
|
+
}: AgentRunFailureRenderProps) {
|
|
184
|
+
const thread = useAgentThread(threadId);
|
|
185
|
+
const { controller } = useAgentKit();
|
|
186
|
+
const t = useT();
|
|
187
|
+
const recoveryMetadata = (message: (typeof thread.messages)[number]) =>
|
|
188
|
+
(
|
|
189
|
+
message.metadata as
|
|
190
|
+
| {
|
|
191
|
+
custom?: {
|
|
192
|
+
agentNativeRecoveryAction?: unknown;
|
|
193
|
+
agentNativeRecoveryOfRunId?: unknown;
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
| undefined
|
|
197
|
+
)?.custom;
|
|
198
|
+
const userRequests = thread.messages.filter((message) => {
|
|
199
|
+
if (message.role !== "user") return false;
|
|
200
|
+
const action = recoveryMetadata(message)?.agentNativeRecoveryAction;
|
|
201
|
+
return action !== "continue" && action !== "retry";
|
|
202
|
+
});
|
|
203
|
+
const originalRequest = userRequests[0];
|
|
204
|
+
const hasRetryForThisRun = thread.messages.some(
|
|
205
|
+
(message) =>
|
|
206
|
+
recoveryMetadata(message)?.agentNativeRecoveryAction === "retry" &&
|
|
207
|
+
recoveryMetadata(message)?.agentNativeRecoveryOfRunId === runId,
|
|
208
|
+
);
|
|
209
|
+
const retryFirstMessage = useCallback(() => {
|
|
210
|
+
const prompt =
|
|
211
|
+
originalRequest?.parts
|
|
212
|
+
.filter((part) => part.type === "text")
|
|
213
|
+
.map((part) => part.text)
|
|
214
|
+
.join("\n") ?? "";
|
|
215
|
+
const attachments =
|
|
216
|
+
originalRequest?.parts.filter((part) => part.type === "file") ?? [];
|
|
217
|
+
void controller.sendMessage({
|
|
218
|
+
threadId,
|
|
219
|
+
text: prompt || t("chat.retryPreviousRequest"),
|
|
220
|
+
...(attachments.length ? { attachments } : {}),
|
|
221
|
+
metadata: {
|
|
222
|
+
custom: {
|
|
223
|
+
agentNativeRecoveryAction: "retry",
|
|
224
|
+
agentNativeRecoveryOfRunId: runId,
|
|
225
|
+
},
|
|
226
|
+
},
|
|
227
|
+
});
|
|
228
|
+
}, [controller, originalRequest, runId, t, threadId]);
|
|
229
|
+
const isFirstMessage = userRequests.length === 1 && !hasRetryForThisRun;
|
|
230
|
+
if (
|
|
231
|
+
isFirstMessage &&
|
|
232
|
+
isMissingLlmProviderRunError({
|
|
233
|
+
message: error.message,
|
|
234
|
+
details: typeof error.details === "string" ? error.details : undefined,
|
|
235
|
+
errorCode: error.code,
|
|
236
|
+
})
|
|
237
|
+
) {
|
|
238
|
+
return (
|
|
239
|
+
<BuilderSetupCard
|
|
240
|
+
fullWidth
|
|
241
|
+
layout="sidebar"
|
|
242
|
+
onRetry={retryFirstMessage}
|
|
243
|
+
/>
|
|
244
|
+
);
|
|
245
|
+
}
|
|
246
|
+
return <AgentRunFailure error={error} runId={runId} threadId={threadId} />;
|
|
247
|
+
}
|
|
248
|
+
|
|
156
249
|
function ChatLifecycleTracking({ threadId }: { threadId: string }) {
|
|
157
250
|
const thread = useAgentThread(threadId);
|
|
158
251
|
const lifecycleRef = useRef({
|
|
@@ -33,6 +33,8 @@ const messages = {
|
|
|
33
33
|
pinChat: "Pin Chat",
|
|
34
34
|
pinned: "Pinned",
|
|
35
35
|
recents: "Recents",
|
|
36
|
+
retryPreviousRequest:
|
|
37
|
+
"Retry my previous request now that the model provider is connected.",
|
|
36
38
|
renameChat: "Rename Chat",
|
|
37
39
|
renameFailed: "Rename Failed",
|
|
38
40
|
renameThread: "Rename Thread",
|
|
@@ -11,9 +11,51 @@ import {
|
|
|
11
11
|
type ContentRecentTarget,
|
|
12
12
|
} from "@shared/content-personal-navigation";
|
|
13
13
|
import { useQueryClient } from "@tanstack/react-query";
|
|
14
|
-
import { useCallback, useEffect, useRef } from "react";
|
|
14
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
15
15
|
import { toast } from "sonner";
|
|
16
16
|
|
|
17
|
+
const contentRecentRecoveries = new WeakMap<
|
|
18
|
+
ReturnType<typeof useQueryClient>,
|
|
19
|
+
Map<string, Promise<void>>
|
|
20
|
+
>();
|
|
21
|
+
|
|
22
|
+
function recoverContentRecentScope(
|
|
23
|
+
queryClient: ReturnType<typeof useQueryClient>,
|
|
24
|
+
scopeKey: string,
|
|
25
|
+
refresh: () => Promise<void>,
|
|
26
|
+
) {
|
|
27
|
+
let recoveries = contentRecentRecoveries.get(queryClient);
|
|
28
|
+
if (!recoveries) {
|
|
29
|
+
recoveries = new Map();
|
|
30
|
+
contentRecentRecoveries.set(queryClient, recoveries);
|
|
31
|
+
}
|
|
32
|
+
const recovery = recoveries.get(scopeKey);
|
|
33
|
+
if (recovery) return recovery;
|
|
34
|
+
|
|
35
|
+
let nextRecovery: Promise<void>;
|
|
36
|
+
nextRecovery = Promise.resolve()
|
|
37
|
+
.then(refresh)
|
|
38
|
+
.finally(() => {
|
|
39
|
+
if (recoveries.get(scopeKey) === nextRecovery) {
|
|
40
|
+
recoveries.delete(scopeKey);
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
recoveries.set(scopeKey, nextRecovery);
|
|
44
|
+
return nextRecovery;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function contentRecentScopeKey(
|
|
48
|
+
org: ReturnType<typeof useOrg>["data"],
|
|
49
|
+
spaceId?: string,
|
|
50
|
+
) {
|
|
51
|
+
if (!org) return undefined;
|
|
52
|
+
return JSON.stringify([
|
|
53
|
+
org.email.trim().toLowerCase(),
|
|
54
|
+
org.orgId ?? null,
|
|
55
|
+
spaceId ?? null,
|
|
56
|
+
]);
|
|
57
|
+
}
|
|
58
|
+
|
|
17
59
|
export function contentRecentQueryArgs(
|
|
18
60
|
scopeKey: string | undefined,
|
|
19
61
|
spaceId?: string,
|
|
@@ -22,31 +64,110 @@ export function contentRecentQueryArgs(
|
|
|
22
64
|
return { scopeKey, ...(spaceId ? { spaceId } : {}) };
|
|
23
65
|
}
|
|
24
66
|
|
|
67
|
+
export function isContentRecentContextChanged(error: unknown): boolean {
|
|
68
|
+
return (
|
|
69
|
+
!!error &&
|
|
70
|
+
typeof error === "object" &&
|
|
71
|
+
(error as { errorCode?: unknown }).errorCode === "context_changed"
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
|
|
25
75
|
export function useContentRecent(spaceId?: string) {
|
|
26
76
|
const org = useOrg();
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
77
|
+
const queryClient = useQueryClient();
|
|
78
|
+
const scopeKey = contentRecentScopeKey(org.data, spaceId);
|
|
79
|
+
const args = useMemo(
|
|
80
|
+
() => contentRecentQueryArgs(scopeKey, spaceId),
|
|
81
|
+
[scopeKey, spaceId],
|
|
82
|
+
);
|
|
83
|
+
const query = useActionQuery("get-content-recent", args, {
|
|
84
|
+
enabled: Boolean(scopeKey) && !org.isFetching,
|
|
85
|
+
placeholderData: undefined,
|
|
86
|
+
});
|
|
87
|
+
const [refreshingScopes, setRefreshingScopes] = useState<Set<string>>(
|
|
88
|
+
() => new Set(),
|
|
89
|
+
);
|
|
90
|
+
const resyncedScopesRef = useRef(new Set<string>());
|
|
91
|
+
const contextChanged = isContentRecentContextChanged(query.error);
|
|
92
|
+
|
|
93
|
+
useEffect(() => {
|
|
94
|
+
if (!contextChanged) {
|
|
95
|
+
if (scopeKey) {
|
|
96
|
+
resyncedScopesRef.current.delete(scopeKey);
|
|
97
|
+
}
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
if (!scopeKey) return;
|
|
101
|
+
if (resyncedScopesRef.current.has(scopeKey)) return;
|
|
102
|
+
|
|
103
|
+
resyncedScopesRef.current.add(scopeKey);
|
|
104
|
+
setRefreshingScopes((current) => new Set(current).add(scopeKey));
|
|
105
|
+
void recoverContentRecentScope(queryClient, scopeKey, async () => {
|
|
106
|
+
try {
|
|
107
|
+
const refreshedOrg = await org.refetch({ cancelRefetch: false });
|
|
108
|
+
if (refreshedOrg.isError) return;
|
|
109
|
+
const refreshedArgs = contentRecentQueryArgs(
|
|
110
|
+
contentRecentScopeKey(refreshedOrg.data, spaceId),
|
|
111
|
+
spaceId,
|
|
112
|
+
);
|
|
113
|
+
if (!refreshedArgs) return;
|
|
114
|
+
await queryClient.invalidateQueries(
|
|
115
|
+
{
|
|
116
|
+
queryKey: ["action", "get-content-recent", refreshedArgs],
|
|
117
|
+
exact: true,
|
|
118
|
+
},
|
|
119
|
+
{ cancelRefetch: false },
|
|
120
|
+
);
|
|
121
|
+
} catch (error) {
|
|
122
|
+
console.warn(
|
|
123
|
+
"Could not refresh the Content Recent context after a scope mismatch.",
|
|
124
|
+
error,
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
}).finally(() => {
|
|
128
|
+
setRefreshingScopes((current) => {
|
|
129
|
+
if (!current.has(scopeKey)) return current;
|
|
130
|
+
const next = new Set(current);
|
|
131
|
+
next.delete(scopeKey);
|
|
132
|
+
return next;
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
}, [
|
|
136
|
+
contextChanged,
|
|
137
|
+
org.refetch,
|
|
138
|
+
query.error,
|
|
139
|
+
query.isError,
|
|
140
|
+
queryClient,
|
|
141
|
+
scopeKey,
|
|
142
|
+
spaceId,
|
|
143
|
+
]);
|
|
144
|
+
|
|
145
|
+
const refetch = useCallback(
|
|
146
|
+
(...args: Parameters<typeof query.refetch>) => {
|
|
147
|
+
if (contextChanged && scopeKey) {
|
|
148
|
+
resyncedScopesRef.current.delete(scopeKey);
|
|
149
|
+
contentRecentRecoveries.get(queryClient)?.delete(scopeKey);
|
|
150
|
+
}
|
|
151
|
+
return query.refetch(...args);
|
|
40
152
|
},
|
|
153
|
+
[contextChanged, query.refetch, scopeKey],
|
|
41
154
|
);
|
|
155
|
+
|
|
156
|
+
const recoveringContext =
|
|
157
|
+
contextChanged &&
|
|
158
|
+
(!scopeKey ||
|
|
159
|
+
refreshingScopes.has(scopeKey) ||
|
|
160
|
+
!resyncedScopesRef.current.has(scopeKey));
|
|
42
161
|
return {
|
|
43
162
|
...query,
|
|
163
|
+
refetch,
|
|
44
164
|
data:
|
|
45
165
|
!org.isFetching && query.data?.scopeKey === scopeKey
|
|
46
166
|
? query.data
|
|
47
167
|
: undefined,
|
|
48
|
-
isLoading:
|
|
49
|
-
|
|
168
|
+
isLoading:
|
|
169
|
+
org.isLoading || org.isFetching || query.isLoading || recoveringContext,
|
|
170
|
+
isError: org.isError || (query.isError && !recoveringContext),
|
|
50
171
|
};
|
|
51
172
|
}
|
|
52
173
|
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
AppSidebarHeader,
|
|
17
17
|
EnvironmentBadge,
|
|
18
18
|
FeedbackButton,
|
|
19
|
+
RouterSidebarLink,
|
|
19
20
|
} from "@agent-native/core/client/ui";
|
|
20
21
|
import { SidebarFooterActions } from "@agent-native/toolkit/app-shell";
|
|
21
22
|
import {
|
|
@@ -1458,7 +1459,7 @@ function AppLayoutInner({ children }: AppLayoutProps) {
|
|
|
1458
1459
|
dropIndicator?.tabIndex === tabIndex &&
|
|
1459
1460
|
dropIndicator.side === "right";
|
|
1460
1461
|
const link = (
|
|
1461
|
-
<
|
|
1462
|
+
<RouterSidebarLink
|
|
1462
1463
|
to={tab.href}
|
|
1463
1464
|
aria-current={tab.isActive ? "page" : undefined}
|
|
1464
1465
|
draggable={canDrag}
|
|
@@ -1492,7 +1493,7 @@ function AppLayoutInner({ children }: AppLayoutProps) {
|
|
|
1492
1493
|
{count}
|
|
1493
1494
|
</span>
|
|
1494
1495
|
)}
|
|
1495
|
-
</
|
|
1496
|
+
</RouterSidebarLink>
|
|
1496
1497
|
);
|
|
1497
1498
|
return (
|
|
1498
1499
|
<div
|
|
@@ -1900,7 +1901,7 @@ function AppLayoutInner({ children }: AppLayoutProps) {
|
|
|
1900
1901
|
return (
|
|
1901
1902
|
<Tooltip key={item.id}>
|
|
1902
1903
|
<TooltipTrigger asChild>
|
|
1903
|
-
<
|
|
1904
|
+
<RouterSidebarLink
|
|
1904
1905
|
to={item.href}
|
|
1905
1906
|
aria-label={item.label}
|
|
1906
1907
|
className={cn(
|
|
@@ -1913,7 +1914,7 @@ function AppLayoutInner({ children }: AppLayoutProps) {
|
|
|
1913
1914
|
{item.count && item.count > 0 ? (
|
|
1914
1915
|
<span className="absolute end-1 top-1 h-1.5 w-1.5 rounded-full bg-primary" />
|
|
1915
1916
|
) : null}
|
|
1916
|
-
</
|
|
1917
|
+
</RouterSidebarLink>
|
|
1917
1918
|
</TooltipTrigger>
|
|
1918
1919
|
<TooltipContent side="right">
|
|
1919
1920
|
{item.label}
|
|
@@ -2134,14 +2135,14 @@ function AppLayoutInner({ children }: AppLayoutProps) {
|
|
|
2134
2135
|
<DevDatabaseLink />
|
|
2135
2136
|
<Tooltip>
|
|
2136
2137
|
<TooltipTrigger asChild>
|
|
2137
|
-
<
|
|
2138
|
+
<RouterSidebarLink
|
|
2138
2139
|
to="/settings"
|
|
2139
2140
|
onClick={closeSidebar}
|
|
2140
2141
|
aria-label={t("mail.toolbar.settings")}
|
|
2141
2142
|
className="flex size-9 shrink-0 items-center justify-center rounded-md text-primary hover:bg-accent/60 hover:text-primary"
|
|
2142
2143
|
>
|
|
2143
2144
|
<IconSettings className="size-4" />
|
|
2144
|
-
</
|
|
2145
|
+
</RouterSidebarLink>
|
|
2145
2146
|
</TooltipTrigger>
|
|
2146
2147
|
<TooltipContent side="right">
|
|
2147
2148
|
{t("mail.toolbar.settings")}
|
|
@@ -2625,14 +2626,14 @@ function StandardLayout({ children }: AppLayoutProps) {
|
|
|
2625
2626
|
<DevDatabaseLink />
|
|
2626
2627
|
<Tooltip>
|
|
2627
2628
|
<TooltipTrigger asChild>
|
|
2628
|
-
<
|
|
2629
|
+
<RouterSidebarLink
|
|
2629
2630
|
to="/settings"
|
|
2630
2631
|
onClick={() => setSidebarOpen(false)}
|
|
2631
2632
|
aria-label={t("mail.toolbar.settings")}
|
|
2632
2633
|
className="flex size-9 shrink-0 items-center justify-center rounded-md text-primary hover:bg-accent/60 hover:text-primary"
|
|
2633
2634
|
>
|
|
2634
2635
|
<IconSettings className="size-4" />
|
|
2635
|
-
</
|
|
2636
|
+
</RouterSidebarLink>
|
|
2636
2637
|
</TooltipTrigger>
|
|
2637
2638
|
<TooltipContent side="right">
|
|
2638
2639
|
{t("mail.toolbar.settings")}
|
|
@@ -51,7 +51,7 @@ export function useSetPageTitle(node: ReactNode) {
|
|
|
51
51
|
currentTitle = null;
|
|
52
52
|
notify();
|
|
53
53
|
};
|
|
54
|
-
});
|
|
54
|
+
}, [node]);
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
export function useSetHeaderActions(node: ReactNode) {
|
|
@@ -70,5 +70,5 @@ export function useSetHeaderActions(node: ReactNode) {
|
|
|
70
70
|
notify();
|
|
71
71
|
}
|
|
72
72
|
};
|
|
73
|
-
});
|
|
73
|
+
}, [node]);
|
|
74
74
|
}
|
|
@@ -186,8 +186,8 @@ export declare function createAutomationCallbackHandler(runtime: AutomationRunti
|
|
|
186
186
|
duplicate?: undefined;
|
|
187
187
|
eventId?: undefined;
|
|
188
188
|
} | {
|
|
189
|
-
error?: undefined;
|
|
190
189
|
accepted: boolean;
|
|
191
190
|
duplicate: boolean;
|
|
192
191
|
eventId: string;
|
|
192
|
+
error?: undefined;
|
|
193
193
|
}>;
|
|
@@ -40,7 +40,7 @@ const loadMultiTabAssistantChat = () => import("./MultiTabAssistantChat.js").the
|
|
|
40
40
|
default: m.MultiTabAssistantChat,
|
|
41
41
|
}));
|
|
42
42
|
const MultiTabAssistantChatLazy = lazy(loadMultiTabAssistantChat);
|
|
43
|
-
import {
|
|
43
|
+
import { useLocation, useNavigate } from "react-router";
|
|
44
44
|
import { withBuilderUtmTrackingParams } from "../shared/builder-link-tracking.js";
|
|
45
45
|
import { AGENT_PANEL_OPEN_SETTINGS_EVENT, AGENT_PANEL_SET_MODE_EVENT, } from "./agent-sidebar-events.js";
|
|
46
46
|
export { shouldHandleAgentPanelChatShortcut, shouldHandleAgentSidebarToggle, } from "./agent-sidebar-events.js";
|
|
@@ -59,6 +59,7 @@ import { useFirstRunOnboardingGateOwnsSurface } from "./onboarding/first-run-sta
|
|
|
59
59
|
import { useOnboardingPreviewMode } from "./onboarding/use-preview-mode.js";
|
|
60
60
|
import { recoverFromStaleChunkError } from "./route-chunk-recovery.js";
|
|
61
61
|
import { withBuilderConnectTrackingParams } from "./settings/useBuilderStatus.js";
|
|
62
|
+
import { RouterSidebarLink } from "./ui/AppSidebar.js";
|
|
62
63
|
import { useDevMode } from "./use-dev-mode.js";
|
|
63
64
|
import { cn } from "./utils.js";
|
|
64
65
|
function parentFrameTargetOrigin() {
|
|
@@ -786,7 +787,7 @@ function AgentPanelInner({ defaultMode = "chat", className, style, apiUrl, empty
|
|
|
786
787
|
// A sibling overlay owns focus next; restoring it to the menu
|
|
787
788
|
// trigger would dismiss that overlay as an outside interaction.
|
|
788
789
|
consumeAgentPanelOverlayFocusRestore(preventHeaderMenuFocusRestoreRef, event);
|
|
789
|
-
}, children: [onCollapse && (_jsxs(_Fragment, { children: [_jsxs(DropdownMenuItem, { onSelect: onCollapse, children: [_jsx(IconLayoutSidebarRightCollapse, { size: 14, className: "shrink-0" }), t("agentPanel.collapseSidebar"), _jsx(DropdownMenuShortcut, { children: toggleSidebarHint })] }), _jsx(DropdownMenuSeparator, {})] })), onCollapse && mode === "chat" && wideDrawerAction ? (_jsxs(DropdownMenuItem, { onSelect: wideDrawerAction, children: [_jsx(IconArrowsHorizontal, { size: 14, className: "shrink-0" }), wideDrawerLabel, _jsx(DropdownMenuShortcut, { children: widenChatHint })] })) : null, fullViewAction?.kind === "callback" && onFullViewRequest ? (_jsxs(DropdownMenuItem, { onSelect: onFullViewRequest, "aria-label": t("agentPanel.openFullView"), children: [_jsx(IconArrowsMaximize, { size: 14, className: "shrink-0" }), t("agentPanel.openFullView")] })) : fullViewAction?.kind === "link" ? (_jsx(DropdownMenuItem, { asChild: true, children: _jsxs(
|
|
790
|
+
}, children: [onCollapse && (_jsxs(_Fragment, { children: [_jsxs(DropdownMenuItem, { onSelect: onCollapse, children: [_jsx(IconLayoutSidebarRightCollapse, { size: 14, className: "shrink-0" }), t("agentPanel.collapseSidebar"), _jsx(DropdownMenuShortcut, { children: toggleSidebarHint })] }), _jsx(DropdownMenuSeparator, {})] })), onCollapse && mode === "chat" && wideDrawerAction ? (_jsxs(DropdownMenuItem, { onSelect: wideDrawerAction, children: [_jsx(IconArrowsHorizontal, { size: 14, className: "shrink-0" }), wideDrawerLabel, _jsx(DropdownMenuShortcut, { children: widenChatHint })] })) : null, fullViewAction?.kind === "callback" && onFullViewRequest ? (_jsxs(DropdownMenuItem, { onSelect: onFullViewRequest, "aria-label": t("agentPanel.openFullView"), children: [_jsx(IconArrowsMaximize, { size: 14, className: "shrink-0" }), t("agentPanel.openFullView")] })) : fullViewAction?.kind === "link" ? (_jsx(DropdownMenuItem, { asChild: true, children: _jsxs(RouterSidebarLink, { to: fullViewAction.href, "aria-label": t("agentPanel.openFullView"), children: [_jsx(IconArrowsMaximize, { size: 14, className: "shrink-0" }), t("agentPanel.openFullView")] }) })) : null, (onCollapse && mode === "chat" && wideDrawerAction) ||
|
|
790
791
|
fullViewAction ? (_jsx(DropdownMenuSeparator, {})) : null, onCollapse &&
|
|
791
792
|
(newTabMode === "cli" || (mode === "cli" && renderCliTab)) && (_jsxs(_Fragment, { children: [_jsxs(DropdownMenuItem, { onSelect: () => openNewUiTab(addTab), children: [_jsx(IconPlus, { size: 14, className: "shrink-0" }), newUiTabLabel ?? t("agentPanel.newChat")] }), _jsxs(DropdownMenuItem, { onSelect: openNewCliTab, children: [_jsx(IconTerminal2, { size: 14, className: "shrink-0" }), newCliTabLabel ?? t("agentPanel.newTerminal")] }), mode === "chat" ? _jsx(DropdownMenuSeparator, {}) : null] })), onCollapse && mode === "chat" && newTabMode !== "cli" && (_jsxs(DropdownMenuItem, { onSelect: () => openNewUiTab(addTab), children: [_jsx(IconPlus, { size: 14, className: "shrink-0" }), newUiTabLabel ?? t("agentPanel.newChat")] })), onCollapse &&
|
|
792
793
|
mode === "chat" &&
|
|
@@ -18,7 +18,7 @@ export { CodeRequiredDialog, type CodeRequiredDialogProps, } from "../components
|
|
|
18
18
|
export { ChatFirstAgentActivityPanel, type ChatFirstAgentActivityPanelProps, } from "../chat-first-agent-activity.js";
|
|
19
19
|
export { ChatFirstSurfacePanelToggle } from "../chat-first-surface-panel-toggle.js";
|
|
20
20
|
export { useAgentEngineConfigured, type AgentEngineConfiguredState, type UseAgentEngineConfiguredResult, } from "../use-agent-engine-configured.js";
|
|
21
|
-
export { BuilderSetupCard } from "../chat/run-recovery.js";
|
|
21
|
+
export { BuilderSetupCard, isMissingLlmProviderRunError, type RunErrorInfo, } from "../chat/run-recovery.js";
|
|
22
22
|
export { AgentConversation, AgentConversationMessageView, normalizeCodeAgentTranscriptForConversation, useNearBottomAutoscroll, type CodeAgentConversationTranscriptEvent, type CodeAgentConversationTranscriptEventType, type NormalizeCodeAgentTranscriptOptions, type AgentConversationArtifact, type AgentConversationAttachment, type AgentConversationMessage, type AgentConversationMessagePart, type AgentConversationMessageRole, type AgentConversationNotice, type AgentConversationNoticeTone, type AgentConversationToolCall, type AgentConversationToolState, } from "../conversation/index.js";
|
|
23
23
|
export { McpAppRenderer } from "../mcp-apps/McpAppRenderer.js";
|
|
24
24
|
export { AGENT_NATIVE_MCP_APP_HOST_MESSAGE_TYPES, getMcpAppHostContext, initializeMcpAppHost, openMcpAppHostLink, requestMcpAppDisplayMode, sendMcpAppHostMessage, updateMcpAppModelContext, useMcpAppHostContext, type AgentNativeMcpAppHostMessageType, type McpAppDisplayMode, type McpAppHostChatMessage, type McpAppHostCapabilities, type McpAppHostContext, type McpAppHostInfo, type McpAppHostContextSnapshot, type McpAppModelContextContentPart, type McpAppModelContextUpdate, } from "../mcp-app-host.js";
|
|
@@ -18,7 +18,7 @@ export { CodeRequiredDialog, } from "../components/CodeRequiredDialog.js";
|
|
|
18
18
|
export { ChatFirstAgentActivityPanel, } from "../chat-first-agent-activity.js";
|
|
19
19
|
export { ChatFirstSurfacePanelToggle } from "../chat-first-surface-panel-toggle.js";
|
|
20
20
|
export { useAgentEngineConfigured, } from "../use-agent-engine-configured.js";
|
|
21
|
-
export { BuilderSetupCard } from "../chat/run-recovery.js";
|
|
21
|
+
export { BuilderSetupCard, isMissingLlmProviderRunError, } from "../chat/run-recovery.js";
|
|
22
22
|
export { AgentConversation, AgentConversationMessageView, normalizeCodeAgentTranscriptForConversation, useNearBottomAutoscroll, } from "../conversation/index.js";
|
|
23
23
|
export { McpAppRenderer } from "../mcp-apps/McpAppRenderer.js";
|
|
24
24
|
export { AGENT_NATIVE_MCP_APP_HOST_MESSAGE_TYPES, getMcpAppHostContext, initializeMcpAppHost, openMcpAppHostLink, requestMcpAppDisplayMode, sendMcpAppHostMessage, updateMcpAppModelContext, useMcpAppHostContext, } from "../mcp-app-host.js";
|
|
@@ -1852,12 +1852,29 @@ export function createAgentKitProtocolAdapter(runtime, options = {}) {
|
|
|
1852
1852
|
if (input.resume !== undefined) {
|
|
1853
1853
|
throw new AgentProtocolValidationError("startRun.resume", "Core requires approval continuations to use resumeRun");
|
|
1854
1854
|
}
|
|
1855
|
-
const
|
|
1855
|
+
const latestUserMessage = [...input.messages]
|
|
1856
|
+
.reverse()
|
|
1857
|
+
.find((message) => message.role === "user");
|
|
1858
|
+
const latestUserMetadata = asRecord(latestUserMessage?.metadata);
|
|
1859
|
+
const recoveryMetadata = asRecord(latestUserMetadata?.custom);
|
|
1860
|
+
const isRecoveryRetry = recoveryMetadata?.agentNativeRecoveryAction === "retry";
|
|
1861
|
+
const turnMetadata = mergeTrustedProtocolMetadata(options.metadata, input.metadata, input.options?.metadata, input.options?.agentId ? { agentId: input.options.agentId } : undefined, input.options?.locale ? { locale: input.options.locale } : undefined, input.options?.mode ? { mode: input.options.mode } : undefined, isRecoveryRetry ? { agentNativeInternalContinuation: true } : undefined);
|
|
1856
1862
|
const session = await getSession(input.threadId, turnMetadata);
|
|
1857
1863
|
const messages = input.messages.map(protocolMessageToRuntimeMessage);
|
|
1864
|
+
const attachments = latestUserMessage?.parts.flatMap((part) => part.type === "file"
|
|
1865
|
+
? [
|
|
1866
|
+
{
|
|
1867
|
+
name: part.name,
|
|
1868
|
+
...(part.fileId ? { id: part.fileId } : {}),
|
|
1869
|
+
...(part.mediaType ? { mediaType: part.mediaType } : {}),
|
|
1870
|
+
...(part.url ? { url: part.url } : {}),
|
|
1871
|
+
},
|
|
1872
|
+
]
|
|
1873
|
+
: []) ?? [];
|
|
1858
1874
|
const turn = await session.startTurn({
|
|
1859
1875
|
prompt: latestUserPrompt(input.messages),
|
|
1860
1876
|
messages,
|
|
1877
|
+
...(attachments.length ? { attachments } : {}),
|
|
1861
1878
|
model: input.options?.model,
|
|
1862
1879
|
reasoningEffort: input.options?.reasoningEffort,
|
|
1863
1880
|
temperature: input.options?.temperature,
|
|
@@ -22,6 +22,7 @@ export declare function runErrorHeadline(info: RunErrorInfo, labels?: {
|
|
|
22
22
|
}): string;
|
|
23
23
|
export declare function getRequestModeMetadata(message: unknown): "act" | "plan" | null;
|
|
24
24
|
export declare function isBuilderReconnectRunError(info: RunErrorInfo): boolean;
|
|
25
|
+
export declare function isMissingLlmProviderRunError(info: RunErrorInfo): boolean;
|
|
25
26
|
export declare function BuilderConnectCta({ variant, onConnected, reconnect, }: {
|
|
26
27
|
variant?: "primary" | "compact";
|
|
27
28
|
onConnected?: () => void;
|
|
@@ -119,7 +119,7 @@ function isConnectionRecoveryRunError(info) {
|
|
|
119
119
|
message.includes("connection kept failing") ||
|
|
120
120
|
message.includes("automatic recovery attempts"));
|
|
121
121
|
}
|
|
122
|
-
function isMissingLlmProviderRunError(info) {
|
|
122
|
+
export function isMissingLlmProviderRunError(info) {
|
|
123
123
|
const code = (info.errorCode ?? "").toLowerCase();
|
|
124
124
|
const text = [info.message, info.details].filter(Boolean).join("\n");
|
|
125
125
|
const hasCredentialSetupText = /no llm provider(?: key)? (?:is connected|was found)|missing credentials|missing api key|missing_api_key|(?:api[_ -]?key|auth[_ -]?token)\s*(?:(?:is|was)\s+)?(?:not\s+(?:set|configured|available|present|provided|found)|missing|unavailable|empty|unset|unconfigured)/i.test(text);
|