@agent-native/core 0.101.7 → 0.101.11
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/core/CHANGELOG.md +28 -0
- package/corpus/core/docs/content/deployment.mdx +9 -7
- package/corpus/core/docs/content/locales/ar-SA/deployment.mdx +9 -7
- package/corpus/core/docs/content/locales/de-DE/deployment.mdx +9 -7
- package/corpus/core/docs/content/locales/es-ES/deployment.mdx +9 -7
- package/corpus/core/docs/content/locales/fr-FR/deployment.mdx +9 -7
- package/corpus/core/docs/content/locales/hi-IN/deployment.mdx +9 -7
- package/corpus/core/docs/content/locales/ja-JP/deployment.mdx +9 -7
- package/corpus/core/docs/content/locales/ko-KR/deployment.mdx +9 -7
- package/corpus/core/docs/content/locales/pt-BR/deployment.mdx +9 -7
- package/corpus/core/docs/content/locales/zh-CN/deployment.mdx +9 -7
- package/corpus/core/docs/content/locales/zh-TW/deployment.mdx +9 -7
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/a2a/client.ts +23 -1
- package/corpus/core/src/a2a/handlers.ts +65 -1
- package/corpus/core/src/a2a/server.ts +124 -0
- package/corpus/core/src/a2a/task-store.ts +253 -0
- package/corpus/core/src/a2a/types.ts +26 -0
- package/corpus/core/src/agent/production-agent.ts +5 -2
- package/corpus/core/src/client/review/ReviewCommentComposer.tsx +9 -1
- package/corpus/core/src/client/review/ReviewThreadPanel.tsx +17 -2
- package/corpus/core/src/client/settings/SettingsPanel.tsx +41 -21
- package/corpus/core/src/client/settings/useBuilderStatus.ts +28 -9
- package/corpus/core/src/client/setup-connections/BuilderConnectCard.tsx +2 -7
- package/corpus/core/src/mcp/builtin-tools.ts +25 -1
- package/corpus/core/src/scripts/call-agent.ts +22 -3
- package/corpus/core/src/server/agent-chat-plugin.ts +86 -1
- package/corpus/core/src/server/auth.ts +25 -1
- package/corpus/core/src/server/builder-browser.ts +353 -1
- package/corpus/core/src/server/core-routes-plugin.ts +601 -223
- package/corpus/core/src/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +25 -0
- package/corpus/templates/calendar/app/components/calendar/DayView.tsx +80 -1
- package/corpus/templates/calendar/app/components/calendar/EventCard.tsx +28 -3
- package/corpus/templates/calendar/app/components/calendar/EventDetailPanel.tsx +5 -1
- package/corpus/templates/calendar/app/components/calendar/EventDetailPopover.tsx +30 -3
- package/corpus/templates/calendar/app/components/calendar/OutOfOfficeEvent.tsx +196 -0
- package/corpus/templates/calendar/app/components/calendar/WeekView.tsx +115 -1
- package/corpus/templates/calendar/app/lib/out-of-office.ts +45 -0
- package/corpus/templates/calendar/changelog/2026-07-14-out-of-office-blocks-now-sit-behind-meetings-and-event-stack.md +6 -0
- package/corpus/templates/content/.agents/skills/document-editing/SKILL.md +23 -0
- package/corpus/templates/content/AGENTS.md +3 -2
- package/corpus/templates/content/actions/_builder-cms-intent-lookup.ts +87 -0
- package/corpus/templates/content/actions/_builder-cms-read-client.ts +173 -25
- package/corpus/templates/content/actions/_builder-cms-source-adapter.ts +1 -0
- package/corpus/templates/content/actions/_builder-cms-write-adapter.ts +427 -18
- package/corpus/templates/content/actions/_builder-cms-write-client.ts +17 -73
- package/corpus/templates/content/actions/_builder-cms-write-settings.ts +27 -7
- package/corpus/templates/content/actions/_builder-source-execution-claim.ts +124 -0
- package/corpus/templates/content/actions/_builder-source-execution-preservation.ts +21 -0
- package/corpus/templates/content/actions/_builder-source-timings.ts +57 -0
- package/corpus/templates/content/actions/_database-source-utils.ts +1041 -154
- package/corpus/templates/content/actions/_database-utils.ts +89 -12
- package/corpus/templates/content/actions/_preview-document-draft.ts +31 -0
- package/corpus/templates/content/actions/cancel-prepared-builder-source-update.ts +309 -0
- package/corpus/templates/content/actions/execute-builder-source-batch.ts +120 -49
- package/corpus/templates/content/actions/execute-builder-source-execution.ts +608 -264
- package/corpus/templates/content/actions/get-preview-document-draft.ts +26 -0
- package/corpus/templates/content/actions/materialize-builder-required-fields.ts +550 -0
- package/corpus/templates/content/actions/prepare-builder-source-execution.ts +112 -65
- package/corpus/templates/content/actions/prepare-builder-source-review.ts +463 -170
- package/corpus/templates/content/actions/preview-builder-source-review.ts +99 -0
- package/corpus/templates/content/actions/set-content-database-source-write-mode.ts +2 -2
- package/corpus/templates/content/actions/update-preview-document-draft.ts +153 -0
- package/corpus/templates/content/app/components/editor/DocumentProperties.tsx +27 -15
- package/corpus/templates/content/app/components/editor/MathRenderer.tsx +43 -0
- package/corpus/templates/content/app/components/editor/SlashCommandMenu.tsx +260 -4
- package/corpus/templates/content/app/components/editor/VisualEditor.tsx +57 -5
- package/corpus/templates/content/app/components/editor/body-hydration.ts +27 -0
- package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +2353 -576
- package/corpus/templates/content/app/components/editor/database/settings.tsx +13 -10
- package/corpus/templates/content/app/components/editor/database-sources/BuilderSourceReviewDialog.tsx +358 -75
- package/corpus/templates/content/app/components/editor/extensions/NotionExtensions.tsx +78 -0
- package/corpus/templates/content/app/components/editor/previewDocumentSaveController.ts +124 -29
- package/corpus/templates/content/app/components/editor/previewDocumentSaveRegistry.ts +2 -0
- package/corpus/templates/content/app/global.css +71 -1
- package/corpus/templates/content/app/hooks/use-content-database.ts +68 -0
- package/corpus/templates/content/app/hooks/use-documents.ts +53 -4
- package/corpus/templates/content/app/i18n/zh-TW.ts +38 -0
- package/corpus/templates/content/app/i18n-data.ts +450 -0
- package/corpus/templates/content/app/root.tsx +2 -0
- package/corpus/templates/content/changelog/2026-07-10-builder-backed-preview-edits-are-preserved-when-article-bodi.md +6 -0
- package/corpus/templates/content/changelog/2026-07-10-builder-cms-sources-can-now-be-enabled-for-guarded-staged-or.md +6 -0
- package/corpus/templates/content/changelog/2026-07-13-builder-connection-setup-is-now-available-directly-from-conn.md +6 -0
- package/corpus/templates/content/changelog/2026-07-13-builder-reviews-now-hide-already-applied-writes-detect-nativ.md +6 -0
- package/corpus/templates/content/changelog/2026-07-13-required-builder-publishing-fields-can-now-be-added-directly.md +6 -0
- package/corpus/templates/content/changelog/2026-07-13-you-can-now-cancel-a-prepared-builder-update-safely-before-i.md +6 -0
- package/corpus/templates/content/changelog/2026-07-14-builder-account-connection-now-remains-available-when-branch.md +6 -0
- package/corpus/templates/content/changelog/2026-07-14-builder-backed-articles-now-preserve-fifth-and-sixth-level-h.md +6 -0
- package/corpus/templates/content/changelog/2026-07-14-builder-sources-now-review-and-publish-rich-article-updates-.md +6 -0
- package/corpus/templates/content/changelog/2026-07-14-builder-writes-now-stop-retries-when-reconciliation-is-needed.md +6 -0
- package/corpus/templates/content/changelog/2026-07-14-file-and-media-links-now-validate-before-saving.md +6 -0
- package/corpus/templates/content/changelog/2026-07-14-latex-equations-render-in-documents-public-pages-and-exports.md +6 -0
- package/corpus/templates/content/package.json +1 -0
- package/corpus/templates/content/parity/matrix.md +27 -25
- package/corpus/templates/content/parity/matrix.ts +50 -2
- package/corpus/templates/content/server/db/schema.ts +47 -0
- package/corpus/templates/content/server/plugins/auth.ts +1 -0
- package/corpus/templates/content/server/plugins/db.ts +53 -0
- package/corpus/templates/content/shared/api.ts +70 -1
- package/corpus/templates/content/shared/builder-mdx.ts +705 -15
- package/corpus/templates/content/shared/document-export.ts +296 -25
- package/corpus/templates/content/shared/inline-math.ts +128 -0
- package/corpus/templates/content/shared/math-rendering.ts +50 -0
- package/corpus/templates/content/shared/nfm.ts +20 -17
- package/corpus/templates/content/vite.config.ts +0 -1
- package/corpus/templates/design/app/components/design/ReadOnlyDesignBanner.tsx +52 -7
- package/corpus/templates/design/app/components/design/ReviewCommentsPanel.tsx +36 -4
- package/corpus/templates/design/app/components/visual-editor/ReviewCanvasPins.tsx +4 -1
- package/corpus/templates/design/app/i18n/ar-SA.ts +1 -0
- package/corpus/templates/design/app/i18n/de-DE.ts +1 -0
- package/corpus/templates/design/app/i18n/en-US.ts +1 -0
- package/corpus/templates/design/app/i18n/es-ES.ts +1 -0
- package/corpus/templates/design/app/i18n/fr-FR.ts +1 -0
- package/corpus/templates/design/app/i18n/hi-IN.ts +1 -0
- package/corpus/templates/design/app/i18n/ja-JP.ts +1 -0
- package/corpus/templates/design/app/i18n/ko-KR.ts +1 -0
- package/corpus/templates/design/app/i18n/pt-BR.ts +1 -0
- package/corpus/templates/design/app/i18n/zh-CN.ts +1 -0
- package/corpus/templates/design/app/i18n/zh-TW.ts +1 -0
- package/corpus/templates/design/app/pages/design-editor/selection-state.ts +8 -0
- package/corpus/templates/design/app/pages/design-editor/tool-state.ts +11 -0
- package/corpus/templates/design/changelog/2026-07-14-reviewers-can-now-pin-comments-from-the-canvas-toolbar-targe.md +6 -0
- package/corpus/templates/design/changelog/2026-07-15-viewer-comment-controls-now-sit-inside-the-read-only-notice-.md +6 -0
- package/corpus/templates/design/shared/review-anchor.ts +48 -0
- package/corpus/templates/mail/.agents/skills/email-drafts/SKILL.md +17 -0
- package/corpus/templates/mail/AGENTS.md +21 -19
- package/corpus/templates/mail/actions/create-attachment-upload.ts +49 -0
- package/corpus/templates/mail/changelog/2026-07-14-connected-agents-can-now-securely-upload-local-files-for-mai.md +6 -0
- package/corpus/templates/mail/server/handlers/media.ts +84 -61
- package/corpus/templates/mail/server/lib/attachment-upload-ticket.ts +234 -0
- package/corpus/templates/mail/server/lib/mail-connector-catalog.ts +8 -4
- package/corpus/templates/mail/server/lib/media-upload.ts +114 -0
- package/corpus/templates/mail/server/plugins/auth.ts +9 -1
- package/corpus/templates/mail/server/routes/api/media/attachment-upload/[uploadId].put.ts +1 -0
- package/corpus/templates/plan/server/plan-mdx.ts +53 -7
- package/dist/a2a/client.d.ts +5 -1
- package/dist/a2a/client.d.ts.map +1 -1
- package/dist/a2a/client.js +18 -1
- package/dist/a2a/client.js.map +1 -1
- package/dist/a2a/handlers.d.ts.map +1 -1
- package/dist/a2a/handlers.js +57 -8
- package/dist/a2a/handlers.js.map +1 -1
- package/dist/a2a/server.d.ts.map +1 -1
- package/dist/a2a/server.js +87 -1
- package/dist/a2a/server.js.map +1 -1
- package/dist/a2a/task-store.d.ts +27 -0
- package/dist/a2a/task-store.d.ts.map +1 -1
- package/dist/a2a/task-store.js +216 -0
- package/dist/a2a/task-store.js.map +1 -1
- package/dist/a2a/types.d.ts +24 -0
- package/dist/a2a/types.d.ts.map +1 -1
- package/dist/a2a/types.js.map +1 -1
- package/dist/agent/production-agent.d.ts +1 -0
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +5 -2
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/client/review/ReviewCommentComposer.d.ts +2 -1
- package/dist/client/review/ReviewCommentComposer.d.ts.map +1 -1
- package/dist/client/review/ReviewCommentComposer.js +3 -3
- package/dist/client/review/ReviewCommentComposer.js.map +1 -1
- package/dist/client/review/ReviewThreadPanel.d.ts +9 -1
- package/dist/client/review/ReviewThreadPanel.d.ts.map +1 -1
- package/dist/client/review/ReviewThreadPanel.js +6 -4
- package/dist/client/review/ReviewThreadPanel.js.map +1 -1
- package/dist/client/settings/SettingsPanel.d.ts +3 -0
- package/dist/client/settings/SettingsPanel.d.ts.map +1 -1
- package/dist/client/settings/SettingsPanel.js +11 -4
- package/dist/client/settings/SettingsPanel.js.map +1 -1
- package/dist/client/settings/useBuilderStatus.d.ts +8 -4
- package/dist/client/settings/useBuilderStatus.d.ts.map +1 -1
- package/dist/client/settings/useBuilderStatus.js +19 -6
- package/dist/client/settings/useBuilderStatus.js.map +1 -1
- package/dist/client/setup-connections/BuilderConnectCard.d.ts.map +1 -1
- package/dist/client/setup-connections/BuilderConnectCard.js +2 -5
- package/dist/client/setup-connections/BuilderConnectCard.js.map +1 -1
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/awareness.d.ts.map +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/file-upload/actions/upload-image.d.ts +1 -1
- package/dist/mcp/builtin-tools.d.ts.map +1 -1
- package/dist/mcp/builtin-tools.js +22 -3
- package/dist/mcp/builtin-tools.js.map +1 -1
- package/dist/notifications/routes.d.ts +3 -3
- package/dist/resources/handlers.d.ts +2 -2
- package/dist/scripts/call-agent.d.ts +1 -1
- package/dist/scripts/call-agent.d.ts.map +1 -1
- package/dist/scripts/call-agent.js +19 -1
- package/dist/scripts/call-agent.js.map +1 -1
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +71 -2
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/auth.d.ts +1 -0
- package/dist/server/auth.d.ts.map +1 -1
- package/dist/server/auth.js +19 -2
- package/dist/server/auth.js.map +1 -1
- package/dist/server/builder-browser.d.ts +78 -0
- package/dist/server/builder-browser.d.ts.map +1 -1
- package/dist/server/builder-browser.js +246 -1
- package/dist/server/builder-browser.js.map +1 -1
- package/dist/server/core-routes-plugin.d.ts +41 -0
- package/dist/server/core-routes-plugin.d.ts.map +1 -1
- package/dist/server/core-routes-plugin.js +260 -14
- package/dist/server/core-routes-plugin.js.map +1 -1
- package/dist/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +25 -0
- package/docs/content/deployment.mdx +9 -7
- package/docs/content/locales/ar-SA/deployment.mdx +9 -7
- package/docs/content/locales/de-DE/deployment.mdx +9 -7
- package/docs/content/locales/es-ES/deployment.mdx +9 -7
- package/docs/content/locales/fr-FR/deployment.mdx +9 -7
- package/docs/content/locales/hi-IN/deployment.mdx +9 -7
- package/docs/content/locales/ja-JP/deployment.mdx +9 -7
- package/docs/content/locales/ko-KR/deployment.mdx +9 -7
- package/docs/content/locales/pt-BR/deployment.mdx +9 -7
- package/docs/content/locales/zh-CN/deployment.mdx +9 -7
- package/docs/content/locales/zh-TW/deployment.mdx +9 -7
- package/package.json +2 -2
- package/src/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +25 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Button } from "@agent-native/toolkit/ui/button";
|
|
2
2
|
import { Spinner } from "@agent-native/toolkit/ui/spinner";
|
|
3
3
|
import { Textarea } from "@agent-native/toolkit/ui/textarea";
|
|
4
|
-
import { IconMessageCircle, IconSend } from "@tabler/icons-react";
|
|
4
|
+
import { IconFocus2, IconMessageCircle, IconSend } from "@tabler/icons-react";
|
|
5
5
|
|
|
6
6
|
import type { ReviewResolutionTarget } from "../../review/types.js";
|
|
7
7
|
import { cn } from "../utils.js";
|
|
@@ -16,6 +16,7 @@ export interface ReviewCommentComposerProps {
|
|
|
16
16
|
placeholder?: string;
|
|
17
17
|
commentLabel?: string;
|
|
18
18
|
agentLabel?: string;
|
|
19
|
+
contextLabel?: string;
|
|
19
20
|
autoFocus?: boolean;
|
|
20
21
|
submitOnEnter?: boolean;
|
|
21
22
|
onEscape?: () => void;
|
|
@@ -32,6 +33,7 @@ export function ReviewCommentComposer({
|
|
|
32
33
|
placeholder = "Add a comment...",
|
|
33
34
|
commentLabel = "Comment",
|
|
34
35
|
agentLabel = "Send to agent",
|
|
36
|
+
contextLabel,
|
|
35
37
|
autoFocus = false,
|
|
36
38
|
submitOnEnter = false,
|
|
37
39
|
onEscape,
|
|
@@ -51,6 +53,12 @@ export function ReviewCommentComposer({
|
|
|
51
53
|
submit("human");
|
|
52
54
|
}}
|
|
53
55
|
>
|
|
56
|
+
{contextLabel ? (
|
|
57
|
+
<div className="mb-2 flex min-w-0 items-center gap-1.5 text-xs text-muted-foreground">
|
|
58
|
+
<IconFocus2 className="size-3.5 shrink-0" />
|
|
59
|
+
<span className="truncate">{contextLabel}</span>
|
|
60
|
+
</div>
|
|
61
|
+
) : null}
|
|
54
62
|
<Textarea
|
|
55
63
|
autoFocus={autoFocus}
|
|
56
64
|
value={value}
|
|
@@ -52,6 +52,14 @@ export interface ReviewThreadPanelProps {
|
|
|
52
52
|
resourceType: string;
|
|
53
53
|
resourceId: string;
|
|
54
54
|
targetId?: string | null;
|
|
55
|
+
/** Persist new comments against this target while targetId continues to filter the list. */
|
|
56
|
+
composerTargetId?: string | null;
|
|
57
|
+
/** Optional element/point anchor attached to new comments from the composer. */
|
|
58
|
+
composerAnchor?: unknown | null;
|
|
59
|
+
/** Host metadata attached to new comments from the composer. */
|
|
60
|
+
composerMetadata?: Record<string, unknown>;
|
|
61
|
+
/** Visible label describing the element currently targeted by the composer. */
|
|
62
|
+
composerContextLabel?: string;
|
|
55
63
|
title?: string;
|
|
56
64
|
className?: string;
|
|
57
65
|
includeResolved?: boolean;
|
|
@@ -89,6 +97,10 @@ export function ReviewThreadPanel({
|
|
|
89
97
|
resourceType,
|
|
90
98
|
resourceId,
|
|
91
99
|
targetId,
|
|
100
|
+
composerTargetId,
|
|
101
|
+
composerAnchor,
|
|
102
|
+
composerMetadata,
|
|
103
|
+
composerContextLabel,
|
|
92
104
|
title = "Review",
|
|
93
105
|
className,
|
|
94
106
|
includeResolved = true,
|
|
@@ -145,9 +157,11 @@ export function ReviewThreadPanel({
|
|
|
145
157
|
{
|
|
146
158
|
resourceType,
|
|
147
159
|
resourceId,
|
|
148
|
-
targetId,
|
|
160
|
+
targetId: composerTargetId === undefined ? targetId : composerTargetId,
|
|
161
|
+
...(composerAnchor !== undefined ? { anchor: composerAnchor } : {}),
|
|
162
|
+
...(composerMetadata ? { metadata: composerMetadata } : {}),
|
|
149
163
|
body,
|
|
150
|
-
|
|
164
|
+
resolutionTarget: showComposerTargetPicker ? resolutionTarget : "human",
|
|
151
165
|
},
|
|
152
166
|
{
|
|
153
167
|
onSuccess: (comment) => {
|
|
@@ -194,6 +208,7 @@ export function ReviewThreadPanel({
|
|
|
194
208
|
placeholder={placeholder}
|
|
195
209
|
commentLabel={composerCommentLabel}
|
|
196
210
|
agentLabel={composerAgentLabel}
|
|
211
|
+
contextLabel={composerContextLabel}
|
|
197
212
|
/>
|
|
198
213
|
) : null}
|
|
199
214
|
|
|
@@ -45,6 +45,7 @@ import {
|
|
|
45
45
|
TooltipTrigger,
|
|
46
46
|
} from "../components/ui/tooltip.js";
|
|
47
47
|
import { TeamPage } from "../org/TeamPage.js";
|
|
48
|
+
import { BuilderConnectCard } from "../setup-connections/BuilderConnectCard.js";
|
|
48
49
|
import { callAction } from "../use-action.js";
|
|
49
50
|
import { uploadAvatar, useAvatarUrl } from "../use-avatar.js";
|
|
50
51
|
import { useDevMode } from "../use-dev-mode.js";
|
|
@@ -2578,6 +2579,7 @@ interface SettingsPanelContentProps extends SettingsPanelProps {
|
|
|
2578
2579
|
showCapabilityStrip?: boolean;
|
|
2579
2580
|
className?: string;
|
|
2580
2581
|
surface?: SettingsSurface;
|
|
2582
|
+
builderConnectionOwnedExternally?: boolean;
|
|
2581
2583
|
}
|
|
2582
2584
|
|
|
2583
2585
|
function SettingsPanelContent({
|
|
@@ -2591,8 +2593,11 @@ function SettingsPanelContent({
|
|
|
2591
2593
|
showCapabilityStrip = true,
|
|
2592
2594
|
className,
|
|
2593
2595
|
surface = "sidebar",
|
|
2596
|
+
builderConnectionOwnedExternally = false,
|
|
2594
2597
|
}: SettingsPanelContentProps) {
|
|
2595
|
-
const { status: builder, loading: builderLoading } = useBuilderStatus(
|
|
2598
|
+
const { status: builder, loading: builderLoading } = useBuilderStatus({
|
|
2599
|
+
enabled: !builderConnectionOwnedExternally,
|
|
2600
|
+
});
|
|
2596
2601
|
const connected = builder?.configured ?? false;
|
|
2597
2602
|
const connectUrl = builder?.cliAuthUrl ?? builder?.connectUrl;
|
|
2598
2603
|
const orgName = builder?.orgName;
|
|
@@ -2600,6 +2605,7 @@ function SettingsPanelContent({
|
|
|
2600
2605
|
const credentialSource = builder?.credentialSource;
|
|
2601
2606
|
const builderBranchesAvailable = !!builder?.builderEnabled;
|
|
2602
2607
|
const builderFlow = useBuilderConnectFlow({
|
|
2608
|
+
enabled: !builderConnectionOwnedExternally,
|
|
2603
2609
|
popupUrl: connectUrl,
|
|
2604
2610
|
trackingSource: "settings_panel_builder_card",
|
|
2605
2611
|
});
|
|
@@ -2965,20 +2971,22 @@ function SettingsPanelContent({
|
|
|
2965
2971
|
icon={<IconBrowser size={14} />}
|
|
2966
2972
|
title="Browser Automation"
|
|
2967
2973
|
subtitle="Let agents control a real browser for web tasks."
|
|
2968
|
-
connected={connected}
|
|
2974
|
+
connected={builderConnectionOwnedExternally ? undefined : connected}
|
|
2969
2975
|
open={openSection === "browser"}
|
|
2970
2976
|
onToggle={() => toggle("browser")}
|
|
2971
2977
|
>
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
|
|
2977
|
-
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
2978
|
+
{!builderConnectionOwnedExternally ? (
|
|
2979
|
+
<UseBuilderCard
|
|
2980
|
+
builderFlow={builderFlow}
|
|
2981
|
+
connectUrl={connectUrl}
|
|
2982
|
+
connected={connected}
|
|
2983
|
+
orgName={orgName}
|
|
2984
|
+
envManaged={envManaged}
|
|
2985
|
+
credentialSource={credentialSource}
|
|
2986
|
+
trackingSource="browser_settings"
|
|
2987
|
+
trackingFlow="browser_automation"
|
|
2988
|
+
/>
|
|
2989
|
+
) : null}
|
|
2982
2990
|
</SettingsSection>
|
|
2983
2991
|
)}
|
|
2984
2992
|
|
|
@@ -3057,6 +3065,26 @@ export function SettingsPanel(props: SettingsPanelProps) {
|
|
|
3057
3065
|
return <SettingsPanelContent {...props} />;
|
|
3058
3066
|
}
|
|
3059
3067
|
|
|
3068
|
+
export function ConnectionsSettingsContent({
|
|
3069
|
+
settingsPanelProps,
|
|
3070
|
+
}: {
|
|
3071
|
+
settingsPanelProps: SettingsPanelProps;
|
|
3072
|
+
}) {
|
|
3073
|
+
return (
|
|
3074
|
+
<div className="mx-auto w-full max-w-2xl space-y-4">
|
|
3075
|
+
<BuilderConnectCard trackingSource="settings_connections" />
|
|
3076
|
+
<SettingsPanelContent
|
|
3077
|
+
{...settingsPanelProps}
|
|
3078
|
+
surface="page"
|
|
3079
|
+
sections={CONNECTION_SETTINGS_SECTIONS}
|
|
3080
|
+
showCapabilityStrip={false}
|
|
3081
|
+
className="w-full"
|
|
3082
|
+
builderConnectionOwnedExternally
|
|
3083
|
+
/>
|
|
3084
|
+
</div>
|
|
3085
|
+
);
|
|
3086
|
+
}
|
|
3087
|
+
|
|
3060
3088
|
export function useAgentSettingsTabs(): SettingsTabItem[] {
|
|
3061
3089
|
const { isDevMode, canToggle, setDevMode } = useDevMode();
|
|
3062
3090
|
const baseProps = useMemo<SettingsPanelProps>(
|
|
@@ -3102,15 +3130,7 @@ export function useAgentSettingsTabs(): SettingsTabItem[] {
|
|
|
3102
3130
|
...connections,
|
|
3103
3131
|
icon: IconPlugConnected,
|
|
3104
3132
|
group: "agent",
|
|
3105
|
-
content:
|
|
3106
|
-
<SettingsPanelContent
|
|
3107
|
-
{...baseProps}
|
|
3108
|
-
surface="page"
|
|
3109
|
-
sections={CONNECTION_SETTINGS_SECTIONS}
|
|
3110
|
-
showCapabilityStrip={false}
|
|
3111
|
-
className="mx-auto w-full max-w-2xl"
|
|
3112
|
-
/>
|
|
3113
|
-
),
|
|
3133
|
+
content: <ConnectionsSettingsContent settingsPanelProps={baseProps} />,
|
|
3114
3134
|
},
|
|
3115
3135
|
{
|
|
3116
3136
|
...organization,
|
|
@@ -53,10 +53,14 @@ export interface BuilderStatus {
|
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
/**
|
|
56
|
-
* Fetches Builder connection status from
|
|
56
|
+
* Fetches Builder connection status from the neutral connection-status route.
|
|
57
|
+
* The legacy /_agent-native/builder/status route remains available for older
|
|
58
|
+
* clients.
|
|
57
59
|
* Re-fetches on window focus to detect post-redirect state changes.
|
|
58
60
|
*/
|
|
59
|
-
export function useBuilderStatus(
|
|
61
|
+
export function useBuilderStatus({
|
|
62
|
+
enabled = true,
|
|
63
|
+
}: { enabled?: boolean } = {}) {
|
|
60
64
|
const [status, setStatus] = useState<BuilderStatus | null>(null);
|
|
61
65
|
const [loading, setLoading] = useState(true);
|
|
62
66
|
const [error, setError] = useState<string | null>(null);
|
|
@@ -64,6 +68,7 @@ export function useBuilderStatus() {
|
|
|
64
68
|
const lastGoodStatusRef = useRef<BuilderStatus | null>(null);
|
|
65
69
|
|
|
66
70
|
const fetchStatus = useCallback(async () => {
|
|
71
|
+
if (!enabled) return;
|
|
67
72
|
const keepLastGoodStatus = (message: string) => {
|
|
68
73
|
const lastGoodStatus = lastGoodStatusRef.current;
|
|
69
74
|
setStatus(lastGoodStatus);
|
|
@@ -72,7 +77,9 @@ export function useBuilderStatus() {
|
|
|
72
77
|
};
|
|
73
78
|
|
|
74
79
|
try {
|
|
75
|
-
const res = await fetch(
|
|
80
|
+
const res = await fetch(
|
|
81
|
+
agentNativePath("/_agent-native/connection-status/builder"),
|
|
82
|
+
);
|
|
76
83
|
if (!res.ok) {
|
|
77
84
|
keepLastGoodStatus(`Builder status unavailable (${res.status})`);
|
|
78
85
|
return;
|
|
@@ -91,9 +98,18 @@ export function useBuilderStatus() {
|
|
|
91
98
|
} finally {
|
|
92
99
|
setLoading(false);
|
|
93
100
|
}
|
|
94
|
-
}, []);
|
|
101
|
+
}, [enabled]);
|
|
95
102
|
|
|
96
103
|
useEffect(() => {
|
|
104
|
+
if (!enabled) {
|
|
105
|
+
setStatus(null);
|
|
106
|
+
setLoading(false);
|
|
107
|
+
setError(null);
|
|
108
|
+
setStale(false);
|
|
109
|
+
lastGoodStatusRef.current = null;
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
setLoading(true);
|
|
97
113
|
fetchStatus();
|
|
98
114
|
|
|
99
115
|
function onFocus() {
|
|
@@ -115,7 +131,7 @@ export function useBuilderStatus() {
|
|
|
115
131
|
fetchStatus,
|
|
116
132
|
);
|
|
117
133
|
};
|
|
118
|
-
}, [fetchStatus]);
|
|
134
|
+
}, [enabled, fetchStatus]);
|
|
119
135
|
|
|
120
136
|
return { status, loading, error, stale, refetch: fetchStatus };
|
|
121
137
|
}
|
|
@@ -123,7 +139,7 @@ export function useBuilderStatus() {
|
|
|
123
139
|
// ─── useBuilderConnectFlow ──────────────────────────────────────────────────
|
|
124
140
|
//
|
|
125
141
|
// Shared state machine for the "open Builder CLI-auth popup + poll
|
|
126
|
-
// /builder
|
|
142
|
+
// /connection-status/builder until credentials land" interaction. Replaces three
|
|
127
143
|
// near-duplicate inline implementations: `BuilderCliAuthMethod` in
|
|
128
144
|
// OnboardingPanel, `ConnectBuilderCard`, and `BuilderConnectCta` in
|
|
129
145
|
// AssistantChat. Each consumer supplies its own popup URL / completion
|
|
@@ -158,7 +174,7 @@ export interface BuilderConnectStartOptions {
|
|
|
158
174
|
|
|
159
175
|
export interface BuilderConnectFlow {
|
|
160
176
|
configured: boolean;
|
|
161
|
-
/** True after at least one successful
|
|
177
|
+
/** True after at least one successful Builder connection-status response. */
|
|
162
178
|
statusResolved: boolean;
|
|
163
179
|
/**
|
|
164
180
|
* True when the deploy has BUILDER_PRIVATE_KEY set as a fallback. Connect
|
|
@@ -176,7 +192,7 @@ export interface BuilderConnectFlow {
|
|
|
176
192
|
connecting: boolean;
|
|
177
193
|
error: string | null;
|
|
178
194
|
/**
|
|
179
|
-
* True once the first
|
|
195
|
+
* True once the first Builder connection-status fetch has completed (successfully
|
|
180
196
|
* or not). Consumers that accept an `initialConfigured` prop (e.g. agent
|
|
181
197
|
* tool-call results rendered with server-side state) should treat
|
|
182
198
|
* `configured`/`orgName` as authoritative only once this flips true —
|
|
@@ -579,7 +595,10 @@ export function useBuilderConnectFlow(
|
|
|
579
595
|
const origin = getCallbackOrigin() || window.location.origin;
|
|
580
596
|
try {
|
|
581
597
|
const r = await fetch(
|
|
582
|
-
new URL(
|
|
598
|
+
new URL(
|
|
599
|
+
agentNativePath("/_agent-native/connection-status/builder"),
|
|
600
|
+
origin,
|
|
601
|
+
).href,
|
|
583
602
|
);
|
|
584
603
|
if (!r.ok) return null;
|
|
585
604
|
return (await r.json()) as {
|
|
@@ -30,9 +30,7 @@ export function BuilderConnectCard({
|
|
|
30
30
|
? "Checking"
|
|
31
31
|
: flow.configured
|
|
32
32
|
? connectedLabel
|
|
33
|
-
:
|
|
34
|
-
? "Ready to connect"
|
|
35
|
-
: "Project not configured";
|
|
33
|
+
: "Ready to connect";
|
|
36
34
|
|
|
37
35
|
return (
|
|
38
36
|
<section
|
|
@@ -73,10 +71,7 @@ export function BuilderConnectCard({
|
|
|
73
71
|
<button
|
|
74
72
|
type="button"
|
|
75
73
|
onClick={() => flow.start()}
|
|
76
|
-
disabled={
|
|
77
|
-
flow.connecting ||
|
|
78
|
-
(!flow.builderEnabled && flow.hasFetchedStatus)
|
|
79
|
-
}
|
|
74
|
+
disabled={flow.connecting}
|
|
80
75
|
className="mt-3 inline-flex h-8 items-center gap-2 rounded-md border border-border bg-foreground px-3 text-xs font-medium text-background transition-colors hover:bg-foreground/90 disabled:cursor-not-allowed disabled:opacity-60"
|
|
81
76
|
>
|
|
82
77
|
{flow.connecting ? (
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
* `mountMCP` — the Node bits are dynamically imported inside `run()`.
|
|
32
32
|
*/
|
|
33
33
|
|
|
34
|
-
import type { Task } from "../a2a/types.js";
|
|
34
|
+
import type { A2AApprovedAction, Task } from "../a2a/types.js";
|
|
35
35
|
import type { ActionEntry } from "../agent/production-agent.js";
|
|
36
36
|
import type { ActionTool } from "../agent/types.js";
|
|
37
37
|
import { getConfiguredAppBasePath } from "../server/app-base-path.js";
|
|
@@ -404,6 +404,7 @@ async function submitAskAppA2ATask(
|
|
|
404
404
|
route: AskAppRoute,
|
|
405
405
|
message: string,
|
|
406
406
|
maxWaitMs: number,
|
|
407
|
+
approvedActions?: A2AApprovedAction[],
|
|
407
408
|
): Promise<AskAppTaskResult> {
|
|
408
409
|
const deadline = maxWaitMs > 0 ? Date.now() + maxWaitMs : undefined;
|
|
409
410
|
const { client, metadata } = await createA2AClientForAskApp(
|
|
@@ -419,6 +420,7 @@ async function submitAskAppA2ATask(
|
|
|
419
420
|
{
|
|
420
421
|
async: true,
|
|
421
422
|
metadata,
|
|
423
|
+
...(approvedActions?.length ? { approvedActions } : {}),
|
|
422
424
|
},
|
|
423
425
|
);
|
|
424
426
|
const finalOrRunning = await waitForA2ATask(client, task, deadline);
|
|
@@ -890,6 +892,7 @@ async function routeAskOverA2A(
|
|
|
890
892
|
durable?: boolean;
|
|
891
893
|
maxWaitMs?: number;
|
|
892
894
|
requestOrigin?: string;
|
|
895
|
+
approvedActions?: A2AApprovedAction[];
|
|
893
896
|
},
|
|
894
897
|
): Promise<
|
|
895
898
|
{ app: string; routedVia: "a2a"; response: string } | AskAppTaskResult
|
|
@@ -904,6 +907,7 @@ async function routeAskOverA2A(
|
|
|
904
907
|
},
|
|
905
908
|
message,
|
|
906
909
|
options.maxWaitMs ?? ASK_APP_DEFAULT_INLINE_WAIT_MS,
|
|
910
|
+
options.approvedActions,
|
|
907
911
|
);
|
|
908
912
|
}
|
|
909
913
|
const { callAgent } = await import("../a2a/client.js");
|
|
@@ -919,6 +923,7 @@ async function routeAskOverA2A(
|
|
|
919
923
|
orgDomain: auth.orgDomain,
|
|
920
924
|
orgSecret: auth.orgSecret,
|
|
921
925
|
requestOrigin: options?.requestOrigin,
|
|
926
|
+
approvedActions: options?.approvedActions,
|
|
922
927
|
// Bound the wait — cross-app A2A polls async by default.
|
|
923
928
|
timeoutMs: 5 * 60_000,
|
|
924
929
|
});
|
|
@@ -1012,6 +1017,19 @@ function askAppTool(
|
|
|
1012
1017
|
description:
|
|
1013
1018
|
"Maximum time to wait inline before returning a taskId. Hosted MCP clamps this to 25000ms.",
|
|
1014
1019
|
},
|
|
1020
|
+
approvedActions: {
|
|
1021
|
+
type: "array",
|
|
1022
|
+
description:
|
|
1023
|
+
"Exact downstream tool calls the user explicitly authorized in this chat. Never infer authorization or include a different action.",
|
|
1024
|
+
items: {
|
|
1025
|
+
type: "object",
|
|
1026
|
+
properties: {
|
|
1027
|
+
tool: { type: "string" },
|
|
1028
|
+
input: { type: "object", additionalProperties: true },
|
|
1029
|
+
},
|
|
1030
|
+
required: ["tool", "input"],
|
|
1031
|
+
},
|
|
1032
|
+
} as any,
|
|
1015
1033
|
},
|
|
1016
1034
|
["message"],
|
|
1017
1035
|
),
|
|
@@ -1024,6 +1042,9 @@ function askAppTool(
|
|
|
1024
1042
|
const maxWaitMs = isExplicitAsyncAsk(args.async)
|
|
1025
1043
|
? 0
|
|
1026
1044
|
: boundedAskAppWaitMs(args.maxWaitMs);
|
|
1045
|
+
const approvedActions = Array.isArray(args.approvedActions)
|
|
1046
|
+
? (args.approvedActions as A2AApprovedAction[])
|
|
1047
|
+
: undefined;
|
|
1027
1048
|
|
|
1028
1049
|
// Cross-app: the caller named a *different* workspace app. Route the
|
|
1029
1050
|
// message to THAT app's agent over A2A (its `/_agent-native/a2a`
|
|
@@ -1040,6 +1061,7 @@ function askAppTool(
|
|
|
1040
1061
|
durable: useDurableA2A,
|
|
1041
1062
|
maxWaitMs,
|
|
1042
1063
|
requestOrigin: targetApp.origin,
|
|
1064
|
+
approvedActions,
|
|
1043
1065
|
},
|
|
1044
1066
|
);
|
|
1045
1067
|
} catch (err: any) {
|
|
@@ -1074,6 +1096,7 @@ function askAppTool(
|
|
|
1074
1096
|
durable: useDurableA2A,
|
|
1075
1097
|
maxWaitMs,
|
|
1076
1098
|
requestOrigin: dirMatch.url,
|
|
1099
|
+
approvedActions,
|
|
1077
1100
|
},
|
|
1078
1101
|
);
|
|
1079
1102
|
} catch (err: any) {
|
|
@@ -1120,6 +1143,7 @@ function askAppTool(
|
|
|
1120
1143
|
},
|
|
1121
1144
|
message,
|
|
1122
1145
|
maxWaitMs,
|
|
1146
|
+
approvedActions,
|
|
1123
1147
|
);
|
|
1124
1148
|
}
|
|
1125
1149
|
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
shouldPreferGlobalA2ASecret,
|
|
7
7
|
signA2AToken,
|
|
8
8
|
} from "../a2a/client.js";
|
|
9
|
-
import type { Task } from "../a2a/types.js";
|
|
9
|
+
import type { A2AApprovedAction, Task } from "../a2a/types.js";
|
|
10
10
|
import {
|
|
11
11
|
formatLlmCredentialErrorMessage,
|
|
12
12
|
isLlmCredentialError,
|
|
@@ -112,17 +112,34 @@ export const tool: ActionTool = {
|
|
|
112
112
|
type: "string",
|
|
113
113
|
description: "The message/question to send to the other agent",
|
|
114
114
|
},
|
|
115
|
+
approvedActions: {
|
|
116
|
+
type: "array",
|
|
117
|
+
description:
|
|
118
|
+
"Exact downstream tool calls the current user explicitly authorized in this chat. Never infer authorization or include a broader/different action.",
|
|
119
|
+
items: {
|
|
120
|
+
type: "object",
|
|
121
|
+
properties: {
|
|
122
|
+
tool: { type: "string" },
|
|
123
|
+
input: { type: "object", additionalProperties: true },
|
|
124
|
+
},
|
|
125
|
+
required: ["tool", "input"],
|
|
126
|
+
},
|
|
127
|
+
},
|
|
115
128
|
},
|
|
116
129
|
required: ["agent", "message"],
|
|
117
130
|
},
|
|
118
131
|
};
|
|
119
132
|
|
|
120
133
|
export async function run(
|
|
121
|
-
args: Record<string,
|
|
134
|
+
args: Record<string, unknown>,
|
|
122
135
|
context?: ActionRunContext,
|
|
123
136
|
selfAppId?: string,
|
|
124
137
|
): Promise<string> {
|
|
125
|
-
const
|
|
138
|
+
const agentIdOrName = String(args.agent ?? "");
|
|
139
|
+
const message = String(args.message ?? "");
|
|
140
|
+
const approvedActions = Array.isArray(args.approvedActions)
|
|
141
|
+
? (args.approvedActions as A2AApprovedAction[])
|
|
142
|
+
: undefined;
|
|
126
143
|
|
|
127
144
|
if (!agentIdOrName) return "Error: --agent is required";
|
|
128
145
|
if (!message) return "Error: --message is required";
|
|
@@ -320,6 +337,7 @@ export async function run(
|
|
|
320
337
|
userEmail: callerEmail,
|
|
321
338
|
orgDomain: callerOrgDomain,
|
|
322
339
|
orgSecret: callerOrgSecret,
|
|
340
|
+
approvedActions,
|
|
323
341
|
onUpdate: onRemotePollUpdate,
|
|
324
342
|
...(callTimeoutMs
|
|
325
343
|
? {
|
|
@@ -408,6 +426,7 @@ export async function run(
|
|
|
408
426
|
userEmail: email,
|
|
409
427
|
orgDomain: domain,
|
|
410
428
|
orgSecret,
|
|
429
|
+
approvedActions,
|
|
411
430
|
});
|
|
412
431
|
const sanitized =
|
|
413
432
|
formatDownstreamLlmCredentialFailure(agent.name, response) ?? response;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import crypto from "node:crypto";
|
|
1
2
|
import nodePath from "node:path";
|
|
2
3
|
|
|
3
4
|
import {
|
|
@@ -19,7 +20,10 @@ import {
|
|
|
19
20
|
isTrustedLocalRuntime,
|
|
20
21
|
} from "../a2a/auth-policy.js";
|
|
21
22
|
import { applyAgentTextEventToBuffer } from "../a2a/response-text.js";
|
|
22
|
-
import {
|
|
23
|
+
import {
|
|
24
|
+
createA2AApproval,
|
|
25
|
+
updateTaskStatusMessage,
|
|
26
|
+
} from "../a2a/task-store.js";
|
|
23
27
|
import type { ActionHttpConfig } from "../action.js";
|
|
24
28
|
import {
|
|
25
29
|
canUpdateAgentAppModelDefaultSettings,
|
|
@@ -52,6 +56,7 @@ import {
|
|
|
52
56
|
createProductionAgentHandler,
|
|
53
57
|
actionsToEngineTools,
|
|
54
58
|
executeAgentToolCall,
|
|
59
|
+
toolCallCacheKey,
|
|
55
60
|
getActiveRunForThreadAsync,
|
|
56
61
|
abortRunDurably,
|
|
57
62
|
subscribeToRun,
|
|
@@ -1171,6 +1176,25 @@ export function createAgentChatPlugin(
|
|
|
1171
1176
|
publicSkillsOnly: true,
|
|
1172
1177
|
streaming: true,
|
|
1173
1178
|
durableBackgroundRuns: options?.durableBackgroundRuns,
|
|
1179
|
+
executeApproval: async (approval) => {
|
|
1180
|
+
const result = await executeAgentToolCall({
|
|
1181
|
+
actions: mcpFullActions ?? allScripts,
|
|
1182
|
+
name: approval.tool,
|
|
1183
|
+
input: approval.input,
|
|
1184
|
+
callId: approval.callId,
|
|
1185
|
+
ownerEmail: approval.ownerEmail,
|
|
1186
|
+
orgId: approval.orgId ?? null,
|
|
1187
|
+
approvedToolCalls: [approval.approvalKey],
|
|
1188
|
+
});
|
|
1189
|
+
if (result.status === "approval_required") {
|
|
1190
|
+
return {
|
|
1191
|
+
status: "failed" as const,
|
|
1192
|
+
output:
|
|
1193
|
+
"The approved action was unexpectedly gated again and did not run.",
|
|
1194
|
+
};
|
|
1195
|
+
}
|
|
1196
|
+
return { status: result.status, output: result.output };
|
|
1197
|
+
},
|
|
1174
1198
|
handler: async function* (message, context) {
|
|
1175
1199
|
// Resolve the caller's identity for user-scoped data access.
|
|
1176
1200
|
// Priority: A2A-JWT verified email (set by the A2A handler in
|
|
@@ -1495,6 +1519,9 @@ export function createAgentChatPlugin(
|
|
|
1495
1519
|
// scope when a processor hop or alternate runner is involved.
|
|
1496
1520
|
ownerEmail: userEmail,
|
|
1497
1521
|
orgId: getRequestOrgId() ?? null,
|
|
1522
|
+
approvedToolCalls: context.approvedActions?.map((approved) =>
|
|
1523
|
+
toolCallCacheKey(approved.tool, approved.input),
|
|
1524
|
+
),
|
|
1498
1525
|
executionMode: "act",
|
|
1499
1526
|
send: (event) => {
|
|
1500
1527
|
a2aEvents.push(event);
|
|
@@ -1549,6 +1576,62 @@ export function createAgentChatPlugin(
|
|
|
1549
1576
|
},
|
|
1550
1577
|
);
|
|
1551
1578
|
|
|
1579
|
+
const approval = [...a2aEvents]
|
|
1580
|
+
.reverse()
|
|
1581
|
+
.find(
|
|
1582
|
+
(
|
|
1583
|
+
event,
|
|
1584
|
+
): event is Extract<
|
|
1585
|
+
AgentChatEvent,
|
|
1586
|
+
{ type: "approval_required" }
|
|
1587
|
+
> => event.type === "approval_required",
|
|
1588
|
+
);
|
|
1589
|
+
if (approval) {
|
|
1590
|
+
const pending = await createA2AApproval({
|
|
1591
|
+
taskId: context.taskId,
|
|
1592
|
+
ownerEmail: userEmail,
|
|
1593
|
+
orgId: getRequestOrgId() ?? null,
|
|
1594
|
+
tool: approval.tool,
|
|
1595
|
+
toolInput: approval.input,
|
|
1596
|
+
approvalKey: approval.approvalKey,
|
|
1597
|
+
callId: approval.toolCallId ?? crypto.randomUUID(),
|
|
1598
|
+
});
|
|
1599
|
+
const baseUrl = resolveArtifactBaseUrl(context.event);
|
|
1600
|
+
const approvalPath = `/_agent-native/a2a/approvals/${encodeURIComponent(pending.id)}`;
|
|
1601
|
+
const approvalUrl = baseUrl
|
|
1602
|
+
? `${baseUrl}${approvalPath}`
|
|
1603
|
+
: approvalPath;
|
|
1604
|
+
yield {
|
|
1605
|
+
role: "agent" as const,
|
|
1606
|
+
metadata: {
|
|
1607
|
+
agentNativeTaskState: "input-required",
|
|
1608
|
+
agentNativeApproval: {
|
|
1609
|
+
id: pending.id,
|
|
1610
|
+
tool: approval.tool,
|
|
1611
|
+
url: approvalUrl,
|
|
1612
|
+
},
|
|
1613
|
+
},
|
|
1614
|
+
parts: [
|
|
1615
|
+
{
|
|
1616
|
+
type: "text" as const,
|
|
1617
|
+
text:
|
|
1618
|
+
`Human approval is required to run ${approval.tool}. ` +
|
|
1619
|
+
`Open ${approvalUrl} to review and approve this one-time action.`,
|
|
1620
|
+
},
|
|
1621
|
+
{
|
|
1622
|
+
type: "data" as const,
|
|
1623
|
+
data: {
|
|
1624
|
+
kind: "agent-native/approval-required",
|
|
1625
|
+
approvalId: pending.id,
|
|
1626
|
+
tool: approval.tool,
|
|
1627
|
+
approvalUrl,
|
|
1628
|
+
},
|
|
1629
|
+
},
|
|
1630
|
+
],
|
|
1631
|
+
};
|
|
1632
|
+
return;
|
|
1633
|
+
}
|
|
1634
|
+
|
|
1552
1635
|
const { responseText, finalText } = assembleA2AFinalResponse(
|
|
1553
1636
|
a2aEvents,
|
|
1554
1637
|
a2aToolResults,
|
|
@@ -5621,6 +5704,8 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
|
|
|
5621
5704
|
"/_agent-native/agent-model-defaults",
|
|
5622
5705
|
"/_agent-native/mcp",
|
|
5623
5706
|
"/mcp",
|
|
5707
|
+
"/.well-known/agent-card.json",
|
|
5708
|
+
"/_agent-native/a2a",
|
|
5624
5709
|
],
|
|
5625
5710
|
});
|
|
5626
5711
|
};
|
|
@@ -104,9 +104,12 @@ import type { BetterAuthConfig } from "./better-auth-instance.js";
|
|
|
104
104
|
import {
|
|
105
105
|
BUILDER_CONNECT_OWNER_COOKIE,
|
|
106
106
|
BUILDER_CONNECT_PARAM,
|
|
107
|
+
BUILDER_RELAY_PATH,
|
|
108
|
+
BUILDER_RELAY_STATE_PARAM,
|
|
107
109
|
BUILDER_STATE_PARAM,
|
|
108
110
|
verifyBuilderCallbackStateAndGetOwner,
|
|
109
111
|
verifyBuilderConnectTokenAndGetOwner,
|
|
112
|
+
verifyBuilderPreviewRelayStateForCallback,
|
|
110
113
|
} from "./builder-browser.js";
|
|
111
114
|
import { resolveAuthCookieNamespace } from "./cookie-namespace.js";
|
|
112
115
|
import {
|
|
@@ -1522,7 +1525,15 @@ function verifiedBuilderConnectOwnerFromUrl(url: string): string | null {
|
|
|
1522
1525
|
return verifyBuilderConnectTokenAndGetOwner(token);
|
|
1523
1526
|
}
|
|
1524
1527
|
|
|
1525
|
-
function shouldBypassAuthForBuilderConnect(
|
|
1528
|
+
export function shouldBypassAuthForBuilderConnect(
|
|
1529
|
+
event: H3Event,
|
|
1530
|
+
p: string,
|
|
1531
|
+
): boolean {
|
|
1532
|
+
// The preview-safe second hop is authenticated by its timestamped HMAC and
|
|
1533
|
+
// one-shot pending row. It cannot carry a browser session from the corporate
|
|
1534
|
+
// callback deployment, so let the route perform that stronger check itself.
|
|
1535
|
+
if (p === BUILDER_RELAY_PATH) return true;
|
|
1536
|
+
|
|
1526
1537
|
if (p === "/_agent-native/builder/connect") {
|
|
1527
1538
|
const url = event.node?.req?.url ?? event.path ?? "/";
|
|
1528
1539
|
return Boolean(verifiedBuilderConnectOwnerFromUrl(url));
|
|
@@ -1537,6 +1548,19 @@ function shouldBypassAuthForBuilderConnect(event: H3Event, p: string): boolean {
|
|
|
1537
1548
|
BUILDER_STATE_PARAM,
|
|
1538
1549
|
)
|
|
1539
1550
|
: null;
|
|
1551
|
+
const relayState =
|
|
1552
|
+
queryStart >= 0
|
|
1553
|
+
? new URLSearchParams(url.slice(queryStart + 1)).get(
|
|
1554
|
+
BUILDER_RELAY_STATE_PARAM,
|
|
1555
|
+
)
|
|
1556
|
+
: null;
|
|
1557
|
+
if (relayState) {
|
|
1558
|
+
try {
|
|
1559
|
+
if (verifyBuilderPreviewRelayStateForCallback(relayState)) return true;
|
|
1560
|
+
} catch {
|
|
1561
|
+
// Dedicated relay secret missing: let the auth guard fail closed.
|
|
1562
|
+
}
|
|
1563
|
+
}
|
|
1540
1564
|
// The signed `_an_state` authenticates this specific Builder callback
|
|
1541
1565
|
// flow back to our app. A stale localhost session cookie can otherwise
|
|
1542
1566
|
// make the global guard reject the callback before the handler gets to
|