@agent-native/core 0.141.6 → 0.141.7
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/analytics/.agents/skills/dashboard-management/SKILL.md +3 -14
- package/corpus/templates/analytics/.agents/skills/data-querying/SKILL.md +11 -6
- package/corpus/templates/analytics/.agents/skills/prometheus/SKILL.md +5 -5
- package/corpus/templates/analytics/AGENTS.md +2 -2
- package/corpus/templates/analytics/actions/compose-dashboard.ts +1 -1
- package/corpus/templates/analytics/actions/migrate-first-party-analytics-to-bigquery.ts +135 -0
- package/corpus/templates/analytics/actions/navigate.ts +1 -1
- package/corpus/templates/analytics/actions/query-agent-native-analytics.ts +2 -2
- package/corpus/templates/analytics/actions/update-dashboard.ts +0 -1
- package/corpus/templates/analytics/actions/view-screen.ts +0 -20
- package/corpus/templates/analytics/app/components/layout/Header.tsx +0 -1
- package/corpus/templates/analytics/app/hooks/use-navigation-state.ts +5 -5
- package/corpus/templates/analytics/app/i18n-data.ts +2 -90
- package/corpus/templates/analytics/app/pages/Agents.tsx +0 -3
- package/corpus/templates/analytics/app/pages/Settings.tsx +22 -43
- package/corpus/templates/analytics/app/pages/settings/settings-search.ts +23 -20
- package/corpus/templates/analytics/app/routes/extensions._index.tsx +1 -1
- package/corpus/templates/analytics/app/routes/settings.$.tsx +1 -0
- package/corpus/templates/analytics/app/routes/team.tsx +1 -1
- package/corpus/templates/analytics/changelog/2026-08-05-settings-no-longer-includes-an-unnecessary-about-section.md +6 -0
- package/corpus/templates/analytics/docs/schemas/first-party-analytics.md +1 -1
- package/corpus/templates/analytics/scripts/first-party-analytics-bigquery.sql +104 -0
- package/corpus/templates/analytics/server/lib/agent-chat-plan-mode.ts +0 -2
- package/corpus/templates/analytics/server/lib/first-party-analytics-backend.ts +1058 -0
- package/corpus/templates/analytics/server/lib/first-party-analytics-health.ts +34 -15
- package/corpus/templates/analytics/server/lib/first-party-analytics.ts +57 -4
- package/corpus/templates/analytics/server/lib/real-data-actions.ts +1 -3
- package/corpus/templates/analytics/server/plugins/agent-chat.ts +2 -4
- package/corpus/templates/assets/.agents/skills/asset-generation/SKILL.md +8 -6
- package/corpus/templates/assets/.agents/skills/library-management/SKILL.md +16 -1
- package/corpus/templates/assets/AGENTS.md +1 -0
- package/corpus/templates/assets/actions/_helpers.ts +12 -0
- package/corpus/templates/assets/actions/generate-image.ts +9 -3
- package/corpus/templates/assets/actions/import-style-from-url.ts +115 -0
- package/corpus/templates/assets/app/hooks/use-navigation-state.ts +3 -1
- package/corpus/templates/assets/app/routes/extensions._index.tsx +1 -1
- package/corpus/templates/assets/app/routes/settings.$.tsx +1 -0
- package/corpus/templates/assets/app/routes/settings.tsx +5 -0
- package/corpus/templates/assets/app/routes/team.tsx +1 -1
- package/corpus/templates/assets/changelog/2026-08-05-brand-kits-can-import-a-website-s-hydrated-visual-language-a.md +6 -0
- package/corpus/templates/assets/changelog/2026-08-05-generated-images-now-hand-off-embeddable-previews-to-other-w.md +6 -0
- package/corpus/templates/assets/server/lib/generation.ts +58 -0
- package/corpus/templates/assets/shared/api.ts +12 -0
- package/corpus/templates/brain/app/routes/extensions._index.tsx +1 -1
- package/corpus/templates/brain/app/routes/team.tsx +1 -1
- package/corpus/templates/brain/app/routes.ts +1 -1
- package/corpus/templates/calendar/app/components/layout/AppLayout.tsx +3 -1
- package/corpus/templates/calendar/app/routes/_app.extensions._index.tsx +1 -1
- package/corpus/templates/calendar/app/routes/_app.settings.$.tsx +1 -0
- package/corpus/templates/calendar/app/routes/_app.team.tsx +1 -1
- package/corpus/templates/chat/app/components/layout/Layout.tsx +1 -1
- package/corpus/templates/chat/app/hooks/use-navigation-state.ts +1 -1
- package/corpus/templates/chat/app/root.tsx +1 -1
- package/corpus/templates/chat/app/routes/agent.tsx +7 -7
- package/corpus/templates/chat/app/routes/extensions._index.tsx +1 -1
- package/corpus/templates/chat/app/routes/settings.$.tsx +1 -0
- package/corpus/templates/chat/app/routes/team.tsx +1 -1
- package/corpus/templates/clips/app/components/library/library-layout.tsx +1 -1
- package/corpus/templates/clips/app/components/player/transcript-panel.tsx +1 -1
- package/corpus/templates/clips/app/components/recorder/storage-setup-card.tsx +1 -1
- package/corpus/templates/clips/app/routes/_app.extensions._index.tsx +1 -1
- package/corpus/templates/clips/app/routes/_app.settings.$.tsx +1 -0
- package/corpus/templates/content/app/routes/_app.extensions._index.tsx +1 -1
- package/corpus/templates/content/app/routes/_app.settings.$.tsx +1 -0
- package/corpus/templates/content/app/routes/_app.team.tsx +1 -1
- package/corpus/templates/content/e2e/global-setup.ts +1 -1
- package/corpus/templates/design/.agents/skills/design-systems/SKILL.md +6 -1
- package/corpus/templates/design/actions/analyze-brand-assets.ts +7 -7
- package/corpus/templates/design/actions/import-from-url.ts +6 -5
- package/corpus/templates/design/app/pages/DesignSystemSetup.tsx +2 -2
- package/corpus/templates/design/app/routes/extensions._index.tsx +1 -1
- package/corpus/templates/design/app/routes/settings.$.tsx +1 -0
- package/corpus/templates/design/app/routes/team.tsx +1 -1
- package/corpus/templates/design/changelog/2026-08-05-website-url-imports-now-capture-hydrated-browser-computed-de.md +6 -0
- package/corpus/templates/design/e2e/global-setup.ts +1 -1
- package/corpus/templates/dispatch/app/hooks/use-navigation-state.ts +1 -1
- package/corpus/templates/dispatch/app/routes/settings.$.tsx +1 -0
- package/corpus/templates/dispatch/app/routes/team.tsx +1 -1
- package/corpus/templates/factory/app/hooks/use-navigation-state.ts +1 -1
- package/corpus/templates/factory/app/routes/extensions._index.tsx +1 -1
- package/corpus/templates/factory/app/routes/settings.$.tsx +1 -0
- package/corpus/templates/factory/app/routes/team.tsx +1 -1
- package/corpus/templates/forms/app/routes/_app.extensions._index.tsx +1 -1
- package/corpus/templates/forms/app/routes/_app.settings.$.tsx +1 -0
- package/corpus/templates/forms/app/routes/_app.team.tsx +1 -1
- package/corpus/templates/forms/shared/navigation.ts +1 -1
- package/corpus/templates/macros/app/routes/extensions._index.tsx +1 -1
- package/corpus/templates/macros/app/routes/settings.$.tsx +1 -0
- package/corpus/templates/macros/app/routes/team.tsx +1 -1
- package/corpus/templates/mail/app/routes/extensions._index.tsx +1 -1
- package/corpus/templates/mail/app/routes/settings.$.tsx +1 -0
- package/corpus/templates/plan/app/hooks/use-navigation-state.ts +1 -1
- package/corpus/templates/plan/app/routes/extensions._index.tsx +1 -1
- package/corpus/templates/plan/app/routes/settings.$.tsx +1 -0
- package/corpus/templates/plan/app/routes/team.tsx +1 -1
- package/corpus/templates/slides/.agents/skills/design-systems/SKILL.md +3 -1
- package/corpus/templates/slides/actions/analyze-brand-assets.ts +7 -7
- package/corpus/templates/slides/actions/import-from-url.ts +6 -6
- package/corpus/templates/slides/app/components/design-system/DesignSystemSetup.tsx +1 -1
- package/corpus/templates/slides/app/components/editor/PromptDialog.tsx +3 -0
- package/corpus/templates/slides/app/components/onboarding/FirstDeckOnboardingFlow.tsx +9 -3
- package/corpus/templates/slides/app/context/DeckContext.tsx +71 -20
- package/corpus/templates/slides/app/global.css +6 -0
- package/corpus/templates/slides/app/lib/create-deck-generation.ts +9 -5
- package/corpus/templates/slides/app/pages/DeckEditor.tsx +17 -0
- package/corpus/templates/slides/app/pages/Index.tsx +16 -5
- package/corpus/templates/slides/app/routes/extensions._index.tsx +1 -1
- package/corpus/templates/slides/app/routes/settings.$.tsx +1 -0
- package/corpus/templates/slides/app/routes/team.tsx +1 -1
- package/corpus/templates/slides/changelog/2026-08-05-failed-deck-creation-and-reference-uploads-now-recover-clean.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-05-slides-recover-completed-generation-results-after-a-sync-hic.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-05-website-url-imports-now-capture-hydrated-browser-computed-st.md +6 -0
- package/corpus/templates/tasks/app/components/layout/Header.tsx +3 -1
- package/corpus/templates/tasks/app/routes/extensions._index.tsx +1 -1
- package/corpus/templates/tasks/app/routes/settings.$.tsx +1 -0
- package/dist/agent/engine/ai-sdk-engine.js +49 -3
- package/dist/agent/production-agent.d.ts +1 -0
- package/dist/agent/production-agent.js +8 -0
- package/dist/agent/types.d.ts +7 -0
- package/dist/client/agent-chat-adapter.d.ts +1 -1
- package/dist/client/agent-chat-adapter.js +30 -3
- package/dist/client/agent-page/AgentWorkspaceContent.d.ts +1 -1
- package/dist/client/agent-page/AgentWorkspaceContent.js +13 -13
- package/dist/client/chat/run-recovery.js +5 -1
- package/dist/client/embed-auth.js +6 -2
- package/dist/client/error-format.js +12 -0
- package/dist/client/integrations/IntegrationsPanel.js +40 -6
- package/dist/client/org/OrgSwitcher.js +2 -2
- package/dist/client/org/TeamPage.js +92 -72
- package/dist/client/require-session.d.ts +1 -1
- package/dist/client/require-session.js +3 -3
- package/dist/client/resources/use-mcp-servers.d.ts +5 -0
- package/dist/client/resources/use-mcp-servers.js +36 -0
- package/dist/client/settings/AccountSettingsCard.js +40 -35
- package/dist/client/settings/AutomationsSection.js +1 -1
- package/dist/client/settings/DemoModeSection.d.ts +3 -1
- package/dist/client/settings/DemoModeSection.js +4 -1
- package/dist/client/settings/ExtensionsSettingsContent.js +1 -1
- package/dist/client/settings/SchedulingTimezoneField.d.ts +3 -1
- package/dist/client/settings/SchedulingTimezoneField.js +9 -5
- package/dist/client/settings/SettingsPanel.d.ts +4 -1
- package/dist/client/settings/SettingsPanel.js +21 -21
- package/dist/client/settings/SettingsTabsPage.d.ts +2 -2
- package/dist/client/settings/SettingsTabsPage.js +98 -45
- package/dist/client/settings/VoiceTranscriptionSection.js +6 -1
- package/dist/client/settings/useSettingsPanelController.js +47 -8
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/file-upload/actions/upload-image.d.ts +1 -1
- package/dist/ingestion/website.d.ts +30 -0
- package/dist/localization/default-messages.d.ts +5 -0
- package/dist/localization/default-messages.js +5 -0
- package/dist/mcp-client/oauth-routes.js +1 -1
- package/dist/mcp-client/routes.d.ts +1 -0
- package/dist/mcp-client/routes.js +49 -0
- package/dist/navigation/index.js +16 -5
- package/dist/observability/routes.d.ts +5 -5
- package/dist/progress/routes.d.ts +1 -1
- package/dist/provider-api/actions/custom-provider-registration.d.ts +13 -13
- package/dist/provider-api/actions/provider-api.d.ts +11 -11
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/scripts/call-agent.js +11 -0
- package/dist/secrets/routes.d.ts +3 -3
- package/dist/server/auth.js +9 -7
- package/dist/server/identity-sso.js +2 -1
- package/dist/server/onboarding-html.js +57 -34
- package/dist/server/realtime-token.d.ts +1 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/dist/server/workspace-provider-oauth.js +1 -1
- package/dist/setup-connections/onboarding.js +1 -1
- package/dist/shared/index.d.ts +1 -1
- package/dist/shared/index.js +1 -1
- package/dist/shared/sign-in-journey.d.ts +5 -2
- package/dist/shared/sign-in-journey.js +10 -4
- package/dist/templates/chat/app/components/layout/Layout.tsx +1 -1
- package/dist/templates/chat/app/hooks/use-navigation-state.ts +1 -1
- package/dist/templates/chat/app/root.tsx +1 -1
- package/dist/templates/chat/app/routes/agent.tsx +7 -7
- package/dist/templates/chat/app/routes/extensions._index.tsx +1 -1
- package/dist/templates/chat/app/routes/settings.$.tsx +1 -0
- package/dist/templates/chat/app/routes/team.tsx +1 -1
- package/dist/templates/workspace-core/.agents/skills/address-feedback/SKILL.md +37 -6
- package/dist/templates/workspace-core/.agents/skills/authentication/SKILL.md +4 -2
- package/docs/content/authentication.mdx +4 -5
- package/docs/content/template-analytics-developers.mdx +1 -1
- package/docs/content/template-calendar-developers.mdx +1 -1
- package/docs/content/template-chat-developers.mdx +2 -2
- package/docs/content/template-content-developers.mdx +1 -1
- package/docs/content/template-mail-developers.mdx +1 -1
- package/docs/content/template-plan-developers.mdx +1 -1
- package/docs/content/toolkit-command-navigation.mdx +6 -6
- package/docs/content/toolkit-org-team.mdx +1 -1
- package/docs/content/toolkit-settings.mdx +8 -8
- package/docs/content/toolkit-setup-connections.mdx +1 -1
- package/package.json +1 -1
- package/src/templates/chat/app/components/layout/Layout.tsx +1 -1
- package/src/templates/chat/app/hooks/use-navigation-state.ts +1 -1
- package/src/templates/chat/app/root.tsx +1 -1
- package/src/templates/chat/app/routes/agent.tsx +7 -7
- package/src/templates/chat/app/routes/extensions._index.tsx +1 -1
- package/src/templates/chat/app/routes/settings.$.tsx +1 -0
- package/src/templates/chat/app/routes/team.tsx +1 -1
- package/src/templates/workspace-core/.agents/skills/address-feedback/SKILL.md +37 -6
- package/src/templates/workspace-core/.agents/skills/authentication/SKILL.md +4 -2
- package/corpus/templates/analytics/.agents/skills/dashboard-management/references/template-catalog-and-demo.md +0 -62
- package/corpus/templates/analytics/actions/install-dashboard-template.ts +0 -369
- package/corpus/templates/analytics/actions/list-dashboard-templates.ts +0 -47
- package/corpus/templates/analytics/actions/list-native-v2-dashboard-templates.ts +0 -34
- package/corpus/templates/analytics/app/routes/catalog.tsx +0 -240
- package/src/templates/default/actions/navigate.spec.ts +0 -53
|
@@ -138,6 +138,25 @@ export interface Deck {
|
|
|
138
138
|
aspectRatio?: AspectRatio;
|
|
139
139
|
}
|
|
140
140
|
|
|
141
|
+
export type DeckPersistenceResult =
|
|
142
|
+
| { persisted: true }
|
|
143
|
+
| { persisted: false; reason: "request-failed"; error: unknown }
|
|
144
|
+
| { persisted: false; reason: "not-found" };
|
|
145
|
+
|
|
146
|
+
export function describeDeckPersistenceFailure(
|
|
147
|
+
result: DeckPersistenceResult,
|
|
148
|
+
fallback: string,
|
|
149
|
+
): string {
|
|
150
|
+
if (result.persisted || result.reason === "not-found") return fallback;
|
|
151
|
+
if (result.error instanceof Error && result.error.message.trim()) {
|
|
152
|
+
return result.error.message;
|
|
153
|
+
}
|
|
154
|
+
if (typeof result.error === "string" && result.error.trim()) {
|
|
155
|
+
return result.error;
|
|
156
|
+
}
|
|
157
|
+
return fallback;
|
|
158
|
+
}
|
|
159
|
+
|
|
141
160
|
interface DeckContextType {
|
|
142
161
|
decks: Deck[];
|
|
143
162
|
loading: boolean;
|
|
@@ -146,7 +165,7 @@ interface DeckContextType {
|
|
|
146
165
|
title?: string,
|
|
147
166
|
options?: { noDefaultSlides?: boolean; designSystemId?: string | null },
|
|
148
167
|
) => Deck;
|
|
149
|
-
ensureDeckPersisted: (id: string) => Promise<
|
|
168
|
+
ensureDeckPersisted: (id: string) => Promise<DeckPersistenceResult>;
|
|
150
169
|
/**
|
|
151
170
|
* Optimistically duplicate a deck. Inserts a copy into local state with the
|
|
152
171
|
* supplied `newId` immediately so the UI can navigate without awaiting the
|
|
@@ -167,6 +186,7 @@ interface DeckContextType {
|
|
|
167
186
|
) => void;
|
|
168
187
|
reloadDecks: () => Promise<void>;
|
|
169
188
|
reloadDecksWithStatus: () => Promise<DeckReloadStatus>;
|
|
189
|
+
refreshOpenDeck: (deckId: string) => Promise<Deck | null>;
|
|
170
190
|
getDeck: (id: string) => Deck | undefined;
|
|
171
191
|
addSlide: (
|
|
172
192
|
deckId: string,
|
|
@@ -885,7 +905,22 @@ async function fetchDecksForCurrentRoute(): Promise<Deck[] | null> {
|
|
|
885
905
|
}
|
|
886
906
|
|
|
887
907
|
async function deleteDeckFromAPI(id: string): Promise<void> {
|
|
888
|
-
|
|
908
|
+
try {
|
|
909
|
+
await callAction("delete-deck", { id }, { method: "DELETE" });
|
|
910
|
+
} catch (error) {
|
|
911
|
+
// Deleting an optimistic deck is intentionally idempotent. A create can
|
|
912
|
+
// fail after the server committed the row, or before it created one.
|
|
913
|
+
if (
|
|
914
|
+
!(
|
|
915
|
+
error &&
|
|
916
|
+
typeof error === "object" &&
|
|
917
|
+
"status" in error &&
|
|
918
|
+
(error as { status?: unknown }).status === 404
|
|
919
|
+
)
|
|
920
|
+
) {
|
|
921
|
+
throw error;
|
|
922
|
+
}
|
|
923
|
+
}
|
|
889
924
|
}
|
|
890
925
|
|
|
891
926
|
async function createDeckOnAPI(deck: Deck): Promise<void> {
|
|
@@ -1081,7 +1116,7 @@ export function DeckProvider({ children }: { children: ReactNode }) {
|
|
|
1081
1116
|
const deletion = pendingCreate
|
|
1082
1117
|
? pendingCreate.then(
|
|
1083
1118
|
() => deleteDeckFromAPI(deckId),
|
|
1084
|
-
() =>
|
|
1119
|
+
() => deleteDeckFromAPI(deckId),
|
|
1085
1120
|
)
|
|
1086
1121
|
: deleteDeckFromAPI(deckId);
|
|
1087
1122
|
void deletion.catch((err) => {
|
|
@@ -1267,11 +1302,11 @@ export function DeckProvider({ children }: { children: ReactNode }) {
|
|
|
1267
1302
|
// - Dirty deck / unsaved local create → additive merge only: surface
|
|
1268
1303
|
// agent-added slides without ever overwriting or dropping local slides.
|
|
1269
1304
|
const refetchOpenDeckIfChanged = useCallback(
|
|
1270
|
-
async (currentOpenId: string) => {
|
|
1305
|
+
async (currentOpenId: string): Promise<Deck | null> => {
|
|
1271
1306
|
const serverDeck = await fetchDeckFromAPI(currentOpenId);
|
|
1272
1307
|
// Null means 404 (row not created yet), a transient failure, or a
|
|
1273
1308
|
// still-pending create — nothing authoritative to reconcile.
|
|
1274
|
-
if (!serverDeck) return;
|
|
1309
|
+
if (!serverDeck) return null;
|
|
1275
1310
|
const clientDeck = decksRef.current.find((d) => d.id === currentOpenId);
|
|
1276
1311
|
|
|
1277
1312
|
const hasLocalEdits =
|
|
@@ -1281,7 +1316,7 @@ export function DeckProvider({ children }: { children: ReactNode }) {
|
|
|
1281
1316
|
if (hasLocalEdits && clientDeck) {
|
|
1282
1317
|
// Content-preserving: only ADD server slides missing locally.
|
|
1283
1318
|
const merged = mergeServerAddedSlides(clientDeck, serverDeck);
|
|
1284
|
-
if (merged === clientDeck) return; // nothing new to surface
|
|
1319
|
+
if (merged === clientDeck) return serverDeck; // nothing new to surface
|
|
1285
1320
|
lastExternalUpdateRef.current = Date.now();
|
|
1286
1321
|
setDecks((prev) => {
|
|
1287
1322
|
const idx = prev.findIndex((d) => d.id === currentOpenId);
|
|
@@ -1290,16 +1325,17 @@ export function DeckProvider({ children }: { children: ReactNode }) {
|
|
|
1290
1325
|
next[idx] = merged;
|
|
1291
1326
|
return next;
|
|
1292
1327
|
});
|
|
1293
|
-
return;
|
|
1328
|
+
return serverDeck;
|
|
1294
1329
|
}
|
|
1295
1330
|
|
|
1296
1331
|
const changed =
|
|
1297
1332
|
!clientDeck ||
|
|
1298
1333
|
clientDeck.updatedAt !== serverDeck.updatedAt ||
|
|
1299
|
-
clientDeck
|
|
1300
|
-
if (!changed) return;
|
|
1334
|
+
deckContentSignature(clientDeck) !== deckContentSignature(serverDeck);
|
|
1335
|
+
if (!changed) return serverDeck;
|
|
1301
1336
|
lastExternalUpdateRef.current = Date.now();
|
|
1302
1337
|
applyRemoteDeckUpdate(serverDeck);
|
|
1338
|
+
return serverDeck;
|
|
1303
1339
|
},
|
|
1304
1340
|
[applyRemoteDeckUpdate],
|
|
1305
1341
|
);
|
|
@@ -1728,19 +1764,33 @@ export function DeckProvider({ children }: { children: ReactNode }) {
|
|
|
1728
1764
|
[noteLocalCreate, setDecksLocal],
|
|
1729
1765
|
);
|
|
1730
1766
|
|
|
1731
|
-
const ensureDeckPersisted = useCallback(
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1767
|
+
const ensureDeckPersisted = useCallback(
|
|
1768
|
+
async (id: string): Promise<DeckPersistenceResult> => {
|
|
1769
|
+
const pendingCreate = pendingCreatePromisesRef.current.get(id);
|
|
1770
|
+
if (pendingCreate) {
|
|
1771
|
+
try {
|
|
1772
|
+
await pendingCreate;
|
|
1773
|
+
return { persisted: true };
|
|
1774
|
+
} catch (error) {
|
|
1775
|
+
return { persisted: false, reason: "request-failed", error };
|
|
1776
|
+
}
|
|
1739
1777
|
}
|
|
1740
|
-
}
|
|
1741
1778
|
|
|
1742
|
-
|
|
1743
|
-
|
|
1779
|
+
try {
|
|
1780
|
+
const result = await callAction<unknown>(
|
|
1781
|
+
"get-deck",
|
|
1782
|
+
{ id },
|
|
1783
|
+
{ method: "GET" },
|
|
1784
|
+
);
|
|
1785
|
+
return normalizeActionDeck(result)
|
|
1786
|
+
? { persisted: true }
|
|
1787
|
+
: { persisted: false, reason: "not-found" };
|
|
1788
|
+
} catch (error) {
|
|
1789
|
+
return { persisted: false, reason: "request-failed", error };
|
|
1790
|
+
}
|
|
1791
|
+
},
|
|
1792
|
+
[],
|
|
1793
|
+
);
|
|
1744
1794
|
|
|
1745
1795
|
const duplicateDeck = useCallback(
|
|
1746
1796
|
(sourceDeckId: string, newId: string, title?: string): Deck | null => {
|
|
@@ -2150,6 +2200,7 @@ export function DeckProvider({ children }: { children: ReactNode }) {
|
|
|
2150
2200
|
updateDeck,
|
|
2151
2201
|
reloadDecks,
|
|
2152
2202
|
reloadDecksWithStatus,
|
|
2203
|
+
refreshOpenDeck: refetchOpenDeckIfChanged,
|
|
2153
2204
|
getDeck,
|
|
2154
2205
|
addSlide,
|
|
2155
2206
|
updateSlide,
|
|
@@ -14,6 +14,12 @@
|
|
|
14
14
|
|
|
15
15
|
@source "./**/*.{ts,tsx}";
|
|
16
16
|
|
|
17
|
+
/* Keep the editable agent prompt readable even if the generated text utility
|
|
18
|
+
is missing or loses a cascade tie during the hosted build. */
|
|
19
|
+
.agent-composer-root [data-agent-composer-slot="editor-input"] {
|
|
20
|
+
color: hsl(var(--foreground));
|
|
21
|
+
}
|
|
22
|
+
|
|
17
23
|
/* Hide the sidebar's built-in collapsed tab strip — AgentToggleButton in the
|
|
18
24
|
toolbar serves this purpose instead, so we don't want a redundant bar. */
|
|
19
25
|
button[title="Open agent sidebar"] {
|
|
@@ -4,7 +4,7 @@ import { flushSync } from "react-dom";
|
|
|
4
4
|
|
|
5
5
|
import type { NewDeckReferenceSelection } from "@/components/editor/NewDeckReferenceStep";
|
|
6
6
|
import type { UploadedFile } from "@/components/editor/PromptDialog";
|
|
7
|
-
import type { Deck } from "@/context/DeckContext";
|
|
7
|
+
import type { Deck, DeckPersistenceResult } from "@/context/DeckContext";
|
|
8
8
|
import { createDeckAgentMessage } from "@/lib/agent-visible-message";
|
|
9
9
|
|
|
10
10
|
interface DesignSystemGenerationContextResult {
|
|
@@ -150,13 +150,17 @@ export interface StartDeckGenerationOptions {
|
|
|
150
150
|
selectedReferenceDeckId?: string | null;
|
|
151
151
|
designSystems: Array<{ id: string; title: string }>;
|
|
152
152
|
createDeck: CreateDeck;
|
|
153
|
-
ensureDeckPersisted: (id: string) => Promise<
|
|
153
|
+
ensureDeckPersisted: (id: string) => Promise<DeckPersistenceResult>;
|
|
154
154
|
deleteDeck: (id: string) => void;
|
|
155
155
|
navigate: Navigate;
|
|
156
156
|
agentSubmit: SubmitAgent;
|
|
157
157
|
onPromptClosed: () => void;
|
|
158
158
|
onUnauthenticated: (prompt: string, hadFiles: boolean) => void;
|
|
159
|
-
onPersistenceFailure: (
|
|
159
|
+
onPersistenceFailure: (
|
|
160
|
+
prompt: string,
|
|
161
|
+
files: UploadedFile[],
|
|
162
|
+
failure: DeckPersistenceResult,
|
|
163
|
+
) => void;
|
|
160
164
|
}
|
|
161
165
|
|
|
162
166
|
/** Create the optimistic deck, hydrate references, and start the agent run. */
|
|
@@ -214,8 +218,8 @@ export async function startDeckGeneration({
|
|
|
214
218
|
onPromptClosed();
|
|
215
219
|
|
|
216
220
|
const persisted = await ensureDeckPersisted(deck.id);
|
|
217
|
-
if (!persisted) {
|
|
218
|
-
onPersistenceFailure(prompt, filesForGeneration);
|
|
221
|
+
if (!persisted.persisted) {
|
|
222
|
+
onPersistenceFailure(prompt, filesForGeneration, persisted);
|
|
219
223
|
deleteDeck(deckId);
|
|
220
224
|
return "failed";
|
|
221
225
|
}
|
|
@@ -155,6 +155,7 @@ export default function DeckEditor() {
|
|
|
155
155
|
getDeck,
|
|
156
156
|
reloadDecks,
|
|
157
157
|
reloadDecksWithStatus,
|
|
158
|
+
refreshOpenDeck,
|
|
158
159
|
updateDeck,
|
|
159
160
|
updateSlide,
|
|
160
161
|
deleteSlide,
|
|
@@ -396,6 +397,22 @@ export default function DeckEditor() {
|
|
|
396
397
|
}
|
|
397
398
|
}, [refetchOrg, reloadDecks]);
|
|
398
399
|
|
|
400
|
+
// The final generation write can race the last sync event. Pull the
|
|
401
|
+
// authoritative open deck when the run settles so a stale canvas does not
|
|
402
|
+
// require a browser refresh to reveal completed slides.
|
|
403
|
+
useEffect(() => {
|
|
404
|
+
if (
|
|
405
|
+
!id ||
|
|
406
|
+
!shouldClearNewDeckGeneratingState({
|
|
407
|
+
generating,
|
|
408
|
+
generationStarted: newDeckGenerationStarted.current,
|
|
409
|
+
})
|
|
410
|
+
) {
|
|
411
|
+
return;
|
|
412
|
+
}
|
|
413
|
+
void refreshOpenDeck(id);
|
|
414
|
+
}, [generating, id, refreshOpenDeck]);
|
|
415
|
+
|
|
399
416
|
// Clean up the generating URL param/ref when generation completes or when
|
|
400
417
|
// the first slide lands, so partial progress is visible during long decks.
|
|
401
418
|
useEffect(() => {
|
|
@@ -40,7 +40,10 @@ import {
|
|
|
40
40
|
} from "@/components/ui/alert-dialog";
|
|
41
41
|
import { Button } from "@/components/ui/button";
|
|
42
42
|
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group";
|
|
43
|
-
import
|
|
43
|
+
import {
|
|
44
|
+
describeDeckPersistenceFailure,
|
|
45
|
+
type Deck,
|
|
46
|
+
} from "@/context/DeckContext";
|
|
44
47
|
import { useDecks } from "@/context/DeckContext";
|
|
45
48
|
import { useAgentGenerating } from "@/hooks/use-agent-generating";
|
|
46
49
|
import { useDesignSystems } from "@/hooks/use-design-systems";
|
|
@@ -571,14 +574,17 @@ export default function Index() {
|
|
|
571
574
|
setNewDeckPromptOpen(false);
|
|
572
575
|
|
|
573
576
|
const persisted = await ensureDeckPersisted(deck.id);
|
|
574
|
-
if (!persisted) {
|
|
577
|
+
if (!persisted.persisted) {
|
|
575
578
|
if (!savePromptForRetry(prompt)) {
|
|
576
579
|
setNewDeckInitialPrompt({ text: prompt, key: Date.now() });
|
|
577
580
|
}
|
|
578
581
|
setNewDeckRetryFiles(filesForGeneration);
|
|
579
582
|
deleteDeck(deckId);
|
|
580
583
|
toast.error(t("home.generationStartFailed"), {
|
|
581
|
-
description:
|
|
584
|
+
description: describeDeckPersistenceFailure(
|
|
585
|
+
persisted,
|
|
586
|
+
t("home.generationStartFailedDescription"),
|
|
587
|
+
),
|
|
582
588
|
});
|
|
583
589
|
setShowNewDeckPrompt(true);
|
|
584
590
|
return;
|
|
@@ -747,9 +753,14 @@ export default function Index() {
|
|
|
747
753
|
noDefaultSlides: true,
|
|
748
754
|
});
|
|
749
755
|
const persisted = await ensureDeckPersisted(referenceDeck.id);
|
|
750
|
-
if (!persisted) {
|
|
756
|
+
if (!persisted.persisted) {
|
|
751
757
|
deleteDeck(referenceDeck.id);
|
|
752
|
-
throw new Error(
|
|
758
|
+
throw new Error(
|
|
759
|
+
describeDeckPersistenceFailure(
|
|
760
|
+
persisted,
|
|
761
|
+
"The PDF reference deck could not be saved.",
|
|
762
|
+
),
|
|
763
|
+
);
|
|
753
764
|
}
|
|
754
765
|
try {
|
|
755
766
|
const imported = (await callAction("import-file", {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default, meta } from "./settings.js";
|
|
@@ -11,7 +11,9 @@ type Translate = ReturnType<typeof useT>;
|
|
|
11
11
|
|
|
12
12
|
function resolveTitle(t: Translate, pathname: string): string {
|
|
13
13
|
if (pathname === "/tasks") return t("header.pageTasks");
|
|
14
|
-
if (pathname === "/settings"
|
|
14
|
+
if (pathname === "/settings" || pathname.startsWith("/settings/")) {
|
|
15
|
+
return t("header.pageSettings");
|
|
16
|
+
}
|
|
15
17
|
if (pathname === "/team") return t("header.pageTeam");
|
|
16
18
|
if (pathname.startsWith("/extensions")) return t("header.pageExtensions");
|
|
17
19
|
return APP_TITLE;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default, meta } from "./settings.js";
|
|
@@ -193,9 +193,14 @@ class AISDKEngine {
|
|
|
193
193
|
// `builder-engine` and `anthropic-engine` already fail closed here; this
|
|
194
194
|
// engine was the only one that did not.
|
|
195
195
|
//
|
|
196
|
-
// A
|
|
197
|
-
// legitimately accept unauthenticated requests.
|
|
198
|
-
|
|
196
|
+
// A LOCAL `baseUrl` is exempt: a self-hosted gateway on the same machine or
|
|
197
|
+
// private network may legitimately accept unauthenticated requests. A public
|
|
198
|
+
// one may not — every hosted provider requires a key, so exempting any
|
|
199
|
+
// baseUrl at all reopened the same doomed unauthenticated request this
|
|
200
|
+
// guard exists to stop, just for anyone pointing at a remote gateway.
|
|
201
|
+
if (!this.apiKey &&
|
|
202
|
+
!isLocalBaseUrl(this.baseUrl) &&
|
|
203
|
+
this.requiredEnvVars.length > 0) {
|
|
199
204
|
yield {
|
|
200
205
|
type: "stop",
|
|
201
206
|
reason: "error",
|
|
@@ -531,6 +536,47 @@ async function importProviderPackage(provider) {
|
|
|
531
536
|
return import("ai-sdk-ollama");
|
|
532
537
|
}
|
|
533
538
|
}
|
|
539
|
+
/**
|
|
540
|
+
* True only for a gateway on this machine or a private network — the case the
|
|
541
|
+
* keyless exemption was written for. Anything routable on the public internet
|
|
542
|
+
* (openrouter.ai, an api.* host, a cloud proxy) needs credentials, so treating
|
|
543
|
+
* it as keyless just sends a request that cannot succeed.
|
|
544
|
+
*
|
|
545
|
+
* An unparseable value is NOT local: this gates a security-shaped decision, so
|
|
546
|
+
* the ambiguous case has to take the safe branch and require a key.
|
|
547
|
+
*/
|
|
548
|
+
function isLocalBaseUrl(baseUrl) {
|
|
549
|
+
if (!baseUrl)
|
|
550
|
+
return false;
|
|
551
|
+
let host;
|
|
552
|
+
try {
|
|
553
|
+
host = new URL(baseUrl).hostname.toLowerCase();
|
|
554
|
+
}
|
|
555
|
+
catch (error) {
|
|
556
|
+
// An invalid URL is never a local exemption; fail closed.
|
|
557
|
+
if (error instanceof TypeError)
|
|
558
|
+
return false;
|
|
559
|
+
throw error;
|
|
560
|
+
}
|
|
561
|
+
if (host === "localhost" || host.endsWith(".localhost"))
|
|
562
|
+
return true;
|
|
563
|
+
if (host === "::1" || host === "[::1]")
|
|
564
|
+
return true;
|
|
565
|
+
if (host.endsWith(".local") || host.endsWith(".internal"))
|
|
566
|
+
return true;
|
|
567
|
+
// IPv4 loopback and the RFC1918 private ranges.
|
|
568
|
+
const v4 = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/.exec(host);
|
|
569
|
+
if (!v4)
|
|
570
|
+
return false;
|
|
571
|
+
const [a, b] = [Number(v4[1]), Number(v4[2])];
|
|
572
|
+
if (a === 127 || a === 10)
|
|
573
|
+
return true;
|
|
574
|
+
if (a === 192 && b === 168)
|
|
575
|
+
return true;
|
|
576
|
+
if (a === 172 && b >= 16 && b <= 31)
|
|
577
|
+
return true;
|
|
578
|
+
return false;
|
|
579
|
+
}
|
|
534
580
|
function capitalize(s) {
|
|
535
581
|
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
536
582
|
}
|
|
@@ -922,6 +922,7 @@ export interface ChainServerDrivenContinuationDeps {
|
|
|
922
922
|
updateRunStatusIfRunning?: typeof updateRunStatusIfRunning;
|
|
923
923
|
markRunAborted?: typeof markRunAborted;
|
|
924
924
|
setRunTerminalReason?: typeof setRunTerminalReason;
|
|
925
|
+
setRunError?: typeof setRunError;
|
|
925
926
|
recordRunDiagnostic?: typeof recordRunDiagnostic;
|
|
926
927
|
markBackgroundContinuationChunkTerminal?: typeof markBackgroundContinuationChunkTerminal;
|
|
927
928
|
generateRunId?: typeof generateRunId;
|
|
@@ -5271,6 +5271,7 @@ export async function chainServerDrivenContinuation(opts) {
|
|
|
5271
5271
|
updateRunStatusIfRunning: opts.deps?.updateRunStatusIfRunning ?? updateRunStatusIfRunning,
|
|
5272
5272
|
markRunAborted: opts.deps?.markRunAborted ?? markRunAborted,
|
|
5273
5273
|
setRunTerminalReason: opts.deps?.setRunTerminalReason ?? setRunTerminalReason,
|
|
5274
|
+
setRunError: opts.deps?.setRunError ?? setRunError,
|
|
5274
5275
|
recordRunDiagnostic: opts.deps?.recordRunDiagnostic ?? recordRunDiagnostic,
|
|
5275
5276
|
markBackgroundContinuationChunkTerminal: opts.deps?.markBackgroundContinuationChunkTerminal ??
|
|
5276
5277
|
markBackgroundContinuationChunkTerminal,
|
|
@@ -5545,6 +5546,13 @@ export async function chainServerDrivenContinuation(opts) {
|
|
|
5545
5546
|
await d
|
|
5546
5547
|
.setRunTerminalReason(runId, "background_continuation_dispatch_failed")
|
|
5547
5548
|
.catch(() => { });
|
|
5549
|
+
// Record the cause on the row itself, not only inside diag_stage's JSON.
|
|
5550
|
+
// Without this the run goes terminal with error_code and error_detail
|
|
5551
|
+
// both NULL, so every dashboard and query reads it as a failure with no
|
|
5552
|
+
// known cause and the real message is only findable by parsing a blob.
|
|
5553
|
+
await d
|
|
5554
|
+
.setRunError(runId, "background_continuation_dispatch_failed", chainErr instanceof Error ? chainErr.message : String(chainErr))
|
|
5555
|
+
.catch(() => { });
|
|
5548
5556
|
}
|
|
5549
5557
|
}
|
|
5550
5558
|
}
|
package/dist/agent/types.d.ts
CHANGED
|
@@ -275,6 +275,13 @@ export type AgentChatEvent = {
|
|
|
275
275
|
/** Remote task to resume when status is pending/input-required. */
|
|
276
276
|
taskId?: string;
|
|
277
277
|
durationMs?: number;
|
|
278
|
+
/**
|
|
279
|
+
* Why the call ended, on a terminal status. Already computed for
|
|
280
|
+
* telemetry; without it here the persisted event says only that a
|
|
281
|
+
* cross-app call failed after N ms and never why, so a failed A2A call
|
|
282
|
+
* cannot be diagnosed from the database without a repro.
|
|
283
|
+
*/
|
|
284
|
+
terminalCode?: string;
|
|
278
285
|
} | {
|
|
279
286
|
/**
|
|
280
287
|
* Periodic liveness for an in-flight cross-app A2A call. Emitted by the
|
|
@@ -14,7 +14,7 @@ export type AgentChatSurfaceKind =
|
|
|
14
14
|
/** Chat hosted by Desktop for a local app with explicit code access. */
|
|
15
15
|
| "desktop";
|
|
16
16
|
export declare const BACKGROUND_FOLLOW_IDLE_TIMEOUT_MS = 210000;
|
|
17
|
-
export declare const MAX_FOLLOWED_BACKGROUND_RUNS =
|
|
17
|
+
export declare const MAX_FOLLOWED_BACKGROUND_RUNS = 24;
|
|
18
18
|
export declare const MAX_BACKGROUND_FOLLOW_WALL_TIME_MS: number;
|
|
19
19
|
/**
|
|
20
20
|
* Server truth for "does this run still look alive?", used to keep the client
|
|
@@ -131,8 +131,30 @@ export const BACKGROUND_FOLLOW_IDLE_TIMEOUT_MS = 210_000;
|
|
|
131
131
|
// every poll tick and the follow loop never exits (prod: 26 chained runs over
|
|
132
132
|
// 22 minutes, all error:stale_run, user watching a spinner). These bound the
|
|
133
133
|
// whole turn instead, and an identical repeated failure counts as no progress.
|
|
134
|
-
|
|
135
|
-
|
|
134
|
+
//
|
|
135
|
+
// CLIENT-ABOVE-SERVER INVARIANT (asserted in agent-chat-adapter.spec.ts).
|
|
136
|
+
// These are a backstop for a server that has gone silent in a way the idle
|
|
137
|
+
// timeout misses — NOT the primary limit. They must stay ABOVE the server's
|
|
138
|
+
// own ceilings so the server, which can actually tell progress from looping,
|
|
139
|
+
// always terminates a turn first and writes a truthful terminal reason:
|
|
140
|
+
// BACKGROUND_SOFT_TIMEOUT_CEILING_MS (13 min, run-manager.ts) — one chunk
|
|
141
|
+
// MAX_TURN_WALL_CLOCK_MS (90 min, production-agent.ts) — one turn
|
|
142
|
+
// MAX_BACKGROUND_RUN_CONTINUATIONS (20, production-agent.ts)
|
|
143
|
+
//
|
|
144
|
+
// They were originally set to 10 min / 6 runs, which put the whole-turn client
|
|
145
|
+
// budget BELOW the 13-minute ceiling of a single legal chunk. Any turn needing
|
|
146
|
+
// a second full-length chunk was killed by the client while the server was
|
|
147
|
+
// healthy and had 80 minutes left — measured in prod as turns dying at 11-25
|
|
148
|
+
// minutes with `last_progress_at` tracking the abort, i.e. still streaming
|
|
149
|
+
// tokens and completing tools when the client gave up. That is the top
|
|
150
|
+
// non-auth cause of "the chat just stopped" reports.
|
|
151
|
+
//
|
|
152
|
+
// Killing a turn that is NOT progressing is already covered twice over, by
|
|
153
|
+
// mechanisms that read progress rather than a clock: the 210s idle timeout
|
|
154
|
+
// above, and MAX_REPEATED_BACKGROUND_TERMINAL_REASONS below. Do not re-tighten
|
|
155
|
+
// these two to catch a stuck turn — fix the progress signal instead.
|
|
156
|
+
export const MAX_FOLLOWED_BACKGROUND_RUNS = 24;
|
|
157
|
+
export const MAX_BACKGROUND_FOLLOW_WALL_TIME_MS = 95 * 60_000;
|
|
136
158
|
const MAX_REPEATED_BACKGROUND_TERMINAL_REASONS = 3;
|
|
137
159
|
// A re-observed terminal run whose outcome would be an ERROR (never a
|
|
138
160
|
// genuine "done" success) gets a short extra grace window before the follow
|
|
@@ -2185,7 +2207,12 @@ export function createAgentChatAdapter(options) {
|
|
|
2185
2207
|
if (Date.now() - followStartedAt >=
|
|
2186
2208
|
MAX_BACKGROUND_FOLLOW_WALL_TIME_MS) {
|
|
2187
2209
|
yield* stopBackgroundTurnBeforeReporting({
|
|
2188
|
-
|
|
2210
|
+
// Says only what this backstop actually knows. It fires on a
|
|
2211
|
+
// clock, so it cannot tell a looping turn from one that was
|
|
2212
|
+
// still working — the old copy asserted "kept restarting
|
|
2213
|
+
// without finishing", which prod runs contradicted: they were
|
|
2214
|
+
// streaming tokens right up to the abort.
|
|
2215
|
+
message: `This turn ran for ${Math.round(MAX_BACKGROUND_FOLLOW_WALL_TIME_MS / 60_000)} minutes without finishing, so it was stopped. Your chat context is preserved — retrying, or splitting this into smaller requests, usually gets through.`,
|
|
2189
2216
|
errorCode: "background_follow_time_budget_exhausted",
|
|
2190
2217
|
details: `followed_runs: ${followedRunIds.size}`,
|
|
2191
2218
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type ReactNode } from "react";
|
|
2
|
-
export type AgentWorkspaceTab = "overview" | "resources" | "automations" | "agents"
|
|
2
|
+
export type AgentWorkspaceTab = "overview" | "resources" | "automations" | "agents";
|
|
3
3
|
export declare function AgentWorkspaceContent({ overview, className, activeTab, }: {
|
|
4
4
|
overview: ReactNode;
|
|
5
5
|
activeTab: AgentWorkspaceTab;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { IconBook2, IconBolt, IconChecklist, IconFolder, IconHierarchy2, IconHistory, IconNotes,
|
|
2
|
+
import { IconBook2, IconBolt, IconChecklist, IconFolder, IconHierarchy2, IconHistory, IconNotes, IconTopologyRing2, } from "@tabler/icons-react";
|
|
3
3
|
import { lazy, Suspense, useEffect, useState } from "react";
|
|
4
4
|
import { AgentsSection } from "../settings/AgentsSection.js";
|
|
5
5
|
import { cn } from "../utils.js";
|
|
@@ -21,7 +21,6 @@ const HUB_TABS = [
|
|
|
21
21
|
{ id: "resources", label: "Resources", icon: IconFolder },
|
|
22
22
|
{ id: "automations", label: "Automations", icon: IconBolt },
|
|
23
23
|
{ id: "agents", label: "Connected agents", icon: IconTopologyRing2 },
|
|
24
|
-
{ id: "access", label: "Access", icon: IconShieldLock },
|
|
25
24
|
];
|
|
26
25
|
const RESOURCE_IDS = new Set(RESOURCE_TABS.map((tab) => tab.id));
|
|
27
26
|
function normalizeHash(value) {
|
|
@@ -31,9 +30,15 @@ function initialHubState() {
|
|
|
31
30
|
if (typeof window === "undefined") {
|
|
32
31
|
return { tab: "overview", resource: "files" };
|
|
33
32
|
}
|
|
33
|
+
const pathParts = window.location.pathname.split("/").filter(Boolean);
|
|
34
|
+
const settingsIndex = pathParts.indexOf("settings");
|
|
35
|
+
const settingsPath = settingsIndex === -1 ? [] : pathParts.slice(settingsIndex + 1);
|
|
36
|
+
const routeParts = settingsPath[0] === "agent" ? settingsPath : ["agent", ...settingsPath];
|
|
34
37
|
const hash = normalizeHash(window.location.hash);
|
|
35
|
-
const
|
|
36
|
-
const
|
|
38
|
+
const hashParts = hash.split(":");
|
|
39
|
+
const pathScoped = settingsPath[0] === "agent";
|
|
40
|
+
const scoped = pathScoped || hashParts[0] === "agent";
|
|
41
|
+
const parts = pathScoped ? routeParts : hashParts;
|
|
37
42
|
const requested = scoped ? parts[1] : hash;
|
|
38
43
|
const resource = scoped && RESOURCE_IDS.has(parts[2])
|
|
39
44
|
? parts[2]
|
|
@@ -54,8 +59,6 @@ function initialHubState() {
|
|
|
54
59
|
requested === "remote-agents") {
|
|
55
60
|
return { tab: "agents", resource };
|
|
56
61
|
}
|
|
57
|
-
if (requested === "access")
|
|
58
|
-
return { tab: "access", resource };
|
|
59
62
|
return { tab: "overview", resource };
|
|
60
63
|
}
|
|
61
64
|
function ResourceContent({ resource }) {
|
|
@@ -65,8 +68,8 @@ function ResourceContent({ resource }) {
|
|
|
65
68
|
const selected = tab.id === resource;
|
|
66
69
|
return (_jsxs("button", { type: "button", onClick: () => {
|
|
67
70
|
if (typeof window !== "undefined") {
|
|
68
|
-
window.history.pushState(null, "",
|
|
69
|
-
window.dispatchEvent(new Event("
|
|
71
|
+
window.history.pushState(null, "", `/settings/agent/resources/${tab.id}${window.location.search}`);
|
|
72
|
+
window.dispatchEvent(new Event("popstate"));
|
|
70
73
|
}
|
|
71
74
|
}, className: cn("inline-flex shrink-0 items-center gap-1.5 rounded-md px-2.5 py-1.5 text-xs font-medium transition-colors", selected
|
|
72
75
|
? "bg-accent text-foreground"
|
|
@@ -75,9 +78,6 @@ function ResourceContent({ resource }) {
|
|
|
75
78
|
? "Add context the agent can use across conversations."
|
|
76
79
|
: "Manage the resources that shape how the agent works." })] }), _jsx(Suspense, { fallback: _jsx("div", { className: "h-48 animate-pulse rounded-xl border border-border bg-muted/20" }), children: _jsx(ResourcesPanel, { showMcpServers: false, resourceFilter: resource, resourceTreeVariant: "collection", scope: "personal" }, resource) })] }));
|
|
77
80
|
}
|
|
78
|
-
function AccessContent() {
|
|
79
|
-
return (_jsx("div", { children: _jsx("div", { className: "rounded-xl border border-border/70 bg-card text-card-foreground", children: _jsx("div", { className: "px-5 py-5 sm:px-6", children: _jsxs("div", { className: "flex items-start gap-3", children: [_jsx("span", { className: "flex size-9 shrink-0 items-center justify-center rounded-lg border border-border bg-background text-muted-foreground", children: _jsx(IconShieldLock, { className: "size-4" }) }), _jsxs("div", { className: "min-w-0", children: [_jsx("p", { className: "text-sm font-medium text-foreground", children: "Agent access" }), _jsx("p", { className: "mt-1 text-sm leading-5 text-muted-foreground", children: "Use the agent card and MCP endpoints from connected clients." })] })] }) }) }) }));
|
|
80
|
-
}
|
|
81
81
|
export function AgentWorkspaceContent({ overview, className, activeTab, }) {
|
|
82
82
|
const [{ resource }, setState] = useState(initialHubState);
|
|
83
83
|
useEffect(() => {
|
|
@@ -98,8 +98,8 @@ export function AgentWorkspaceContent({ overview, className, activeTab, }) {
|
|
|
98
98
|
? "Schedule and manage agent tasks."
|
|
99
99
|
: activeTab === "agents"
|
|
100
100
|
? "Connect agents to delegate work from chat."
|
|
101
|
-
: "
|
|
102
|
-
return (_jsxs("div", { className: cn("w-full space-y-6", className), children: [_jsxs("header", { className: "space-y-1", children: [_jsx("h1", { className: "text-2xl font-semibold tracking-tight text-foreground", children: activeTab === "overview" ? "Agent" : page?.label }), _jsx("p", { className: "text-sm leading-5 text-muted-foreground", children: pageDescription })] }), activeTab === "overview" && overview, activeTab === "resources" && _jsx(ResourceContent, { resource: resource }), activeTab === "automations" && (_jsx(Suspense, { fallback: _jsx("div", { className: "h-48 animate-pulse rounded-xl border border-border bg-muted/20" }), children: _jsx(AgentJobsTab, { scope: "user", canManageOrg: true, hideHeader: true }) })), activeTab === "agents" && _jsx(AgentsSection, {})
|
|
101
|
+
: "Configure how your agent works, what it knows, and what it can do.";
|
|
102
|
+
return (_jsxs("div", { className: cn("w-full space-y-6", className), children: [_jsxs("header", { className: "space-y-1", children: [_jsx("h1", { className: "text-2xl font-semibold tracking-tight text-foreground", children: activeTab === "overview" ? "Agent" : page?.label }), _jsx("p", { className: "text-sm leading-5 text-muted-foreground", children: pageDescription })] }), activeTab === "overview" && overview, activeTab === "resources" && _jsx(ResourceContent, { resource: resource }), activeTab === "automations" && (_jsx(Suspense, { fallback: _jsx("div", { className: "h-48 animate-pulse rounded-xl border border-border bg-muted/20" }), children: _jsx(AgentJobsTab, { scope: "user", canManageOrg: true, hideHeader: true }) })), activeTab === "agents" && _jsx(AgentsSection, {})] }));
|
|
103
103
|
}
|
|
104
104
|
export function agentWorkspaceTabHash(tab) {
|
|
105
105
|
return `agent:${tab}`;
|
|
@@ -227,7 +227,11 @@ export function RunErrorRecoveryCard({ info, onContinue, onRetry, onFork, onDism
|
|
|
227
227
|
const canRecover = info.recoverable === true;
|
|
228
228
|
const shouldShowBuilderReconnect = isBuilderReconnectRunError(info);
|
|
229
229
|
const isProviderAuthError = isProviderAuthenticationError([info.message, info.details].filter(Boolean).join("\n"), info.errorCode);
|
|
230
|
-
|
|
230
|
+
// Blocked on something the reader goes and fixes elsewhere, then comes back
|
|
231
|
+
// to. Without a retry the card is a dead end and its own copy ("then retry")
|
|
232
|
+
// points at a button that isn't there.
|
|
233
|
+
const isUnblockableExternally = info.errorCode === "email_verification_required";
|
|
234
|
+
const canRetry = canRecover || isProviderAuthError || isUnblockableExternally;
|
|
231
235
|
const builderReconnectResolved = shouldShowBuilderReconnect &&
|
|
232
236
|
builderReconnect.hasFetchedStatus &&
|
|
233
237
|
builderReconnect.configured;
|