@agent-native/core 0.161.23 → 0.163.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/corpus/README.md +1 -1
- package/corpus/templates/analytics/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/analytics/.agents/skills/sharing/SKILL.md +27 -2
- package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +18 -2
- package/corpus/templates/assets/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/assets/.agents/skills/sharing/SKILL.md +27 -2
- package/corpus/templates/brain/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/brain/.agents/skills/sharing/SKILL.md +27 -2
- package/corpus/templates/calendar/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/calendar/.agents/skills/sharing/SKILL.md +27 -2
- package/corpus/templates/calendar/server/handlers/google-auth.ts +1 -8
- package/corpus/templates/chat/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/chat/.agents/skills/sharing/SKILL.md +27 -2
- package/corpus/templates/clips/app/components/recorder/pre-record-panel.tsx +88 -35
- package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +36 -1
- package/corpus/templates/clips/app/i18n/en-US.ts +4 -3
- package/corpus/templates/clips/app/lib/camera-composite.ts +15 -1
- package/corpus/templates/clips/changelog/2026-08-18-clips-no-longer-crashes-when-a-camera-bubble-starts-at-a-tin.md +6 -0
- package/corpus/templates/clips/desktop/src/app.tsx +30 -40
- package/corpus/templates/clips/desktop/src/components/MicOffConfirmation.tsx +47 -0
- package/corpus/templates/clips/desktop/src/styles.css +110 -0
- package/corpus/templates/clips/desktop/src-tauri/src/whisper_speech.rs +114 -7
- package/corpus/templates/clips/shared/recording-capture.ts +18 -13
- package/corpus/templates/content/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/content/.agents/skills/sharing/SKILL.md +27 -2
- package/corpus/templates/content/actions/create-content-database.ts +1 -1
- package/corpus/templates/content/actions/create-document.ts +1 -1
- package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +3 -5
- package/corpus/templates/content/app/components/editor/DocumentToolbar.tsx +0 -3
- package/corpus/templates/content/app/components/editor/NotionConflictBanner.tsx +0 -4
- package/corpus/templates/content/app/components/editor/NotionSyncBar.tsx +4 -1
- package/corpus/templates/content/app/hooks/use-notion.ts +17 -15
- package/corpus/templates/crm/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/crm/.agents/skills/sharing/SKILL.md +27 -2
- package/corpus/templates/design/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/design/.agents/skills/sharing/SKILL.md +27 -2
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +6 -1
- package/corpus/templates/dispatch/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/dispatch/.agents/skills/sharing/SKILL.md +27 -2
- package/corpus/templates/factory/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/factory/.agents/skills/sharing/SKILL.md +27 -2
- package/corpus/templates/forms/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/forms/.agents/skills/sharing/SKILL.md +27 -2
- package/corpus/templates/macros/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/macros/.agents/skills/sharing/SKILL.md +27 -2
- package/corpus/templates/mail/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/mail/.agents/skills/sharing/SKILL.md +27 -2
- package/corpus/templates/mail/app/components/layout/AppLayout.tsx +18 -3
- package/corpus/templates/mail/server/handlers/google-auth.ts +1 -8
- package/corpus/templates/plan/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/plan/.agents/skills/sharing/SKILL.md +27 -2
- package/corpus/templates/slides/.agents/skills/create-deck/SKILL.md +4 -0
- package/corpus/templates/slides/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/slides/.agents/skills/sharing/SKILL.md +27 -2
- package/corpus/templates/slides/actions/_await-fit-check.ts +30 -5
- package/corpus/templates/slides/actions/add-slide.ts +6 -2
- package/corpus/templates/slides/actions/create-deck.ts +2 -1
- package/corpus/templates/slides/app/components/editor/GoogleDriveConnectionCta.tsx +3 -3
- package/corpus/templates/slides/app/components/editor/GoogleSlidesReferenceImport.tsx +3 -3
- package/corpus/templates/slides/app/components/editor/PromptDialog.tsx +3 -1
- package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +1 -1
- package/corpus/templates/slides/app/components/editor/slide-object-interactions.ts +1 -1
- package/corpus/templates/slides/app/lib/create-deck-generation.ts +1 -0
- package/corpus/templates/slides/app/pages/DeckEditor.tsx +35 -2
- package/corpus/templates/slides/app/routes/p.$id.tsx +3 -1
- package/corpus/templates/slides/changelog/2026-08-18-generated-slides-preserve-speaker-notes.md +6 -0
- package/corpus/templates/slides/server/handlers/assets.ts +23 -12
- package/corpus/templates/slides/server/handlers/design-system-decode-job-status.ts +15 -6
- package/corpus/templates/slides/server/handlers/design-system-upload-start.ts +15 -6
- package/corpus/templates/slides/server/handlers/index-design-system-sources.ts +34 -19
- package/corpus/templates/slides/server/handlers/request-auth-context.ts +1 -0
- package/corpus/templates/slides/server/handlers/share.ts +1 -1
- package/corpus/templates/slides/server/plugins/agent-chat.ts +1 -1
- package/corpus/templates/slides/server/routes/api/deck-agent-context.json.get.ts +1 -1
- package/corpus/templates/slides/server/routes/api/exports/[filename].get.ts +9 -3
- package/corpus/templates/slides/server/routes/api/exports/google-slides.post.ts +12 -5
- package/corpus/templates/slides/server/routes/api/exports/html.post.ts +9 -7
- package/corpus/templates/slides/server/routes/api/exports/pptx.post.ts +9 -7
- package/corpus/templates/slides/shared/api.ts +7 -1
- package/corpus/templates/tasks/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/tasks/.agents/skills/sharing/SKILL.md +27 -2
- package/dist/agent/engine/translate-anthropic.js +27 -2
- package/dist/agent/production-agent.d.ts +2 -2
- package/dist/agent/production-agent.js +16 -8
- package/dist/agent/thread-data-builder.d.ts +1 -0
- package/dist/agent/thread-data-builder.js +6 -4
- package/dist/agent/tool-approval-store.d.ts +10 -1
- package/dist/agent/tool-approval-store.js +19 -2
- package/dist/agent/types.d.ts +9 -0
- package/dist/app-config/schema.d.ts +1 -0
- package/dist/app-config/workspace.d.ts +1 -0
- package/dist/app-config/workspace.js +8 -0
- package/dist/chat-threads/schema.d.ts +2 -2
- package/dist/client/AssistantChat.js +14 -6
- package/dist/client/EnvironmentBadge.d.ts +15 -0
- package/dist/client/EnvironmentBadge.js +79 -0
- package/dist/client/MultiTabAssistantChat.js +73 -17
- package/dist/client/agent-chat-adapter.js +11 -1
- package/dist/client/api-path.js +14 -1
- package/dist/client/app-providers.js +2 -1
- package/dist/client/chat/tool-call-display.d.ts +12 -2
- package/dist/client/chat/tool-call-display.js +17 -7
- package/dist/client/chat/widgets/WorkspaceFileWidget.js +1 -1
- package/dist/client/chat/widgets/builtin-tool-renderers.d.ts +6 -0
- package/dist/client/chat/widgets/builtin-tool-renderers.js +19 -0
- package/dist/client/onboarding/FirstRunOnboarding.js +46 -32
- package/dist/client/onboarding/use-onboarding.d.ts +8 -1
- package/dist/client/onboarding/use-onboarding.js +22 -7
- package/dist/client/org/TeamPage.js +15 -2
- package/dist/client/org/hooks.d.ts +2 -0
- package/dist/client/org/hooks.js +12 -0
- package/dist/client/org/index.d.ts +2 -2
- package/dist/client/org/index.js +1 -1
- package/dist/client/session-replay.js +58 -15
- package/dist/client/settings/SettingsTabsPage.js +19 -6
- package/dist/client/sharing/ShareButton.js +43 -18
- package/dist/client/sharing/useShareButtonController.d.ts +12 -2
- package/dist/client/sharing/useShareButtonController.js +38 -8
- package/dist/client/sse-event-processor.d.ts +7 -0
- package/dist/client/sse-event-processor.js +4 -1
- package/dist/client/ui/index.d.ts +1 -0
- package/dist/client/ui/index.js +1 -0
- package/dist/client/use-action.js +26 -0
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/config.d.ts +15 -0
- package/dist/config.js +53 -0
- package/dist/dashboard-storage/schema.d.ts +2 -2
- package/dist/data-programs/schema.d.ts +2 -2
- package/dist/extensions/fetch-tool.js +8 -2
- package/dist/extensions/schema.d.ts +2 -2
- package/dist/extensions/store.js +3 -0
- 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/localization/default-messages.d.ts +4 -0
- package/dist/localization/default-messages.js +4 -0
- package/dist/mcp/embed-app.js +1 -1
- package/dist/notifications/routes.d.ts +1 -1
- package/dist/org/handlers.d.ts +6 -1
- package/dist/org/handlers.js +43 -0
- package/dist/org/index.d.ts +3 -3
- package/dist/org/index.js +2 -2
- package/dist/org/migrations.js +33 -0
- package/dist/org/plugin.js +10 -1
- package/dist/org/schema.d.ts +315 -0
- package/dist/org/schema.js +20 -1
- package/dist/org/types.d.ts +3 -0
- package/dist/org/workspace-app-access.d.ts +10 -0
- package/dist/org/workspace-app-access.js +179 -0
- package/dist/progress/routes.d.ts +1 -1
- package/dist/provider-api/actions/custom-provider-registration.d.ts +7 -7
- package/dist/provider-api/actions/provider-api.d.ts +7 -7
- package/dist/provider-api/index.d.ts +10 -0
- package/dist/provider-api/index.js +45 -9
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/secrets/routes.d.ts +9 -9
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/auth.js +24 -4
- package/dist/server/poll.js +13 -3
- package/dist/server/sentry.d.ts +1 -1
- package/dist/sharing/access.d.ts +2 -2
- package/dist/sharing/access.js +56 -3
- package/dist/sharing/actions/list-resource-shares.d.ts +2 -0
- package/dist/sharing/actions/list-resource-shares.js +26 -1
- package/dist/sharing/actions/share-resource.d.ts +1 -1
- package/dist/sharing/actions/share-resource.js +23 -4
- package/dist/sharing/actions/unshare-resource.d.ts +1 -1
- package/dist/sharing/actions/unshare-resource.js +1 -1
- package/dist/sharing/registry.d.ts +12 -0
- package/dist/sharing/schema.d.ts +4 -4
- package/dist/sharing/schema.js +2 -2
- package/dist/templates/chat/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/dist/templates/chat/.agents/skills/sharing/SKILL.md +27 -2
- package/dist/templates/default/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/dist/templates/default/.agents/skills/sharing/SKILL.md +27 -2
- package/dist/templates/workspace-core/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/dist/templates/workspace-core/.agents/skills/sharing/SKILL.md +27 -2
- package/dist/vite/client.d.ts +5 -0
- package/dist/vite/client.js +64 -2
- package/dist/workspace-connections/actions/list-workspace-user-groups.d.ts +9 -1
- package/dist/workspace-connections/actions/list-workspace-user-groups.js +9 -4
- package/dist/workspace-connections/groups.d.ts +2 -0
- package/dist/workspace-connections/groups.js +16 -5
- package/dist/workspace-files/actions.d.ts +1 -8
- package/dist/workspace-files/actions.js +5 -21
- package/dist/workspace-files/index.d.ts +1 -1
- package/dist/workspace-files/index.js +1 -1
- package/dist/workspace-files/store.d.ts +18 -0
- package/dist/workspace-files/store.js +24 -3
- package/package.json +3 -3
- package/src/templates/chat/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/src/templates/chat/.agents/skills/sharing/SKILL.md +27 -2
- package/src/templates/default/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/src/templates/default/.agents/skills/sharing/SKILL.md +27 -2
- package/src/templates/workspace-core/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/src/templates/workspace-core/.agents/skills/sharing/SKILL.md +27 -2
|
@@ -65,7 +65,17 @@ const MAX_HISTORY_ATTACHMENT_CHARS = 60_000;
|
|
|
65
65
|
// the trailing truncation notice still makes a pathological multi-MB paste
|
|
66
66
|
// visibly (not silently) capped.
|
|
67
67
|
const MAX_OUTBOUND_ATTACHMENT_CHARS = 200_000;
|
|
68
|
-
|
|
68
|
+
// An array-length backstop, NOT the reduction policy. Reducing a long thread is
|
|
69
|
+
// Observational Memory's job: it folds older turns into observations/reflections
|
|
70
|
+
// and replaces the raw prefix with a memory block plus a recent-raw window
|
|
71
|
+
// (agent/observational-memory/). But its Observer only engages once a thread
|
|
72
|
+
// passes 30k unobserved tokens, and a count cap of 24 bit long before that — so
|
|
73
|
+
// turns were evicted from the request while compaction still had nothing to say
|
|
74
|
+
// about them, and only reached the model again once thread_data was observed a
|
|
75
|
+
// turn or more later. The two char budgets below are the real bound (they cap
|
|
76
|
+
// what a request can carry regardless of message count); this cap only keeps the
|
|
77
|
+
// array from growing without limit.
|
|
78
|
+
const MAX_HISTORY_MESSAGES = 80;
|
|
69
79
|
// Every provider prompt cache matches a byte-identical PREFIX. A window that
|
|
70
80
|
// ends at the newest message and starts MAX_HISTORY_MESSAGES back moves its
|
|
71
81
|
// START by one message per turn, so from the first turn past the cap onward no
|
package/dist/client/api-path.js
CHANGED
|
@@ -48,7 +48,20 @@ function workspacePathBasePath() {
|
|
|
48
48
|
const segment = window.location.pathname.split("/").find(Boolean);
|
|
49
49
|
if (!segment || segment === "_agent-native" || segment === "api")
|
|
50
50
|
return "";
|
|
51
|
-
|
|
51
|
+
const basePath = normalizeBasePath(segment);
|
|
52
|
+
// Guard against treating an app-local route (e.g. a client-rendered
|
|
53
|
+
// "/settings" page reached via stale client-side navigation) as if it
|
|
54
|
+
// were a sibling app's workspace mount — that built URLs like
|
|
55
|
+
// "/settings/_agent-native/builder/connect", which the workspace gateway
|
|
56
|
+
// 404s (no app is mounted at "/settings") into its app-picker page instead
|
|
57
|
+
// of the real target route. Only trust the segment when it matches a
|
|
58
|
+
// known mount from the deployed app manifest; when the manifest can't be
|
|
59
|
+
// read, fall back to the prior blind-trust behavior (e.g. the same build
|
|
60
|
+
// reused across sibling app ids without a manifest).
|
|
61
|
+
const mounts = workspaceAppMountPaths();
|
|
62
|
+
if (mounts && !mounts.has(basePath))
|
|
63
|
+
return "";
|
|
64
|
+
return basePath;
|
|
52
65
|
}
|
|
53
66
|
function externalEmbedTargetBasePath() {
|
|
54
67
|
if (typeof window === "undefined")
|
|
@@ -57,6 +57,7 @@ import { useInRouterContext } from "react-router";
|
|
|
57
57
|
import { isHumanReadableDocumentTitle, normalizeDocumentTitle, } from "../shared/document-title.js";
|
|
58
58
|
import { ClientOnly } from "./ClientOnly.js";
|
|
59
59
|
import { DefaultSpinner } from "./DefaultSpinner.js";
|
|
60
|
+
import { EnvironmentBadge } from "./EnvironmentBadge.js";
|
|
60
61
|
import { AgentNativeI18nProvider, } from "./i18n.js";
|
|
61
62
|
import { FirstRunOnboardingStartupGate } from "./onboarding/first-run-startup-gate.js";
|
|
62
63
|
import { RequireSession } from "./require-session.js";
|
|
@@ -151,5 +152,5 @@ export function AppProviders({ queryClient, isPublicPath = false, clientOnlyFall
|
|
|
151
152
|
if (isPublicPath) {
|
|
152
153
|
return (_jsx(ProvidersInner, { queryClient: queryClient, defaultTheme: defaultTheme, themeAttribute: themeAttribute, tooltipDelayDuration: tooltipDelayDuration, toaster: toaster, disableThemeTransitions: disableThemeTransitions, i18n: i18n, documentTitleFallback: documentTitleFallback, children: children }));
|
|
153
154
|
}
|
|
154
|
-
return (_jsx(ClientOnly, { fallback: fallback, children: _jsx(ProvidersInner, { queryClient: queryClient, defaultTheme: defaultTheme, themeAttribute: themeAttribute, tooltipDelayDuration: tooltipDelayDuration, toaster: toaster, disableThemeTransitions: disableThemeTransitions, i18n: i18n, documentTitleFallback: documentTitleFallback, children: _jsx(RequireSession, { bypass: sessionBypass, fallback: fallback, children: sessionBypass ? (children) : (
|
|
155
|
+
return (_jsx(ClientOnly, { fallback: fallback, children: _jsx(ProvidersInner, { queryClient: queryClient, defaultTheme: defaultTheme, themeAttribute: themeAttribute, tooltipDelayDuration: tooltipDelayDuration, toaster: toaster, disableThemeTransitions: disableThemeTransitions, i18n: i18n, documentTitleFallback: documentTitleFallback, children: _jsx(RequireSession, { bypass: sessionBypass, fallback: fallback, children: sessionBypass ? (children) : (_jsxs(FirstRunOnboardingStartupGate, { children: [children, _jsx(EnvironmentBadge, {})] })) }) }) }));
|
|
155
156
|
}
|
|
@@ -34,9 +34,17 @@ export type ApprovalContextValue = {
|
|
|
34
34
|
* Keep the visible resolution stable while the chat repository refreshes or
|
|
35
35
|
* remounts the message containing this approval card.
|
|
36
36
|
*/
|
|
37
|
-
onApprovalResolved?: (approvalKey: string, resolution: ApprovalResolution, toolCallId?: string
|
|
37
|
+
onApprovalResolved?: (approvalKey: string, resolution: ApprovalResolution, toolCallId?: string,
|
|
38
|
+
/**
|
|
39
|
+
* Identifies the specific `approval_required` ask being resolved. A
|
|
40
|
+
* remount that replays the SAME ask (e.g. a chat repository refresh)
|
|
41
|
+
* omits nothing new here, so the retained resolution still matches; a
|
|
42
|
+
* fresh ask after a failed resume carries a different `askId` and so
|
|
43
|
+
* looks up as unresolved. See `ApprovalAffordance` below.
|
|
44
|
+
*/
|
|
45
|
+
askId?: string) => void;
|
|
38
46
|
/** Read a resolution retained by the owning chat surface. */
|
|
39
|
-
getApprovalResolution?: (approvalKey: string, toolCallId?: string) => ApprovalResolution | null;
|
|
47
|
+
getApprovalResolution?: (approvalKey: string, toolCallId?: string, askId?: string) => ApprovalResolution | null;
|
|
40
48
|
/**
|
|
41
49
|
* Optional host hook invoked in addition to the local "denied" state, e.g.
|
|
42
50
|
* so a Code session can also resolve its own pending approval as denied.
|
|
@@ -97,6 +105,7 @@ export declare function ToolCallDisplay({ toolName, toolCallId, argsText, args,
|
|
|
97
105
|
approval?: {
|
|
98
106
|
approvalKey: string;
|
|
99
107
|
dismissed?: boolean;
|
|
108
|
+
askId?: string;
|
|
100
109
|
};
|
|
101
110
|
repeatCount?: number;
|
|
102
111
|
/** The latest tool shown while the overall chat turn is still active. */
|
|
@@ -113,6 +122,7 @@ export declare function ToolCallFallback({ toolName, toolCallId, args, argsText,
|
|
|
113
122
|
approval?: {
|
|
114
123
|
approvalKey: string;
|
|
115
124
|
dismissed?: boolean;
|
|
125
|
+
askId?: string;
|
|
116
126
|
};
|
|
117
127
|
repeatCount?: number;
|
|
118
128
|
isLatestRunning?: boolean;
|
|
@@ -16,7 +16,7 @@ import { cn } from "../utils.js";
|
|
|
16
16
|
import { ActionChatUiSurface } from "./action-chat-ui-surface.js";
|
|
17
17
|
import { SmoothMarkdownText, HighlightedCodeBlock, } from "./markdown-renderer.js";
|
|
18
18
|
import { resolveToolRenderer } from "./tool-render-registry.js";
|
|
19
|
-
import { isBuiltinDataWidgetActionRenderer, resolveBuiltinActionChatRenderer, resolveBuiltinFallbackToolRenderer, } from "./widgets/builtin-tool-renderers.js";
|
|
19
|
+
import { isBuiltinDataWidgetActionRenderer, isBuiltinWorkspaceFileResult, resolveBuiltinActionChatRenderer, resolveBuiltinFallbackToolRenderer, } from "./widgets/builtin-tool-renderers.js";
|
|
20
20
|
// Exported so AssistantChatInner can provide a context value.
|
|
21
21
|
export const ChatRunningContext = React.createContext(false);
|
|
22
22
|
export const ChatRunningRunIdContext = React.createContext(null);
|
|
@@ -249,7 +249,7 @@ function ApprovalAffordance({ toolName, toolCallId, approval, }) {
|
|
|
249
249
|
const t = useT();
|
|
250
250
|
const ctx = React.useContext(ApprovalContext);
|
|
251
251
|
const [localResolution, setLocalResolution] = useState(null);
|
|
252
|
-
const retainedResolution = ctx?.getApprovalResolution?.(approval.approvalKey, toolCallId) ?? null;
|
|
252
|
+
const retainedResolution = ctx?.getApprovalResolution?.(approval.approvalKey, toolCallId, approval.askId) ?? null;
|
|
253
253
|
const resolution = retainedResolution ??
|
|
254
254
|
localResolution ??
|
|
255
255
|
(approval.dismissed === true ? "denied" : null);
|
|
@@ -266,15 +266,15 @@ function ApprovalAffordance({ toolName, toolCallId, approval, }) {
|
|
|
266
266
|
}
|
|
267
267
|
return (_jsxs("div", { className: "mt-1.5 flex min-w-0 flex-wrap items-center gap-2 rounded-md border border-border bg-muted/40 px-2.5 py-1.5", children: [_jsx(IconShieldCheck, { className: "h-3.5 w-3.5 shrink-0 text-muted-foreground" }), _jsx("span", { className: "min-w-0 flex-1 text-xs text-muted-foreground", children: t("agentChat.approval.question", { tool: toolName }) }), ctx && (_jsxs("button", { type: "button", onClick: () => {
|
|
268
268
|
setLocalResolution("approved");
|
|
269
|
-
ctx.onApprovalResolved?.(approval.approvalKey, "approved", toolCallId);
|
|
269
|
+
ctx.onApprovalResolved?.(approval.approvalKey, "approved", toolCallId, approval.askId);
|
|
270
270
|
ctx.onApprove(approval.approvalKey);
|
|
271
271
|
}, className: cn("inline-flex shrink-0 items-center gap-1 rounded-md px-2.5 py-1 text-xs font-medium transition-colors", "bg-foreground text-background hover:bg-foreground/90"), children: [_jsx(IconCheck, { className: "h-3.5 w-3.5" }), t("agentChat.approval.approve")] })), ctx?.onAlwaysAllow && (_jsxs("button", { type: "button", onClick: () => {
|
|
272
272
|
setLocalResolution("approved");
|
|
273
|
-
ctx.onApprovalResolved?.(approval.approvalKey, "approved", toolCallId);
|
|
273
|
+
ctx.onApprovalResolved?.(approval.approvalKey, "approved", toolCallId, approval.askId);
|
|
274
274
|
ctx.onAlwaysAllow?.(approval.approvalKey);
|
|
275
275
|
}, title: t("agentChat.approval.alwaysAllowHint"), className: cn("inline-flex shrink-0 items-center gap-1 rounded-md border border-border px-2.5 py-1 text-xs font-medium transition-colors", "text-foreground hover:bg-muted"), children: [_jsx(IconShieldCheck, { className: "h-3.5 w-3.5" }), t("agentChat.approval.alwaysAllow")] })), _jsxs("button", { type: "button", onClick: () => {
|
|
276
276
|
setLocalResolution("denied");
|
|
277
|
-
ctx?.onApprovalResolved?.(approval.approvalKey, "denied", toolCallId);
|
|
277
|
+
ctx?.onApprovalResolved?.(approval.approvalKey, "denied", toolCallId, approval.askId);
|
|
278
278
|
ctx?.onDeny?.(approval.approvalKey);
|
|
279
279
|
}, className: cn("inline-flex shrink-0 items-center gap-1 rounded-md border border-border px-2.5 py-1 text-xs font-medium transition-colors", "text-foreground hover:bg-muted"), children: [_jsx(IconX, { className: "h-3.5 w-3.5" }), t("agentChat.approval.deny")] })] }));
|
|
280
280
|
}
|
|
@@ -403,7 +403,8 @@ function ToolCallDisplayGeneric({ toolName, toolCallId, argsText, args, result,
|
|
|
403
403
|
(skipRegistryRenderer ? null : resolveToolRenderer(nativeToolContext)) ??
|
|
404
404
|
resolveBuiltinFallbackToolRenderer(nativeToolContext));
|
|
405
405
|
if (NativeToolRenderer) {
|
|
406
|
-
return (_jsx(ActionChatUiSurface, { context: nativeToolContext, isBuiltinDataWidget: isBuiltinDataWidgetActionRenderer(nativeToolContext)
|
|
406
|
+
return (_jsx(ActionChatUiSurface, { context: nativeToolContext, isBuiltinDataWidget: isBuiltinDataWidgetActionRenderer(nativeToolContext) ||
|
|
407
|
+
isBuiltinWorkspaceFileResult(nativeToolContext), children: _jsx(NativeToolRenderer, { context: nativeToolContext }) }));
|
|
407
408
|
}
|
|
408
409
|
const inputPayload = hasArgs
|
|
409
410
|
? toolInputPayload(toolName, args, {
|
|
@@ -432,7 +433,16 @@ function ToolCallDisplayGeneric({ toolName, toolCallId, argsText, args, result,
|
|
|
432
433
|
}
|
|
433
434
|
return (_jsxs("div", { className: "group/tool my-0.5 w-full overflow-hidden", children: [mcpApp && !(suppressInlineOpenApp && toolName === "open_app") && (_jsx(McpAppRenderer, { app: mcpApp, className: "mb-1.5" })), _jsxs("button", { type: "button", onClick: () => canExpand && setExpanded(!isExpanded), "aria-expanded": canExpand ? isExpanded : undefined, className: cn("flex w-full items-center gap-1.5 rounded-md py-0.5 text-left text-[13px] text-muted-foreground transition-colors", canExpand && "hover:text-foreground", isRunning && "text-muted-foreground"), children: [_jsx("span", { className: "relative flex size-4 shrink-0 items-center justify-center", children: isRunning ? (_jsx(IconLoader2, { className: "size-3.5 animate-spin" })) : isAgentError ? (_jsx(IconCircleX, { className: "size-3.5 text-destructive" })) : isUnknownOutcome ? (_jsx(IconAlertTriangle, { className: "size-3.5 text-muted-foreground" })) : (_jsxs(_Fragment, { children: [_jsx(ToolIcon, { className: cn("size-3.5 transition-opacity", canExpand && "group-hover/tool:opacity-0") }), canExpand && (_jsx(IconChevronRight, { className: cn("absolute size-3.5 opacity-0 transition-[opacity,transform] group-hover/tool:opacity-100", isExpanded && "rotate-90") }))] })) }), _jsx("span", { className: cn("min-w-0 truncate font-normal", isActiveTail && "agent-running-shimmer"), children: displayName }), repeatCount && repeatCount > 1 && (_jsxs("span", { className: "shrink-0 rounded border border-border/60 px-1.5 py-0.5 text-[10px] leading-none text-muted-foreground", title: t("agentChat.tool.repeated", { count: repeatCount }), children: [repeatCount, "x"] }))] }), _jsx(AnimatedCollapse, { open: isExpanded && !isAgentCall && (hasArgs || result !== undefined), children: _jsxs("div", { className: "mt-1 space-y-2 pl-5", children: [inputPayload && (_jsx(SimpleCodeViewer, { text: inputPayload.text, lang: inputPayload.lang })), resultPayload && (_jsx(ToolOutputPopover, { open: outputOpen, onOpenChange: setOutputOpen, title: outputTitle, payload: resultPayload, children: _jsx("button", { type: "button", "aria-label": t("agentChat.tool.viewOutput", {
|
|
434
435
|
tool: toolName,
|
|
435
|
-
}), className: "inline-flex size-6 items-center justify-center rounded-md text-muted-foreground/70 transition-colors hover:bg-accent hover:text-foreground", children: _jsx(IconCode, { className: "size-3.5" }) }) }))] }) }), isUnknownOutcome && (_jsx("p", { role: "status", className: "ps-5 text-xs text-muted-foreground", children: t("agentChat.tool.interrupted") })), approval && (_jsx(ApprovalAffordance
|
|
436
|
+
}), className: "inline-flex size-6 items-center justify-center rounded-md text-muted-foreground/70 transition-colors hover:bg-accent hover:text-foreground", children: _jsx(IconCode, { className: "size-3.5" }) }) }))] }) }), isUnknownOutcome && (_jsx("p", { role: "status", className: "ps-5 text-xs text-muted-foreground", children: t("agentChat.tool.interrupted") })), approval && (_jsx(ApprovalAffordance
|
|
437
|
+
// A changed `askId` means the server re-emitted approval_required
|
|
438
|
+
// for this same call (e.g. a failed resume never consumed the
|
|
439
|
+
// prior grant) rather than the same ask re-rendering. Keying on it
|
|
440
|
+
// forces a fresh mount so a stale local "approved" state from the
|
|
441
|
+
// earlier ask can't linger and hide Approve/Deny with no way to
|
|
442
|
+
// retry. Falls back to approvalKey when askId is absent (older
|
|
443
|
+
// events, non-production-agent approval sources) to keep the
|
|
444
|
+
// existing remount-safe behavior unchanged there.
|
|
445
|
+
, { toolName: toolName, toolCallId: toolCallId, approval: approval }, approval.askId ?? approval.approvalKey))] }));
|
|
436
446
|
}
|
|
437
447
|
function AgentCallCell({ agentName, activity, progress, responseText, isRunning, isError, durationMs, }) {
|
|
438
448
|
const t = useT();
|
|
@@ -29,5 +29,5 @@ export function WorkspaceFileWidget({ result, }) {
|
|
|
29
29
|
const { file } = result;
|
|
30
30
|
const FileIcon = fileIcon(file.contentType);
|
|
31
31
|
const href = resourceDownloadUrl(file.resourceId);
|
|
32
|
-
return (_jsxs("div", { className: "flex items-center gap-3", children: [_jsx("div", { className: "flex size-10 shrink-0 items-center justify-center rounded-md bg-muted text-muted-foreground", children: _jsx(FileIcon, { className: "size-5", "aria-hidden": "true" }) }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("div", { className: "truncate text-sm font-medium", children: file.name }), _jsxs("div", { className: "truncate text-xs text-muted-foreground", children: [formatFileSize(file.sizeBytes, formatNumber), " \u00B7 ", file.path] })] }), _jsxs("a", { href: href, download: file.name, className: "inline-flex shrink-0 items-center gap-1.5 rounded-md bg-primary px-3 py-1.5 text-xs font-medium text-primary-foreground no-underline transition-colors hover:bg-primary/90 hover:no-underline", children: [_jsx(IconDownload, { className: "size-3.5", "aria-hidden": "true" }), t("workspaceFile.download")] })] }));
|
|
32
|
+
return (_jsxs("div", { className: "flex items-center gap-3 rounded-lg border border-border bg-card p-3 text-card-foreground shadow-sm", children: [_jsx("div", { className: "flex size-10 shrink-0 items-center justify-center rounded-md bg-muted text-muted-foreground", children: _jsx(FileIcon, { className: "size-5", "aria-hidden": "true" }) }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("div", { className: "truncate text-sm font-medium", children: file.name }), _jsxs("div", { className: "truncate text-xs text-muted-foreground", children: [formatFileSize(file.sizeBytes, formatNumber), " \u00B7 ", file.path] })] }), _jsxs("a", { href: href, download: file.name, className: "inline-flex shrink-0 items-center gap-1.5 rounded-md bg-primary px-3 py-1.5 text-xs font-medium text-primary-foreground no-underline transition-colors hover:bg-primary/90 hover:no-underline", children: [_jsx(IconDownload, { className: "size-3.5", "aria-hidden": "true" }), t("workspaceFile.download")] })] }));
|
|
33
33
|
}
|
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
import { type ToolRendererContext, type ToolRendererComponent } from "../tool-render-registry.js";
|
|
2
2
|
export declare function isBuiltinDataWidgetActionRenderer(context: ToolRendererContext): boolean;
|
|
3
|
+
/** True whenever a result renders as a workspace-file card — with or
|
|
4
|
+
* without a static chatUI on the action that produced it (see the
|
|
5
|
+
* shape-based fallback registered below). The widget frames itself, so
|
|
6
|
+
* callers use this the same way they use `isBuiltinDataWidgetActionRenderer`
|
|
7
|
+
* to skip the chatUI-gated outer border and avoid a double frame. */
|
|
8
|
+
export declare function isBuiltinWorkspaceFileResult(context: ToolRendererContext): boolean;
|
|
3
9
|
export declare function resolveBuiltinActionChatRenderer(context: ToolRendererContext): ToolRendererComponent | null;
|
|
4
10
|
export declare function resolveBuiltinFallbackToolRenderer(context: ToolRendererContext): ToolRendererComponent | null;
|
|
@@ -99,6 +99,14 @@ export function isBuiltinDataWidgetActionRenderer(context) {
|
|
|
99
99
|
renderer === ACTION_CHAT_UI_DATA_INSIGHTS_RENDERER ||
|
|
100
100
|
renderer === ACTION_CHAT_UI_DATA_WIDGET_RENDERER);
|
|
101
101
|
}
|
|
102
|
+
/** True whenever a result renders as a workspace-file card — with or
|
|
103
|
+
* without a static chatUI on the action that produced it (see the
|
|
104
|
+
* shape-based fallback registered below). The widget frames itself, so
|
|
105
|
+
* callers use this the same way they use `isBuiltinDataWidgetActionRenderer`
|
|
106
|
+
* to skip the chatUI-gated outer border and avoid a double frame. */
|
|
107
|
+
export function isBuiltinWorkspaceFileResult(context) {
|
|
108
|
+
return normalizeWorkspaceFileResult(context.resultJson) !== null;
|
|
109
|
+
}
|
|
102
110
|
export function resolveBuiltinActionChatRenderer(context) {
|
|
103
111
|
if (context.chatUI?.renderer === ACTION_CHAT_UI_INLINE_EXTENSION_RENDERER &&
|
|
104
112
|
normalizeInlineExtensionToolResult(context)) {
|
|
@@ -143,3 +151,14 @@ registerReservedFallbackToolRenderer({
|
|
|
143
151
|
match: (context) => normalizeActionDataWidgetResult(context) !== null,
|
|
144
152
|
Component: BuiltinDataWidgetRenderer,
|
|
145
153
|
});
|
|
154
|
+
// Shape-based, not chatUI-based: any tool result — from show-workspace-file,
|
|
155
|
+
// or any other action that spreads `{ file: toWorkspaceFileCard(meta) }` into
|
|
156
|
+
// its own result — renders a download card without a second discretionary
|
|
157
|
+
// call to show-workspace-file. Matching by shape (instead of statically
|
|
158
|
+
// tagging every such action with `chatUI`) also keeps read/list-style calls
|
|
159
|
+
// on the same multi-purpose action collapsible when they don't produce a file.
|
|
160
|
+
registerReservedFallbackToolRenderer({
|
|
161
|
+
id: "core.workspace-file",
|
|
162
|
+
match: (context) => normalizeWorkspaceFileResult(context.resultJson) !== null,
|
|
163
|
+
Component: BuiltinWorkspaceFileRenderer,
|
|
164
|
+
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Skeleton } from "@agent-native/toolkit/ui/skeleton";
|
|
3
3
|
import { IconArrowRight, IconBrandGithub, IconCheck, IconExternalLink, IconInfoCircle, IconKey, IconLoader2, IconSearch, } from "@tabler/icons-react";
|
|
4
|
-
import React, { useMemo, useState } from "react";
|
|
4
|
+
import React, { useCallback, useMemo, useState } from "react";
|
|
5
5
|
import { docsUrl } from "../../shared/docs-url.js";
|
|
6
6
|
import { appPath } from "../api-path.js";
|
|
7
7
|
import { Tooltip, TooltipContent, TooltipTrigger, } from "../components/ui/tooltip.js";
|
|
@@ -28,7 +28,14 @@ const BUILDER_MORE_SERVICES = [
|
|
|
28
28
|
];
|
|
29
29
|
export function FirstRunOnboarding({ skipIntegrations = shouldSkipFirstRunIntegrations(), initialFirstRun = false, } = {}) {
|
|
30
30
|
const previewMode = useOnboardingPreviewMode();
|
|
31
|
-
const { firstRun, loading, error, profile, completeFirstRun } = useOnboarding({ preview: previewMode, initialFirstRun });
|
|
31
|
+
const { firstRun, loading, error, profile, completeFirstRun, completeFirstRunError, } = useOnboarding({ preview: previewMode, initialFirstRun });
|
|
32
|
+
// completeFirstRun() rejects on failure — swallow it here so a Skip/
|
|
33
|
+
// Continue click never becomes an unhandled rejection; completeFirstRunError
|
|
34
|
+
// (rendered below) is the real signal, and the user stays on this screen
|
|
35
|
+
// to retry instead of being bounced to an unrelated error screen.
|
|
36
|
+
const finishOnboarding = useCallback(() => {
|
|
37
|
+
completeFirstRun().catch(() => { });
|
|
38
|
+
}, [completeFirstRun]);
|
|
32
39
|
const [screen, setScreen] = useState("intro");
|
|
33
40
|
const [extensionIndex, setExtensionIndex] = useState(0);
|
|
34
41
|
const [integrationQuery, setIntegrationQuery] = useState("");
|
|
@@ -86,15 +93,15 @@ export function FirstRunOnboarding({ skipIntegrations = shouldSkipFirstRunIntegr
|
|
|
86
93
|
trackingFlow: "connect_llm",
|
|
87
94
|
});
|
|
88
95
|
};
|
|
89
|
-
const handleOpenSettings =
|
|
96
|
+
const handleOpenSettings = () => {
|
|
90
97
|
window.dispatchEvent(new CustomEvent("agent-panel:open-settings", {
|
|
91
98
|
detail: { section: "integrations" },
|
|
92
99
|
}));
|
|
93
|
-
|
|
100
|
+
finishOnboarding();
|
|
94
101
|
};
|
|
95
102
|
const handleFinish = () => {
|
|
96
103
|
if (extensions.length === 0) {
|
|
97
|
-
|
|
104
|
+
finishOnboarding();
|
|
98
105
|
return;
|
|
99
106
|
}
|
|
100
107
|
setExtensionIndex(0);
|
|
@@ -155,7 +162,7 @@ export function FirstRunOnboarding({ skipIntegrations = shouldSkipFirstRunIntegr
|
|
|
155
162
|
if (screen === "extension") {
|
|
156
163
|
const extension = extensions[extensionIndex];
|
|
157
164
|
if (!extension) {
|
|
158
|
-
|
|
165
|
+
finishOnboarding();
|
|
159
166
|
return null;
|
|
160
167
|
}
|
|
161
168
|
const Extension = extension.component;
|
|
@@ -164,9 +171,9 @@ export function FirstRunOnboarding({ skipIntegrations = shouldSkipFirstRunIntegr
|
|
|
164
171
|
setExtensionIndex((current) => current + 1);
|
|
165
172
|
return;
|
|
166
173
|
}
|
|
167
|
-
|
|
174
|
+
finishOnboarding();
|
|
168
175
|
};
|
|
169
|
-
return (_jsx(Extension, { onComplete: advanceExtension, onSkip:
|
|
176
|
+
return (_jsxs(_Fragment, { children: [_jsx(Extension, { onComplete: advanceExtension, onSkip: finishOnboarding }), completeFirstRunError && (_jsx(FirstRunCompletionError, { message: completeFirstRunError, onRetry: finishOnboarding }))] }));
|
|
170
177
|
}
|
|
171
178
|
if (screen === "intro") {
|
|
172
179
|
return (_jsx(OnboardingShell, { profile: profile, screen: "intro", children: _jsxs("div", { className: "mx-auto flex w-full max-w-lg flex-col items-center text-center", children: [_jsxs("h1", { className: "text-3xl font-semibold tracking-[-0.05em] sm:text-4xl", children: ["Free forever.", _jsx("br", {}), _jsx("span", { className: "text-primary", children: "Open source for life." })] }), _jsxs("div", { className: "mt-7 grid w-full gap-2 text-left sm:grid-cols-3", children: [_jsxs("div", { className: "rounded-lg bg-muted/35 px-3 py-3", children: [_jsx("p", { className: "text-xs font-medium", children: "Fully customizable" }), _jsx("p", { className: "mt-1 text-[11px] leading-4 text-muted-foreground", children: "Change the UI, code, and behavior." })] }), _jsxs("div", { className: "rounded-lg bg-muted/35 px-3 py-3", children: [_jsx("p", { className: "text-xs font-medium", children: "Bring your own keys" }), _jsx("p", { className: "mt-1 text-[11px] leading-4 text-muted-foreground", children: "Use your own providers and accounts." })] }), _jsxs("div", { className: "rounded-lg bg-muted/35 px-3 py-3", children: [_jsx("p", { className: "text-xs font-medium", children: "Build your own" }), _jsx("p", { className: "mt-1 text-[11px] leading-4 text-muted-foreground", children: "Mix and match toolkit pieces in your own apps." })] })] }), _jsxs("button", { type: "button", className: cn(primaryButtonClass, "mt-6"), onClick: () => setScreen("choice"), children: ["Continue", _jsx(IconArrowRight, { size: 15 })] }), _jsxs("a", { href: "https://github.com/builderio/agent-native", target: "_blank", rel: "noreferrer", className: "mt-3 inline-flex items-center gap-1.5 text-xs text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", children: [_jsx(IconBrandGithub, { size: 14 }), _jsx("span", { children: "View source" }), _jsx(IconExternalLink, { size: 13 })] })] }) }));
|
|
@@ -204,29 +211,29 @@ export function FirstRunOnboarding({ skipIntegrations = shouldSkipFirstRunIntegr
|
|
|
204
211
|
if (screen === "connecting") {
|
|
205
212
|
return (_jsx(OnboardingShell, { profile: profile, screen: "choice", children: _jsxs("div", { className: "mx-auto flex w-full max-w-md flex-col items-center text-center", children: [_jsx("div", { className: "flex size-10 items-center justify-center rounded-full bg-primary/10 text-primary", children: _jsx(IconLoader2, { className: "animate-spin", size: 19 }) }), _jsx("h1", { className: "mt-5 text-xl font-semibold tracking-[-0.04em]", children: "Connecting Builder.io free credits" }), _jsx("p", { className: "mt-2 text-sm text-muted-foreground", children: "Finish the one-click connection in the new window." }), _jsxs("div", { className: "mt-7 w-full rounded-xl bg-muted/35 p-4 text-left", children: [_jsxs("div", { className: "flex items-center justify-between gap-3", children: [_jsx(Skeleton, { className: "h-3 w-28" }), _jsx(Skeleton, { className: "h-5 w-16 rounded-full" })] }), _jsx(Skeleton, { className: "mt-4 h-8 w-full" }), _jsxs("div", { className: "mt-3 grid grid-cols-3 gap-2", children: [_jsx(Skeleton, { className: "h-7 w-full" }), _jsx(Skeleton, { className: "h-7 w-full" }), _jsx(Skeleton, { className: "h-7 w-full" })] })] }), connectFlow.error && (_jsxs("div", { className: "mt-4 flex flex-col items-center gap-2", children: [_jsx("p", { className: "text-xs text-destructive", children: connectFlow.error }), _jsx("button", { type: "button", className: secondaryButtonClass, onClick: () => setScreen("choice"), children: "Try again" })] }))] }) }));
|
|
206
213
|
}
|
|
207
|
-
return (
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
214
|
+
return (_jsxs(OnboardingShell, { profile: profile, screen: "ready", children: [_jsxs("div", { className: "mx-auto flex w-full max-w-2xl flex-col items-center text-center", children: [_jsx("div", { className: "flex size-12 items-center justify-center rounded-2xl bg-primary/10 text-primary", children: _jsx(IconCheck, { size: 20 }) }), _jsx("h1", { className: "mt-5 text-xl font-semibold tracking-[-0.04em]", children: "Your agent is ready." }), _jsx("p", { className: "mt-2 max-w-md text-sm leading-6 text-muted-foreground", children: "Start with a chat, then connect more tools whenever you need them." }), _jsx("div", { className: "mt-7 grid w-full gap-2 text-left sm:grid-cols-3", children: (skipIntegrations
|
|
215
|
+
? [
|
|
216
|
+
[
|
|
217
|
+
"Workflow actions",
|
|
218
|
+
"Use the app's buttons and sidebar to run the workflow.",
|
|
219
|
+
],
|
|
220
|
+
[
|
|
221
|
+
"AI sidebar",
|
|
222
|
+
"Ask the agent to review or refine a step in context.",
|
|
223
|
+
],
|
|
224
|
+
[
|
|
225
|
+
"Flexible providers",
|
|
226
|
+
"Use Builder.io free credits or your own keys.",
|
|
227
|
+
],
|
|
228
|
+
]
|
|
229
|
+
: [
|
|
230
|
+
["Chat + actions", "Ask your agent to work across the app."],
|
|
231
|
+
["Agent integrations", "Connect tools from Settings anytime."],
|
|
232
|
+
[
|
|
233
|
+
"Flexible providers",
|
|
234
|
+
"Use Builder.io free credits or your own keys.",
|
|
235
|
+
],
|
|
236
|
+
]).map(([title, description]) => (_jsxs("div", { className: "rounded-xl bg-muted/35 px-4 py-4", children: [_jsx("span", { className: "flex size-7 items-center justify-center rounded-full bg-primary/10 text-primary", children: _jsx(IconCheck, { size: 14 }) }), _jsx("p", { className: "mt-3 text-sm font-medium", children: title }), _jsx("p", { className: "mt-1 text-xs leading-5 text-muted-foreground", children: description })] }, title))) }), _jsxs("button", { type: "button", "data-testid": "first-run-open-app", className: cn(primaryButtonClass, "mt-7"), onClick: handleFinish, children: ["Open app", _jsx(IconArrowRight, { size: 15 })] })] }), completeFirstRunError && (_jsx(FirstRunCompletionError, { message: completeFirstRunError, onRetry: finishOnboarding }))] }));
|
|
230
237
|
}
|
|
231
238
|
function OnboardingShell({ profile, screen, footer, children, }) {
|
|
232
239
|
return (_jsxs("div", { className: "fixed inset-0 z-[100] flex h-full min-h-0 flex-col bg-background text-foreground", "data-onboarding-screen": screen, role: "dialog", "aria-modal": "true", "aria-label": `${profile?.appName ?? "Your app"} setup`, children: [_jsx("div", { className: "h-0.5 shrink-0 bg-muted", "data-testid": "onboarding-progress", children: _jsx("div", { className: "h-full bg-primary transition-[width] duration-200", style: {
|
|
@@ -266,6 +273,13 @@ function CapabilityInfoButton({ capability, ariaLabel, }) {
|
|
|
266
273
|
return (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { type: "button", "aria-label": ariaLabel, className: "inline-flex size-4 items-center justify-center rounded-full text-muted-foreground hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", onClick: (event) => event.stopPropagation(), onKeyDown: (event) => event.stopPropagation(), children: _jsx(IconInfoCircle, { size: 13 }) }) }), _jsx(TooltipContent, { side: "top", className: "max-w-xs text-xs", children: capability.why })] }));
|
|
267
274
|
}
|
|
268
275
|
const primaryButtonClass = "inline-flex min-h-9 items-center justify-center gap-2 rounded-lg bg-primary px-4 text-xs font-medium text-primary-foreground shadow-sm transition-opacity hover:opacity-90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring";
|
|
276
|
+
/** Inline failure signal for a failed completeFirstRun() call — keeps the
|
|
277
|
+
* user on their current screen with a way forward, instead of swapping to
|
|
278
|
+
* an unrelated full-screen error or leaving Skip/Continue looking like it
|
|
279
|
+
* did nothing. */
|
|
280
|
+
function FirstRunCompletionError({ message, onRetry, }) {
|
|
281
|
+
return (_jsxs("div", { className: "fixed inset-x-0 bottom-4 z-50 mx-auto flex w-fit max-w-[90vw] items-center gap-3 rounded-lg border border-destructive/30 bg-background px-4 py-2 text-xs shadow-lg", children: [_jsx("span", { className: "text-destructive", children: message }), _jsx("button", { type: "button", className: "font-medium underline underline-offset-2 hover:no-underline", onClick: onRetry, children: "Try again" })] }));
|
|
282
|
+
}
|
|
269
283
|
const secondaryButtonClass = "inline-flex min-h-9 items-center justify-center gap-2 rounded-lg border border-border bg-background px-4 text-xs font-medium text-foreground transition-colors hover:bg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring";
|
|
270
284
|
function compareUrl(value) {
|
|
271
285
|
try {
|
|
@@ -30,8 +30,15 @@ export interface UseOnboardingResult {
|
|
|
30
30
|
reopen: () => Promise<void>;
|
|
31
31
|
/** True until the post-signup full-screen flow is completed. */
|
|
32
32
|
firstRun: boolean;
|
|
33
|
-
/** Clear the post-signup full-screen flow marker.
|
|
33
|
+
/** Clear the post-signup full-screen flow marker. Rejects instead of
|
|
34
|
+
* resolving silently when the server call fails — see
|
|
35
|
+
* `completeFirstRunError` for the message to show the user. */
|
|
34
36
|
completeFirstRun: () => Promise<void>;
|
|
37
|
+
/** Set when the last `completeFirstRun()` call failed. Cleared on the next
|
|
38
|
+
* attempt (success or failure). Distinct from `error` (the initial steps
|
|
39
|
+
* load failure) so a failed Skip/Continue doesn't swap the whole screen
|
|
40
|
+
* for an unrelated "could not load" message. */
|
|
41
|
+
completeFirstRunError: string | null;
|
|
35
42
|
}
|
|
36
43
|
export declare function useOnboarding(options?: {
|
|
37
44
|
preview?: boolean;
|
|
@@ -10,6 +10,7 @@ export function useOnboarding(options = {}) {
|
|
|
10
10
|
const [error, setError] = useState(null);
|
|
11
11
|
const [dismissed, setDismissed] = useState(false);
|
|
12
12
|
const [firstRun, setFirstRun] = useState(preview || initialFirstRun);
|
|
13
|
+
const [completeFirstRunError, setCompleteFirstRunError] = useState(null);
|
|
13
14
|
const mountedRef = useRef(true);
|
|
14
15
|
useEffect(() => {
|
|
15
16
|
setFirstRun(preview || initialFirstRun);
|
|
@@ -116,14 +117,27 @@ export function useOnboarding(options = {}) {
|
|
|
116
117
|
}
|
|
117
118
|
return;
|
|
118
119
|
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
120
|
+
setCompleteFirstRunError(null);
|
|
121
|
+
// Both a rejected fetch (offline, dropped connection) and a non-ok
|
|
122
|
+
// response are real failures — neither may look like success to the
|
|
123
|
+
// caller, so both throw instead of returning as if the step advanced.
|
|
124
|
+
let response;
|
|
125
|
+
try {
|
|
126
|
+
response = await fetch(agentNativePath("/_agent-native/onboarding/first-run/complete"), {
|
|
127
|
+
method: "POST",
|
|
128
|
+
headers: { "Content-Type": "application/json" },
|
|
129
|
+
body: "{}",
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
catch (e) {
|
|
133
|
+
const message = e instanceof Error ? e.message : "first-run completion request failed";
|
|
134
|
+
setCompleteFirstRunError(message);
|
|
135
|
+
throw e instanceof Error ? e : new Error(message);
|
|
136
|
+
}
|
|
124
137
|
if (!response.ok) {
|
|
125
|
-
|
|
126
|
-
|
|
138
|
+
const message = `first-run completion failed: ${response.status}`;
|
|
139
|
+
setCompleteFirstRunError(message);
|
|
140
|
+
throw new Error(message);
|
|
127
141
|
}
|
|
128
142
|
setFirstRun(false);
|
|
129
143
|
if (typeof window !== "undefined") {
|
|
@@ -153,5 +167,6 @@ export function useOnboarding(options = {}) {
|
|
|
153
167
|
reopen,
|
|
154
168
|
firstRun,
|
|
155
169
|
completeFirstRun,
|
|
170
|
+
completeFirstRunError,
|
|
156
171
|
};
|
|
157
172
|
}
|
|
@@ -19,7 +19,7 @@ import { SettingsSkeleton } from "../settings/SettingsSkeleton.js";
|
|
|
19
19
|
import { useShareOrgMemberSearch } from "../sharing/share-controller-helpers.js";
|
|
20
20
|
import { useActionMutation, useActionQuery } from "../use-action.js";
|
|
21
21
|
import { cn } from "../utils.js";
|
|
22
|
-
import { useOrg, useOrgMembers, useOrgInvitations, useCreateOrg, useUpdateOrg, useBulkInviteMembers, useChangeMemberRole, useAcceptInvitation, useRemoveMember, useDeleteOrg, useSwitchOrg, useSetOrgDomain, useSetOrgWorkspaceUrl, useSetOrgAuthProvider, useRevealA2ASecret, useSetA2ASecret, useSyncA2ASecret, useJoinByDomain, useAppRoles, useSetAppMemberRole, ORG_MEMBER_PAGE_SIZE, } from "./hooks.js";
|
|
22
|
+
import { useOrg, useOrgMembers, useOrgInvitations, useCreateOrg, useUpdateOrg, useBulkInviteMembers, useChangeMemberRole, useAcceptInvitation, useRemoveMember, useDeleteOrg, useSwitchOrg, useSetOrgDomain, useSetWorkspaceAppDefaultVisibility, useSetOrgWorkspaceUrl, useSetOrgAuthProvider, useRevealA2ASecret, useSetA2ASecret, useSyncA2ASecret, useJoinByDomain, useAppRoles, useSetAppMemberRole, ORG_MEMBER_PAGE_SIZE, } from "./hooks.js";
|
|
23
23
|
const Button = forwardRef(({ className, ...props }, ref) => (_jsx(ToolkitButton, { ref: ref, variant: "ghost", className: cn("h-auto p-0 hover:bg-transparent hover:text-inherit active:scale-100 [&_svg]:!size-auto", className), ...props })));
|
|
24
24
|
Button.displayName = "TeamPrimitiveButton";
|
|
25
25
|
function RoleIcon({ role }) {
|
|
@@ -219,7 +219,20 @@ function MembersCard({ appRoles }) {
|
|
|
219
219
|
const totalMembers = membersData?.totalCount ?? 0;
|
|
220
220
|
const pendingInvites = invitationsData?.invitations ?? [];
|
|
221
221
|
const hasMultipleOrgs = (org.orgs?.length ?? 0) > 1;
|
|
222
|
-
return (_jsxs("div", { className: "space-y-6", children: [_jsxs(SettingsGroup, { title: "Organization", children: [_jsx(SettingsRow, { id: "organization", label: _jsxs("span", { className: "flex items-center gap-2", children: [_jsx(IconUsersGroup, { className: "size-4 text-muted-foreground" }), _jsx(OrgNameDisplay, { name: org.orgName ?? "", canEdit: isOwnerOrAdmin })] }), description: `${t("org.memberCount", { count: totalMembers })} · ${t("org.youAreRole", { role: org.role })}`, control: hasMultipleOrgs ? (_jsxs(Select, { value: org.orgId ?? "", onValueChange: (value) => switchOrg.mutate(value || null), disabled: switchOrg.isPending, children: [_jsx(SelectTrigger, { className: "h-auto w-full rounded-md border border-border bg-background px-2.5 py-1.5 text-xs sm:w-auto", children: _jsx(SelectValue, {}) }), _jsx(SelectContent, { children: org.orgs.map((o) => (_jsx(SelectItem, { value: o.orgId, children: o.orgName }, o.orgId))) })] })) : undefined }), isOwnerOrAdmin && (_jsxs(_Fragment, { children: [_jsx(DomainSettingsSection, { domain: org.allowedDomain, ownerEmail: org.email }), _jsx(WorkspaceUrlSettingsSection, { workspaceUrl: org.workspaceUrl }), _jsx(AuthProviderSettingsSection, { requiredAuthProvider: org.requiredAuthProvider }), isOwner && _jsx(A2ASecretSection, { isSet: Boolean(org.a2aSecretSet) })] })), switchOrg.error && (_jsx("div", { className: "px-5 pb-4", children: _jsx(ErrorText, { error: switchOrg.error }) }))] }), _jsx(MembersTableCard, { members: members, totalMembers: totalMembers, pendingInvites: pendingInvites, isLoadingMembers: isLoadingMembers, isFetchingMembers: isFetchingMembers, currentUserEmail: org.email, currentUserRole: org.role ?? null, appRoles: appRoles, groups: groupsQuery.data ?? [], canManageGroups: isOwnerOrAdmin, memberOffset: memberOffset, hasNextPage: membersData?.hasMore === true, nextMemberOffset: membersData?.nextOffset ?? null, onMemberPageChange: setMemberOffset }), isOwnerOrAdmin && (_jsx(WorkspaceGroupsCard, { groups: groupsQuery.data ?? [] })), isOwner && _jsx(DangerZoneCard, { orgName: org.orgName ?? "" })] }));
|
|
222
|
+
return (_jsxs("div", { className: "space-y-6", children: [_jsxs(SettingsGroup, { title: "Organization", children: [_jsx(SettingsRow, { id: "organization", label: _jsxs("span", { className: "flex items-center gap-2", children: [_jsx(IconUsersGroup, { className: "size-4 text-muted-foreground" }), _jsx(OrgNameDisplay, { name: org.orgName ?? "", canEdit: isOwnerOrAdmin })] }), description: `${t("org.memberCount", { count: totalMembers })} · ${t("org.youAreRole", { role: org.role })}`, control: hasMultipleOrgs ? (_jsxs(Select, { value: org.orgId ?? "", onValueChange: (value) => switchOrg.mutate(value || null), disabled: switchOrg.isPending, children: [_jsx(SelectTrigger, { className: "h-auto w-full rounded-md border border-border bg-background px-2.5 py-1.5 text-xs sm:w-auto", children: _jsx(SelectValue, {}) }), _jsx(SelectContent, { children: org.orgs.map((o) => (_jsx(SelectItem, { value: o.orgId, children: o.orgName }, o.orgId))) })] })) : undefined }), isOwnerOrAdmin && (_jsxs(_Fragment, { children: [_jsx(DomainSettingsSection, { domain: org.allowedDomain, ownerEmail: org.email }), _jsx(WorkspaceAppPrivacySettingsSection, { visibility: org.workspaceAppDefaultVisibility ?? "org" }), _jsx(WorkspaceUrlSettingsSection, { workspaceUrl: org.workspaceUrl }), _jsx(AuthProviderSettingsSection, { requiredAuthProvider: org.requiredAuthProvider }), isOwner && _jsx(A2ASecretSection, { isSet: Boolean(org.a2aSecretSet) })] })), switchOrg.error && (_jsx("div", { className: "px-5 pb-4", children: _jsx(ErrorText, { error: switchOrg.error }) }))] }), _jsx(MembersTableCard, { members: members, totalMembers: totalMembers, pendingInvites: pendingInvites, isLoadingMembers: isLoadingMembers, isFetchingMembers: isFetchingMembers, currentUserEmail: org.email, currentUserRole: org.role ?? null, appRoles: appRoles, groups: groupsQuery.data ?? [], canManageGroups: isOwnerOrAdmin, memberOffset: memberOffset, hasNextPage: membersData?.hasMore === true, nextMemberOffset: membersData?.nextOffset ?? null, onMemberPageChange: setMemberOffset }), isOwnerOrAdmin && (_jsx(WorkspaceGroupsCard, { groups: groupsQuery.data ?? [] })), isOwner && _jsx(DangerZoneCard, { orgName: org.orgName ?? "" })] }));
|
|
223
|
+
}
|
|
224
|
+
function WorkspaceAppPrivacySettingsSection({ visibility, }) {
|
|
225
|
+
const t = useT();
|
|
226
|
+
const setDefault = useSetWorkspaceAppDefaultVisibility();
|
|
227
|
+
return (_jsx(SettingsRow, { id: "workspace-app-default-visibility", label: t("org.workspaceAppsDefaultPrivacy", {
|
|
228
|
+
defaultValue: "New app privacy",
|
|
229
|
+
}), description: t("org.workspaceAppsDefaultPrivacyDescription", {
|
|
230
|
+
defaultValue: "Choose whether new workspace apps start private to their creator or visible to the organization.",
|
|
231
|
+
}), control: _jsxs(Select, { value: visibility, onValueChange: (value) => setDefault.mutate(value === "private" ? "private" : "org"), disabled: setDefault.isPending, children: [_jsx(SelectTrigger, { className: "h-auto w-full rounded-md border border-border bg-background px-2.5 py-1.5 text-xs sm:w-auto", children: _jsx(SelectValue, {}) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "org", children: t("org.workspaceAppsOrganization", {
|
|
232
|
+
defaultValue: "Organization",
|
|
233
|
+
}) }), _jsx(SelectItem, { value: "private", children: t("org.workspaceAppsCreatorOnly", {
|
|
234
|
+
defaultValue: "Creator only",
|
|
235
|
+
}) })] })] }) }));
|
|
223
236
|
}
|
|
224
237
|
function MembersTableCard({ members, totalMembers, pendingInvites, isLoadingMembers, isFetchingMembers, currentUserEmail, currentUserRole, appRoles, groups, canManageGroups, memberOffset, hasNextPage, nextMemberOffset, onMemberPageChange, }) {
|
|
225
238
|
const t = useT();
|
|
@@ -59,6 +59,8 @@ export declare function useSwitchOrg(): import("@tanstack/react-query").UseMutat
|
|
|
59
59
|
export declare function useDeleteOrg(): import("@tanstack/react-query").UseMutationResult<any, Error, string, unknown>;
|
|
60
60
|
export declare function useJoinByDomain(): import("@tanstack/react-query").UseMutationResult<any, Error, string, unknown>;
|
|
61
61
|
export declare function useSetOrgDomain(): import("@tanstack/react-query").UseMutationResult<any, Error, string | null, unknown>;
|
|
62
|
+
export type WorkspaceAppDefaultVisibility = "private" | "org";
|
|
63
|
+
export declare function useSetWorkspaceAppDefaultVisibility(): import("@tanstack/react-query").UseMutationResult<any, Error, WorkspaceAppDefaultVisibility, unknown>;
|
|
62
64
|
export declare function useSetOrgWorkspaceUrl(): import("@tanstack/react-query").UseMutationResult<any, Error, string | null, unknown>;
|
|
63
65
|
export declare function useSetOrgAuthProvider(): import("@tanstack/react-query").UseMutationResult<any, Error, "google" | null, unknown>;
|
|
64
66
|
export interface AppRoleAssignment {
|
package/dist/client/org/hooks.js
CHANGED
|
@@ -247,6 +247,18 @@ export function useSetOrgDomain() {
|
|
|
247
247
|
},
|
|
248
248
|
});
|
|
249
249
|
}
|
|
250
|
+
export function useSetWorkspaceAppDefaultVisibility() {
|
|
251
|
+
const qc = useQueryClient();
|
|
252
|
+
return useMutation({
|
|
253
|
+
mutationFn: (visibility) => apiFetch(`${ORG_BASE}/workspace-app-default-visibility`, {
|
|
254
|
+
method: "PUT",
|
|
255
|
+
body: JSON.stringify({ visibility }),
|
|
256
|
+
}),
|
|
257
|
+
onSuccess: async () => {
|
|
258
|
+
await qc.invalidateQueries({ queryKey: ["org-me"] });
|
|
259
|
+
},
|
|
260
|
+
});
|
|
261
|
+
}
|
|
250
262
|
export function useSetOrgWorkspaceUrl() {
|
|
251
263
|
const qc = useQueryClient();
|
|
252
264
|
return useMutation({
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export { useOrg, useOrgMembers, useOrgInvitations, useCreateOrg, useUpdateOrg, useInviteMember, useBulkInviteMembers, useChangeMemberRole, useAcceptInvitation, useRemoveMember, useDeleteOrg, useSwitchOrg, useJoinByDomain, useSetOrgDomain, useSetOrgWorkspaceUrl, useRevealA2ASecret, useSetA2ASecret, useSyncA2ASecret, useOrgRole, useAppRoles, useAppRole, useSetAppMemberRole, } from "./hooks.js";
|
|
2
|
-
export type { InviteRole, InviteVars, BulkInviteResult, SyncA2ASecretResult, UseOrgRoleResult, AppRoleAssignment, AppRolesInfo, } from "./hooks.js";
|
|
1
|
+
export { useOrg, useOrgMembers, useOrgInvitations, useCreateOrg, useUpdateOrg, useInviteMember, useBulkInviteMembers, useChangeMemberRole, useAcceptInvitation, useRemoveMember, useDeleteOrg, useSwitchOrg, useJoinByDomain, useSetOrgDomain, useSetWorkspaceAppDefaultVisibility, useSetOrgWorkspaceUrl, useRevealA2ASecret, useSetA2ASecret, useSyncA2ASecret, useOrgRole, useAppRoles, useAppRole, useSetAppMemberRole, } from "./hooks.js";
|
|
2
|
+
export type { InviteRole, InviteVars, BulkInviteResult, SyncA2ASecretResult, UseOrgRoleResult, AppRoleAssignment, AppRolesInfo, WorkspaceAppDefaultVisibility, } from "./hooks.js";
|
|
3
3
|
export type { AppRolesDescriptor } from "../../org/app-roles.js";
|
|
4
4
|
export { OrgSwitcher, type OrgSwitcherProps } from "./OrgSwitcher.js";
|
|
5
5
|
export { InvitationBanner, type InvitationBannerProps, } from "./InvitationBanner.js";
|
package/dist/client/org/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// Public client API for the org module.
|
|
2
|
-
export { useOrg, useOrgMembers, useOrgInvitations, useCreateOrg, useUpdateOrg, useInviteMember, useBulkInviteMembers, useChangeMemberRole, useAcceptInvitation, useRemoveMember, useDeleteOrg, useSwitchOrg, useJoinByDomain, useSetOrgDomain, useSetOrgWorkspaceUrl, useRevealA2ASecret, useSetA2ASecret, useSyncA2ASecret, useOrgRole, useAppRoles, useAppRole, useSetAppMemberRole, } from "./hooks.js";
|
|
2
|
+
export { useOrg, useOrgMembers, useOrgInvitations, useCreateOrg, useUpdateOrg, useInviteMember, useBulkInviteMembers, useChangeMemberRole, useAcceptInvitation, useRemoveMember, useDeleteOrg, useSwitchOrg, useJoinByDomain, useSetOrgDomain, useSetWorkspaceAppDefaultVisibility, useSetOrgWorkspaceUrl, useRevealA2ASecret, useSetA2ASecret, useSyncA2ASecret, useOrgRole, useAppRoles, useAppRole, useSetAppMemberRole, } from "./hooks.js";
|
|
3
3
|
export { OrgSwitcher } from "./OrgSwitcher.js";
|
|
4
4
|
export { InvitationBanner, } from "./InvitationBanner.js";
|
|
5
5
|
export { WorkspaceNotice } from "./WorkspaceNotice.js";
|