@agent-native/core 0.107.0 → 0.107.2
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 +16 -0
- package/corpus/core/docs/content/integrations.mdx +27 -27
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/a2a/artifact-response.ts +32 -10
- package/corpus/core/src/agent/production-agent.ts +19 -0
- package/corpus/core/src/agent/run-store.ts +98 -2
- package/corpus/core/src/client/AssistantChat.tsx +13 -0
- package/corpus/core/src/client/CommandMenu.tsx +5 -0
- package/corpus/core/src/client/active-run-state.ts +34 -0
- package/corpus/core/src/client/agent-chat-adapter.ts +4 -0
- package/corpus/core/src/client/resources/McpConnectionSuggestion.tsx +41 -11
- package/corpus/core/src/client/resources/McpIntegrationDialog.tsx +27 -9
- package/corpus/core/src/client/resources/mcp-integration-catalog.ts +45 -0
- package/corpus/core/src/client/sharing/ShareButton.tsx +30 -9
- package/corpus/core/src/client/use-agent-chat-home-handoff.ts +2 -2
- package/corpus/core/src/integrations/a2a-continuation-processor.ts +107 -3
- package/corpus/core/src/integrations/pending-tasks-store.ts +98 -1
- package/corpus/core/src/integrations/plugin.ts +129 -4
- package/corpus/core/src/integrations/webhook-handler.ts +339 -36
- package/corpus/core/src/localization/default-messages.ts +4 -1
- package/corpus/core/src/secrets/register-framework-secrets.ts +28 -0
- package/corpus/core/src/server/agent-chat-plugin.ts +122 -9
- package/corpus/core/src/vite/client.ts +24 -0
- package/corpus/templates/analytics/.agents/skills/dashboard-management/SKILL.md +29 -21
- package/corpus/templates/analytics/AGENTS.md +8 -0
- package/corpus/templates/analytics/actions/dashboard-mutation-api.ts +1 -1
- package/corpus/templates/analytics/actions/update-dashboard.ts +6 -2
- package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +35 -7
- package/corpus/templates/analytics/app/components/layout/Layout.tsx +1 -3
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +11 -1
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/extension-slot.ts +11 -0
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +27 -0
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/types.ts +6 -0
- package/corpus/templates/analytics/changelog/2026-07-17-dashboard-extension-boxes.md +6 -0
- package/corpus/templates/analytics/server/lib/agent-readable-resource-context.ts +8 -0
- package/corpus/templates/analytics/server/plugins/agent-chat.ts +1 -0
- package/corpus/templates/assets/changelog/2026-07-17-the-agent-chat-sidebar-stays-closed-until-you-open-it-or-sta.md +6 -0
- package/corpus/templates/brain/app/hooks/use-navigation-state.ts +6 -1
- package/corpus/templates/brain/changelog/2026-07-17-the-agent-chat-sidebar-stays-closed-until-you-open-it-or-sta.md +6 -0
- package/corpus/templates/calendar/app/components/layout/AppLayout.tsx +1 -1
- package/corpus/templates/calendar/changelog/2026-07-17-the-agent-chat-sidebar-stays-closed-until-you-open-it-or-sta.md +6 -0
- package/corpus/templates/chat/app/hooks/use-navigation-state.ts +4 -1
- package/corpus/templates/chat/changelog/2026-07-17-the-agent-chat-sidebar-stays-closed-until-you-open-it-or-sta.md +6 -0
- package/corpus/templates/clips/app/components/library/library-layout.tsx +1 -1
- package/corpus/templates/clips/changelog/2026-07-17-the-agent-chat-sidebar-stays-closed-until-you-open-it-or-sta.md +6 -0
- package/corpus/templates/content/actions/_content-space-access.ts +45 -2
- package/corpus/templates/content/actions/create-content-database.ts +41 -7
- package/corpus/templates/content/app/components/layout/Layout.tsx +1 -1
- package/corpus/templates/content/app/root.tsx +1 -10
- package/corpus/templates/content/changelog/2026-07-17-creating-a-database-now-completes-reliably-in-hosted-workspa.md +6 -0
- package/corpus/templates/content/changelog/2026-07-17-the-agent-chat-sidebar-stays-closed-until-you-open-it-or-sta.md +6 -0
- package/corpus/templates/dispatch/app/hooks/use-navigation-state.ts +4 -1
- package/corpus/templates/dispatch/changelog/2026-07-17-the-agent-chat-sidebar-stays-closed-until-you-open-it-or-sta.md +6 -0
- package/corpus/templates/forms/app/components/layout/Layout.tsx +2 -4
- package/corpus/templates/forms/app/components/ui/popover.tsx +25 -1
- package/corpus/templates/forms/app/hooks/use-navigation-state.ts +6 -1
- package/corpus/templates/forms/app/pages/FormBuilderPage.tsx +13 -10
- package/corpus/templates/forms/app/root.tsx +6 -1
- package/corpus/templates/forms/changelog/2026-07-17-form-builder-popovers-stay-within-the-viewport.md +6 -0
- package/corpus/templates/forms/changelog/2026-07-17-form-editor-loading-matches-current-sidebar-free-layout.md +6 -0
- package/corpus/templates/forms/changelog/2026-07-17-the-agent-chat-sidebar-stays-closed-until-you-open-it-or-sta.md +6 -0
- package/corpus/templates/mail/app/components/layout/AppLayout.tsx +1 -1
- package/corpus/templates/mail/changelog/2026-07-17-the-agent-chat-sidebar-stays-closed-until-you-open-it-or-sta.md +6 -0
- package/corpus/templates/plan/app/components/layout/Sidebar.tsx +14 -3
- package/corpus/templates/plan/app/hooks/use-navigation-state.ts +8 -1
- package/corpus/templates/plan/app/root.tsx +0 -2
- package/corpus/templates/plan/changelog/2026-07-17-the-agent-chat-sidebar-stays-closed-until-you-open-it-or-sta.md +6 -0
- package/corpus/templates/slides/app/components/layout/Layout.tsx +1 -1
- package/corpus/templates/slides/app/context/DeckContext.tsx +23 -23
- package/corpus/templates/slides/changelog/2026-07-17-duplicated-slides-now-stay-in-the-deck.md +6 -0
- package/corpus/templates/slides/changelog/2026-07-17-the-agent-chat-sidebar-stays-closed-until-you-open-it-or-sta.md +6 -0
- package/corpus/templates/tasks/app/components/layout/Layout.tsx +2 -13
- package/corpus/templates/tasks/changelog/2026-07-17-the-agent-chat-sidebar-stays-closed-until-you-open-it.md +6 -0
- package/dist/a2a/artifact-response.d.ts +5 -1
- package/dist/a2a/artifact-response.d.ts.map +1 -1
- package/dist/a2a/artifact-response.js +18 -12
- package/dist/a2a/artifact-response.js.map +1 -1
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +13 -1
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/agent/run-store.d.ts +17 -0
- package/dist/agent/run-store.d.ts.map +1 -1
- package/dist/agent/run-store.js +84 -2
- package/dist/agent/run-store.js.map +1 -1
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +10 -1
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/CommandMenu.d.ts.map +1 -1
- package/dist/client/CommandMenu.js +4 -0
- package/dist/client/CommandMenu.js.map +1 -1
- package/dist/client/active-run-state.d.ts +7 -0
- package/dist/client/active-run-state.d.ts.map +1 -1
- package/dist/client/active-run-state.js +28 -0
- package/dist/client/active-run-state.js.map +1 -1
- package/dist/client/agent-chat-adapter.d.ts.map +1 -1
- package/dist/client/agent-chat-adapter.js +4 -1
- package/dist/client/agent-chat-adapter.js.map +1 -1
- package/dist/client/resources/McpConnectionSuggestion.d.ts.map +1 -1
- package/dist/client/resources/McpConnectionSuggestion.js +27 -8
- package/dist/client/resources/McpConnectionSuggestion.js.map +1 -1
- package/dist/client/resources/McpIntegrationDialog.d.ts.map +1 -1
- package/dist/client/resources/McpIntegrationDialog.js +4 -2
- package/dist/client/resources/McpIntegrationDialog.js.map +1 -1
- package/dist/client/resources/mcp-integration-catalog.d.ts +6 -0
- package/dist/client/resources/mcp-integration-catalog.d.ts.map +1 -1
- package/dist/client/resources/mcp-integration-catalog.js +33 -0
- package/dist/client/resources/mcp-integration-catalog.js.map +1 -1
- package/dist/client/sharing/ShareButton.d.ts.map +1 -1
- package/dist/client/sharing/ShareButton.js +15 -12
- package/dist/client/sharing/ShareButton.js.map +1 -1
- package/dist/client/use-agent-chat-home-handoff.d.ts +1 -1
- package/dist/client/use-agent-chat-home-handoff.d.ts.map +1 -1
- package/dist/client/use-agent-chat-home-handoff.js +1 -1
- package/dist/client/use-agent-chat-home-handoff.js.map +1 -1
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/awareness.d.ts.map +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/integrations/a2a-continuation-processor.js +62 -5
- package/dist/integrations/a2a-continuation-processor.js.map +1 -1
- package/dist/integrations/pending-tasks-store.d.ts +3 -0
- package/dist/integrations/pending-tasks-store.d.ts.map +1 -1
- package/dist/integrations/pending-tasks-store.js +75 -1
- package/dist/integrations/pending-tasks-store.js.map +1 -1
- package/dist/integrations/plugin.d.ts.map +1 -1
- package/dist/integrations/plugin.js +81 -5
- package/dist/integrations/plugin.js.map +1 -1
- package/dist/integrations/webhook-handler.d.ts +23 -2
- package/dist/integrations/webhook-handler.d.ts.map +1 -1
- package/dist/integrations/webhook-handler.js +257 -35
- package/dist/integrations/webhook-handler.js.map +1 -1
- package/dist/localization/default-messages.d.ts +2 -0
- package/dist/localization/default-messages.d.ts.map +1 -1
- package/dist/localization/default-messages.js +3 -1
- package/dist/localization/default-messages.js.map +1 -1
- package/dist/notifications/routes.d.ts +2 -2
- package/dist/observability/routes.d.ts +5 -5
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/secrets/register-framework-secrets.d.ts.map +1 -1
- package/dist/secrets/register-framework-secrets.js +25 -0
- package/dist/secrets/register-framework-secrets.js.map +1 -1
- package/dist/secrets/routes.d.ts +9 -9
- package/dist/server/agent-chat-plugin.d.ts +6 -0
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +94 -7
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/templates/chat/app/hooks/use-navigation-state.ts +4 -1
- package/dist/templates/chat/changelog/2026-07-17-the-agent-chat-sidebar-stays-closed-until-you-open-it-or-sta.md +6 -0
- package/dist/vite/client.d.ts.map +1 -1
- package/dist/vite/client.js +20 -0
- package/dist/vite/client.js.map +1 -1
- package/docs/content/integrations.mdx +27 -27
- package/package.json +1 -1
- package/src/templates/chat/app/hooks/use-navigation-state.ts +4 -1
- package/src/templates/chat/changelog/2026-07-17-the-agent-chat-sidebar-stays-closed-until-you-open-it-or-sta.md +6 -0
package/corpus/README.md
CHANGED
package/corpus/core/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# @agent-native/core
|
|
2
2
|
|
|
3
|
+
## 0.107.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 2a4d2db: Retry messaging replies without repeating successful agent mutations, and deliver verified A2A artifact checkpoints as soon as they are durable.
|
|
8
|
+
|
|
9
|
+
## 0.107.1
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- 8e0afec: Preserve chat continuation context after stale background workers and make Stop durable before a serverless run id exists.
|
|
14
|
+
- 8e0afec: Offer the Figma REST API personal access token fallback when Figma MCP links are restricted.
|
|
15
|
+
- 8e0afec: Add a practical guide for organization context, team roles, resource permissions, RBAC, and framework environment variables.
|
|
16
|
+
- 8e0afec: Keep empty full-page chat navigation from automatically opening the AgentSidebar.
|
|
17
|
+
- 8e0afec: Keep the share popover open while adding people and preserve unfinished invite emails when it is reopened.
|
|
18
|
+
|
|
3
19
|
## 0.107.0
|
|
4
20
|
|
|
5
21
|
### Minor Changes
|
|
@@ -488,33 +488,33 @@ endpoint is reachable or cataloged, but a live provider authorization or tool
|
|
|
488
488
|
session still needs to be completed. **Restricted** entries remain discoverable
|
|
489
489
|
but need provider or administrator setup before a generic connection can work.
|
|
490
490
|
|
|
491
|
-
| Integration | Connection mode | Status | Endpoint | Setup and notes
|
|
492
|
-
| ------------------------------------------------------------------------------------------------------------------------------ | ---------------------- | ---------------------------------- | ----------------------------------------- |
|
|
493
|
-
| [Context7](https://context7.com/) | No auth | Ready · verified | `https://mcp.context7.com/mcp` | Fetch current library and framework docs.
|
|
494
|
-
| [Sentry](https://docs.sentry.io/product/sentry-mcp/) | Header / token | Ready · preflight only | `https://mcp.sentry.dev/mcp` | Add a Sentry bearer token as the `Authorization` header.
|
|
495
|
-
| [Notion](https://developers.notion.com/guides/mcp/get-started-with-mcp) | OAuth | Ready · preflight only | `https://mcp.notion.com/mcp` | User OAuth; enterprise admins can audit or restrict MCP clients.
|
|
496
|
-
| [Semgrep](https://github.com/semgrep/mcp#readme) | No auth | Ready · preflight only | `https://mcp.semgrep.ai/mcp` | Scan code for security findings.
|
|
497
|
-
| [Linear](https://linear.app/docs/mcp) | OAuth | Ready · preflight only | `https://mcp.linear.app/mcp` | Authorize the workspace and issue permissions required by the workflow.
|
|
498
|
-
| [Atlassian Rovo MCP](https://developer.atlassian.com/cloud/rovo-mcp/guides/getting-started/) | OAuth + provider setup | Restricted | `https://mcp.atlassian.com/v1/mcp/authv2` | Admins may need to trust the app origin and enable Rovo Read, Write, and Search permissions.
|
|
499
|
-
| [Supabase](https://www.builder.io/c/docs/fusion-connect-to-supabase) | OAuth | Ready · preflight only | `https://mcp.supabase.com/mcp` | Authorize the Supabase project and requested backend scopes.
|
|
500
|
-
| [Neon](https://www.builder.io/c/docs/fusion-connect-to-neon) | OAuth | Ready · preflight only | `https://mcp.neon.tech/sse` | Authorize access to the serverless Postgres projects needed by the app.
|
|
501
|
-
| [Stripe](https://docs.stripe.com/mcp) | OAuth | Ready · preflight only | `https://mcp.stripe.com` | Review payment, customer, and subscription permissions before authorizing.
|
|
502
|
-
| [Cloudflare](https://developers.cloudflare.com/agents/model-context-protocol/cloudflare/servers-for-cloudflare/) | OAuth | Ready · preflight only | `https://mcp.cloudflare.com/mcp` | Choose the narrowest Cloudflare server and review scopes.
|
|
503
|
-
| [GitLab](https://docs.gitlab.com/user/model_context_protocol/mcp_server/) | OAuth + provider setup | Beta · restricted | `https://gitlab.com/api/v4/mcp` | A top-level group admin, or the equivalent self-managed instance admin, must allow MCP.
|
|
504
|
-
| [Figma](https://developers.figma.com/docs/figma-mcp-server/) | Manual setup | Approved clients only · restricted | `https://mcp.figma.com/mcp` | Figma only allows clients in its MCP Catalog
|
|
505
|
-
| [Canva](https://www.canva.dev/docs/mcp/) | Manual setup | Approved domains · restricted | `https://mcp.canva.com/mcp` | Per-user OAuth; clients must allow Canva's canva.com and canva.ai domains and follow the current redirect setup.
|
|
506
|
-
| [Vercel](https://vercel.com/docs/agent-resources/vercel-mcp) | Manual setup | Approved clients only · restricted | `https://mcp.vercel.com` | Vercel must list the client as approved before a generic connection will work.
|
|
507
|
-
| [GitHub](https://github.com/github/github-mcp-server) | Manual setup | Provider setup · restricted | `https://api.githubcopilot.com/mcp/` | Use a registered OAuth app; organizations may also enforce OAuth App Access Policies.
|
|
508
|
-
| [Slack](https://docs.slack.dev/ai/slack-mcp-server/) | Manual setup | Approved clients only · restricted | `https://mcp.slack.com/mcp` | Requires a fixed registered Slack app; dynamic client registration is not supported.
|
|
509
|
-
| [Asana](https://developers.asana.com/docs/integrating-with-asanas-mcp-server) | Manual setup | Provider setup · restricted | `https://mcp.asana.com/v2/mcp` | Pre-register an Asana MCP OAuth app before connecting.
|
|
510
|
-
| [HubSpot](https://developers.hubspot.com/docs/apps/developer-platform/build-apps/integrate-with-the-remote-hubspot-mcp-server) | Manual setup | Provider setup · restricted | `https://mcp.hubspot.com` | Create a HubSpot MCP Auth App with PKCE; the existing HubSpot OAuth connector remains available to app actions.
|
|
511
|
-
| [Intercom](https://developers.intercom.com/docs/guides/mcp) | OAuth | Ready · preflight only | `https://mcp.intercom.com/mcp` | Available for US-hosted workspaces; confirm region and scopes during authorization.
|
|
512
|
-
| [monday.com](https://developer.monday.com/api-reference/docs/build-on-monday-with-ai) | OAuth | Ready · preflight only | `https://mcp.monday.com/mcp` | Choose the workspace and permissions to share during authorization.
|
|
513
|
-
| [Webflow](https://developers.webflow.com/mcp/reference/getting-started) | OAuth | Ready · preflight only | `https://mcp.webflow.com/mcp` | Designer capabilities may install Webflow's Bridge App; Data API access is separate.
|
|
514
|
-
| [PayPal](https://developer.paypal.com/ai-tools/mcp-server/) | OAuth | Ready · preflight only | `https://mcp.paypal.com/sse` | Review merchant permissions before authorizing the remote server.
|
|
515
|
-
| [Box](https://developer.box.com/guides/box-mcp) | Manual setup | Beta · restricted | `https://mcp.box.com` | An administrator must enable Box MCP; custom clients also need credentials, a redirect URI, and approved scopes.
|
|
516
|
-
| [Netlify](https://docs.netlify.com/build/build-with-ai/agent-setup-guides/agent-setup-overview/) | OAuth | Ready · preflight only | `https://netlify-mcp.netlify.app/mcp` | Review site and team permissions before completing OAuth.
|
|
517
|
-
| [Zapier MCP](https://help.zapier.com/hc/en-us/articles/36265392843917-Use-Zapier-MCP-with-your-client) | Header / token | User-created server · restricted | `https://mcp.zapier.com/api/v1/connect` | Create the MCP server in Zapier, then paste its generated bearer token into the header field.
|
|
491
|
+
| Integration | Connection mode | Status | Endpoint | Setup and notes |
|
|
492
|
+
| ------------------------------------------------------------------------------------------------------------------------------ | ---------------------- | ---------------------------------- | ----------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
493
|
+
| [Context7](https://context7.com/) | No auth | Ready · verified | `https://mcp.context7.com/mcp` | Fetch current library and framework docs. |
|
|
494
|
+
| [Sentry](https://docs.sentry.io/product/sentry-mcp/) | Header / token | Ready · preflight only | `https://mcp.sentry.dev/mcp` | Add a Sentry bearer token as the `Authorization` header. |
|
|
495
|
+
| [Notion](https://developers.notion.com/guides/mcp/get-started-with-mcp) | OAuth | Ready · preflight only | `https://mcp.notion.com/mcp` | User OAuth; enterprise admins can audit or restrict MCP clients. |
|
|
496
|
+
| [Semgrep](https://github.com/semgrep/mcp#readme) | No auth | Ready · preflight only | `https://mcp.semgrep.ai/mcp` | Scan code for security findings. |
|
|
497
|
+
| [Linear](https://linear.app/docs/mcp) | OAuth | Ready · preflight only | `https://mcp.linear.app/mcp` | Authorize the workspace and issue permissions required by the workflow. |
|
|
498
|
+
| [Atlassian Rovo MCP](https://developer.atlassian.com/cloud/rovo-mcp/guides/getting-started/) | OAuth + provider setup | Restricted | `https://mcp.atlassian.com/v1/mcp/authv2` | Admins may need to trust the app origin and enable Rovo Read, Write, and Search permissions. |
|
|
499
|
+
| [Supabase](https://www.builder.io/c/docs/fusion-connect-to-supabase) | OAuth | Ready · preflight only | `https://mcp.supabase.com/mcp` | Authorize the Supabase project and requested backend scopes. |
|
|
500
|
+
| [Neon](https://www.builder.io/c/docs/fusion-connect-to-neon) | OAuth | Ready · preflight only | `https://mcp.neon.tech/sse` | Authorize access to the serverless Postgres projects needed by the app. |
|
|
501
|
+
| [Stripe](https://docs.stripe.com/mcp) | OAuth | Ready · preflight only | `https://mcp.stripe.com` | Review payment, customer, and subscription permissions before authorizing. |
|
|
502
|
+
| [Cloudflare](https://developers.cloudflare.com/agents/model-context-protocol/cloudflare/servers-for-cloudflare/) | OAuth | Ready · preflight only | `https://mcp.cloudflare.com/mcp` | Choose the narrowest Cloudflare server and review scopes. |
|
|
503
|
+
| [GitLab](https://docs.gitlab.com/user/model_context_protocol/mcp_server/) | OAuth + provider setup | Beta · restricted | `https://gitlab.com/api/v4/mcp` | A top-level group admin, or the equivalent self-managed instance admin, must allow MCP. |
|
|
504
|
+
| [Figma](https://developers.figma.com/docs/figma-mcp-server/) | Manual setup | Approved clients only · restricted | `https://mcp.figma.com/mcp` | Figma only allows clients in its MCP Catalog. Use the [Figma REST API personal access token fallback](https://developers.figma.com/docs/rest-api/personal-access-tokens/) for file and node reads until Agent Native is approved. |
|
|
505
|
+
| [Canva](https://www.canva.dev/docs/mcp/) | Manual setup | Approved domains · restricted | `https://mcp.canva.com/mcp` | Per-user OAuth; clients must allow Canva's canva.com and canva.ai domains and follow the current redirect setup. |
|
|
506
|
+
| [Vercel](https://vercel.com/docs/agent-resources/vercel-mcp) | Manual setup | Approved clients only · restricted | `https://mcp.vercel.com` | Vercel must list the client as approved before a generic connection will work. |
|
|
507
|
+
| [GitHub](https://github.com/github/github-mcp-server) | Manual setup | Provider setup · restricted | `https://api.githubcopilot.com/mcp/` | Use a registered OAuth app; organizations may also enforce OAuth App Access Policies. |
|
|
508
|
+
| [Slack](https://docs.slack.dev/ai/slack-mcp-server/) | Manual setup | Approved clients only · restricted | `https://mcp.slack.com/mcp` | Requires a fixed registered Slack app; dynamic client registration is not supported. |
|
|
509
|
+
| [Asana](https://developers.asana.com/docs/integrating-with-asanas-mcp-server) | Manual setup | Provider setup · restricted | `https://mcp.asana.com/v2/mcp` | Pre-register an Asana MCP OAuth app before connecting. |
|
|
510
|
+
| [HubSpot](https://developers.hubspot.com/docs/apps/developer-platform/build-apps/integrate-with-the-remote-hubspot-mcp-server) | Manual setup | Provider setup · restricted | `https://mcp.hubspot.com` | Create a HubSpot MCP Auth App with PKCE; the existing HubSpot OAuth connector remains available to app actions. |
|
|
511
|
+
| [Intercom](https://developers.intercom.com/docs/guides/mcp) | OAuth | Ready · preflight only | `https://mcp.intercom.com/mcp` | Available for US-hosted workspaces; confirm region and scopes during authorization. |
|
|
512
|
+
| [monday.com](https://developer.monday.com/api-reference/docs/build-on-monday-with-ai) | OAuth | Ready · preflight only | `https://mcp.monday.com/mcp` | Choose the workspace and permissions to share during authorization. |
|
|
513
|
+
| [Webflow](https://developers.webflow.com/mcp/reference/getting-started) | OAuth | Ready · preflight only | `https://mcp.webflow.com/mcp` | Designer capabilities may install Webflow's Bridge App; Data API access is separate. |
|
|
514
|
+
| [PayPal](https://developer.paypal.com/ai-tools/mcp-server/) | OAuth | Ready · preflight only | `https://mcp.paypal.com/sse` | Review merchant permissions before authorizing the remote server. |
|
|
515
|
+
| [Box](https://developer.box.com/guides/box-mcp) | Manual setup | Beta · restricted | `https://mcp.box.com` | An administrator must enable Box MCP; custom clients also need credentials, a redirect URI, and approved scopes. |
|
|
516
|
+
| [Netlify](https://docs.netlify.com/build/build-with-ai/agent-setup-guides/agent-setup-overview/) | OAuth | Ready · preflight only | `https://netlify-mcp.netlify.app/mcp` | Review site and team permissions before completing OAuth. |
|
|
517
|
+
| [Zapier MCP](https://help.zapier.com/hc/en-us/articles/36265392843917-Use-Zapier-MCP-with-your-client) | Header / token | User-created server · restricted | `https://mcp.zapier.com/api/v1/connect` | Create the MCP server in Zapier, then paste its generated bearer token into the header field. |
|
|
518
518
|
|
|
519
519
|
### Repeatable preflight verification
|
|
520
520
|
|
package/corpus/core/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-native/core",
|
|
3
|
-
"version": "0.107.
|
|
3
|
+
"version": "0.107.2",
|
|
4
4
|
"description": "Framework for agent-native application development — where AI agents and UI share SQL state, actions, and context",
|
|
5
5
|
"homepage": "https://github.com/BuilderIO/agent-native#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -11,6 +11,11 @@ export interface A2AArtifactResponseOptions {
|
|
|
11
11
|
baseUrl?: string;
|
|
12
12
|
includeReferencedArtifacts?: boolean;
|
|
13
13
|
includePersistedArtifactMarker?: boolean;
|
|
14
|
+
persistedArtifactSecret?: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface A2AArtifactIdentityOptions {
|
|
18
|
+
persistedArtifactSecrets?: readonly string[];
|
|
14
19
|
}
|
|
15
20
|
|
|
16
21
|
export interface A2AArtifactIdentity {
|
|
@@ -74,21 +79,26 @@ const ARTIFACT_RESOURCE_TYPES = new Set<A2AArtifactIdentity["resourceType"]>([
|
|
|
74
79
|
|
|
75
80
|
function persistedArtifactIdentitiesFromMarker(
|
|
76
81
|
result: string,
|
|
82
|
+
secrets: readonly string[] = process.env.A2A_SECRET
|
|
83
|
+
? [process.env.A2A_SECRET]
|
|
84
|
+
: [],
|
|
77
85
|
): A2AArtifactIdentity[] {
|
|
78
|
-
|
|
79
|
-
if (!secret) return [];
|
|
86
|
+
if (secrets.length === 0) return [];
|
|
80
87
|
const match = result.match(
|
|
81
88
|
/<!--\s*agent-native:persisted-artifacts=([A-Za-z0-9_-]+)\.([a-f0-9]{64})\s*-->/,
|
|
82
89
|
);
|
|
83
90
|
if (!match) return [];
|
|
84
91
|
try {
|
|
85
92
|
const payload = match[1];
|
|
86
|
-
const expected = createHmac("sha256", secret).update(payload).digest();
|
|
87
93
|
const supplied = Buffer.from(match[2], "hex");
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
94
|
+
const verified = secrets.some((secret) => {
|
|
95
|
+
const expected = createHmac("sha256", secret).update(payload).digest();
|
|
96
|
+
return (
|
|
97
|
+
supplied.length === expected.length &&
|
|
98
|
+
timingSafeEqual(supplied, expected)
|
|
99
|
+
);
|
|
100
|
+
});
|
|
101
|
+
if (!verified) {
|
|
92
102
|
return [];
|
|
93
103
|
}
|
|
94
104
|
const parsed = JSON.parse(Buffer.from(payload, "base64url").toString());
|
|
@@ -114,9 +124,15 @@ function persistedArtifactIdentitiesFromMarker(
|
|
|
114
124
|
function withPersistedArtifactMarker(
|
|
115
125
|
text: string,
|
|
116
126
|
toolResults: A2AToolResultSummary[],
|
|
127
|
+
secret = process.env.A2A_SECRET,
|
|
117
128
|
): string {
|
|
118
|
-
const
|
|
119
|
-
|
|
129
|
+
const verificationSecrets = [secret, process.env.A2A_SECRET].filter(
|
|
130
|
+
(value, index, values): value is string =>
|
|
131
|
+
!!value && values.indexOf(value) === index,
|
|
132
|
+
);
|
|
133
|
+
const identities = extractA2AArtifactIdentities(toolResults, {
|
|
134
|
+
persistedArtifactSecrets: verificationSecrets,
|
|
135
|
+
}).slice(0, 12);
|
|
120
136
|
if (identities.length === 0 || !secret) return text;
|
|
121
137
|
const payload = Buffer.from(JSON.stringify(identities)).toString("base64url");
|
|
122
138
|
const signature = createHmac("sha256", secret).update(payload).digest("hex");
|
|
@@ -881,6 +897,7 @@ function collectArtifacts(results: A2AToolResultSummary[]): {
|
|
|
881
897
|
*/
|
|
882
898
|
export function extractA2AArtifactIdentities(
|
|
883
899
|
results: A2AToolResultSummary[],
|
|
900
|
+
options: A2AArtifactIdentityOptions = {},
|
|
884
901
|
): A2AArtifactIdentity[] {
|
|
885
902
|
const identities = new Map<string, A2AArtifactIdentity>();
|
|
886
903
|
|
|
@@ -894,6 +911,7 @@ export function extractA2AArtifactIdentities(
|
|
|
894
911
|
if (result.tool === "call-agent") {
|
|
895
912
|
for (const identity of persistedArtifactIdentitiesFromMarker(
|
|
896
913
|
result.result,
|
|
914
|
+
options.persistedArtifactSecrets,
|
|
897
915
|
)) {
|
|
898
916
|
remember({ ...identity, sourceAction: "call-agent" });
|
|
899
917
|
}
|
|
@@ -1387,7 +1405,11 @@ export function appendA2AArtifactLinks(
|
|
|
1387
1405
|
options.includeReferencedArtifacts ?? false;
|
|
1388
1406
|
const finalize = (value: string) =>
|
|
1389
1407
|
options.includePersistedArtifactMarker
|
|
1390
|
-
? withPersistedArtifactMarker(
|
|
1408
|
+
? withPersistedArtifactMarker(
|
|
1409
|
+
value,
|
|
1410
|
+
toolResults,
|
|
1411
|
+
options.persistedArtifactSecret ?? process.env.A2A_SECRET,
|
|
1412
|
+
)
|
|
1391
1413
|
: value;
|
|
1392
1414
|
const {
|
|
1393
1415
|
documents,
|
|
@@ -136,6 +136,8 @@ import {
|
|
|
136
136
|
readLedgerEntry,
|
|
137
137
|
clearLedgerForThread,
|
|
138
138
|
insertRun,
|
|
139
|
+
isTurnAborted,
|
|
140
|
+
markRunAborted,
|
|
139
141
|
updateRunHeartbeat,
|
|
140
142
|
updateRunStatusIfRunning,
|
|
141
143
|
setRunError,
|
|
@@ -7058,6 +7060,13 @@ export function createProductionAgentHandler(
|
|
|
7058
7060
|
// slot and inserted the run row before dispatching, so re-claiming here
|
|
7059
7061
|
// would falsely 409 against the row the foreground holds.
|
|
7060
7062
|
if (threadId && !isBackgroundWorker) {
|
|
7063
|
+
if (
|
|
7064
|
+
typeof requestTurnId === "string" &&
|
|
7065
|
+
requestTurnId &&
|
|
7066
|
+
(await isTurnAborted(threadId, requestTurnId))
|
|
7067
|
+
) {
|
|
7068
|
+
return { ok: true, stopped: true };
|
|
7069
|
+
}
|
|
7061
7070
|
const slot = await tryClaimRunSlot(threadId);
|
|
7062
7071
|
if (!slot.claimed) {
|
|
7063
7072
|
setResponseStatus(event, 409);
|
|
@@ -7186,6 +7195,16 @@ export function createProductionAgentHandler(
|
|
|
7186
7195
|
);
|
|
7187
7196
|
}
|
|
7188
7197
|
|
|
7198
|
+
// Stop may land after the pre-claim check but before the durable row was
|
|
7199
|
+
// inserted. Terminalize that row before it can be handed to a worker.
|
|
7200
|
+
if (
|
|
7201
|
+
backgroundRowInserted &&
|
|
7202
|
+
(await isTurnAborted(effectiveThreadId, effectiveTurnId))
|
|
7203
|
+
) {
|
|
7204
|
+
await markRunAborted(runId, "user");
|
|
7205
|
+
return { ok: true, stopped: true };
|
|
7206
|
+
}
|
|
7207
|
+
|
|
7189
7208
|
let dispatched = false;
|
|
7190
7209
|
const backgroundDispatchPath = resolveAgentChatProcessRunDispatchPath();
|
|
7191
7210
|
const expectsNetlifyBackgroundFunction =
|
|
@@ -42,6 +42,21 @@ export const RUN_STALE_MS = 15_000;
|
|
|
42
42
|
*/
|
|
43
43
|
export const BACKGROUND_RUN_STALE_MS = 90_000;
|
|
44
44
|
|
|
45
|
+
/**
|
|
46
|
+
* A row is `background` only while the platform may still be cold-starting the
|
|
47
|
+
* worker, so it needs the full 90s handoff allowance above. Once that worker
|
|
48
|
+
* atomically claims the row (`background-processing`), it has already proved
|
|
49
|
+
* it started and should be reaped sooner if both heartbeat and real progress
|
|
50
|
+
* stop. This keeps a silent post-claim worker death from holding the client
|
|
51
|
+
* for the entire cold-start window before the durable successor is created.
|
|
52
|
+
*
|
|
53
|
+
* A real long-running tool or nested agent call still sets `in_flight_since`,
|
|
54
|
+
* which grants the bounded `IN_FLIGHT_RUN_STALE_GRACE_MS` below. Healthy model
|
|
55
|
+
* work keeps the normal heartbeat moving every 1.5s, so this is only a faster
|
|
56
|
+
* recovery path for a worker that has genuinely gone silent.
|
|
57
|
+
*/
|
|
58
|
+
export const BACKGROUND_PROCESSING_RUN_STALE_MS = 45_000;
|
|
59
|
+
|
|
45
60
|
export const STALE_RUN_ERROR_EVENT = {
|
|
46
61
|
type: "error",
|
|
47
62
|
error:
|
|
@@ -601,7 +616,7 @@ function backgroundAwareStaleCutoffSql(): string {
|
|
|
601
616
|
// `CAST(? AS BIGINT)` is required: without it Postgres infers the param as
|
|
602
617
|
// int4 from the int4 window literals, so the bound `Date.now()` ms epoch
|
|
603
618
|
// overflows int4. The cast keeps the subtraction 64-bit; a no-op on SQLite.
|
|
604
|
-
return `(CAST(? AS BIGINT) - CASE WHEN dispatch_mode LIKE 'background%' THEN ${BACKGROUND_RUN_STALE_MS} ELSE ${RUN_STALE_MS} END)`;
|
|
619
|
+
return `(CAST(? AS BIGINT) - CASE WHEN dispatch_mode = 'background-processing' THEN ${BACKGROUND_PROCESSING_RUN_STALE_MS} WHEN dispatch_mode LIKE 'background%' THEN ${BACKGROUND_RUN_STALE_MS} ELSE ${RUN_STALE_MS} END)`;
|
|
605
620
|
}
|
|
606
621
|
|
|
607
622
|
function terminalRunEventExclusionSql(runIdColumn = "id"): string {
|
|
@@ -1358,6 +1373,21 @@ function generateRecoveryRunId(): string {
|
|
|
1358
1373
|
return `run-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
1359
1374
|
}
|
|
1360
1375
|
|
|
1376
|
+
function staleRecoveryDispatchPayload(payload: string): string {
|
|
1377
|
+
try {
|
|
1378
|
+
const parsed = JSON.parse(payload);
|
|
1379
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
1380
|
+
return payload;
|
|
1381
|
+
}
|
|
1382
|
+
return JSON.stringify({
|
|
1383
|
+
...(parsed as Record<string, unknown>),
|
|
1384
|
+
internalContinuation: true,
|
|
1385
|
+
});
|
|
1386
|
+
} catch {
|
|
1387
|
+
return payload;
|
|
1388
|
+
}
|
|
1389
|
+
}
|
|
1390
|
+
|
|
1361
1391
|
/**
|
|
1362
1392
|
* FIX 3 (durable-background incident): when a stale-run reaper is about to
|
|
1363
1393
|
* flip a BACKGROUND chat-turn run to errored/stale_run, attempt to keep the
|
|
@@ -1451,7 +1481,15 @@ async function attemptStaleRunRecovery(
|
|
|
1451
1481
|
const now = Date.now();
|
|
1452
1482
|
await db.execute({
|
|
1453
1483
|
sql: `INSERT INTO agent_runs (id, thread_id, status, started_at, heartbeat_at, last_progress_at, turn_id, dispatch_mode, dispatch_payload) VALUES (?, ?, 'running', ?, ?, ?, ?, 'background', ?) ON CONFLICT (id) DO NOTHING`,
|
|
1454
|
-
args: [
|
|
1484
|
+
args: [
|
|
1485
|
+
successorRunId,
|
|
1486
|
+
threadId,
|
|
1487
|
+
now,
|
|
1488
|
+
now,
|
|
1489
|
+
now,
|
|
1490
|
+
turnId,
|
|
1491
|
+
staleRecoveryDispatchPayload(payload),
|
|
1492
|
+
],
|
|
1455
1493
|
});
|
|
1456
1494
|
return { outcome: "recovered", successorRunId, threadId, turnId };
|
|
1457
1495
|
}
|
|
@@ -1759,6 +1797,64 @@ export async function markRunAborted(
|
|
|
1759
1797
|
}
|
|
1760
1798
|
}
|
|
1761
1799
|
|
|
1800
|
+
function turnAbortMarkerRunId(turnId: string): string {
|
|
1801
|
+
return `turn-abort-${turnId}`;
|
|
1802
|
+
}
|
|
1803
|
+
|
|
1804
|
+
/** Records Stop before a foreground request has created its real run row. */
|
|
1805
|
+
export async function markTurnAborted(
|
|
1806
|
+
threadId: string,
|
|
1807
|
+
turnId: string,
|
|
1808
|
+
reason: string = "user",
|
|
1809
|
+
): Promise<void> {
|
|
1810
|
+
await ensureRunTables();
|
|
1811
|
+
const now = Date.now();
|
|
1812
|
+
const client = getDbExec();
|
|
1813
|
+
await client.execute({
|
|
1814
|
+
sql: `INSERT INTO agent_runs (id, thread_id, status, abort_reason, started_at, completed_at, heartbeat_at, last_progress_at, turn_id, terminal_reason, dispatch_mode) VALUES (?, ?, 'aborted', ?, ?, ?, ?, ?, ?, ?, 'turn-abort') ON CONFLICT (id) DO NOTHING`,
|
|
1815
|
+
args: [
|
|
1816
|
+
turnAbortMarkerRunId(turnId),
|
|
1817
|
+
threadId,
|
|
1818
|
+
reason,
|
|
1819
|
+
now,
|
|
1820
|
+
now,
|
|
1821
|
+
now,
|
|
1822
|
+
now,
|
|
1823
|
+
turnId,
|
|
1824
|
+
`aborted:${reason}`,
|
|
1825
|
+
],
|
|
1826
|
+
});
|
|
1827
|
+
const { rows } = await client.execute({
|
|
1828
|
+
sql: `SELECT id FROM agent_runs WHERE thread_id = ? AND turn_id = ? AND status = 'running'`,
|
|
1829
|
+
args: [threadId, turnId],
|
|
1830
|
+
});
|
|
1831
|
+
const runIds = rows
|
|
1832
|
+
.map((row) => String((row as { id?: unknown }).id ?? ""))
|
|
1833
|
+
.filter(Boolean);
|
|
1834
|
+
if (runIds.length === 0) return;
|
|
1835
|
+
await client.execute({
|
|
1836
|
+
sql: `UPDATE agent_runs SET status = 'aborted', abort_reason = ?, completed_at = ?, terminal_reason = ? WHERE thread_id = ? AND turn_id = ? AND status = 'running'`,
|
|
1837
|
+
args: [reason, Date.now(), `aborted:${reason}`, threadId, turnId],
|
|
1838
|
+
});
|
|
1839
|
+
await Promise.all(
|
|
1840
|
+
runIds.map((runId) =>
|
|
1841
|
+
safeAppendTerminalRunEvent(runId, { type: "done" }, "mark-turn-aborted"),
|
|
1842
|
+
),
|
|
1843
|
+
);
|
|
1844
|
+
}
|
|
1845
|
+
|
|
1846
|
+
export async function isTurnAborted(
|
|
1847
|
+
threadId: string,
|
|
1848
|
+
turnId: string,
|
|
1849
|
+
): Promise<boolean> {
|
|
1850
|
+
await ensureRunTables();
|
|
1851
|
+
const { rows } = await getDbExec().execute({
|
|
1852
|
+
sql: `SELECT id FROM agent_runs WHERE id = ? AND thread_id = ? AND status = 'aborted' LIMIT 1`,
|
|
1853
|
+
args: [turnAbortMarkerRunId(turnId), threadId],
|
|
1854
|
+
});
|
|
1855
|
+
return rows.length > 0;
|
|
1856
|
+
}
|
|
1857
|
+
|
|
1762
1858
|
export async function isRunAborted(runId: string): Promise<boolean> {
|
|
1763
1859
|
return (await getRunAbortState(runId)).aborted;
|
|
1764
1860
|
}
|
|
@@ -38,7 +38,9 @@ import React, {
|
|
|
38
38
|
import type { ReasoningEffort } from "../shared/reasoning-effort.js";
|
|
39
39
|
import {
|
|
40
40
|
ACTIVE_RUN_STATE_EVENT,
|
|
41
|
+
clearPendingTurnIfMatches,
|
|
41
42
|
clearActiveRunIfMatches,
|
|
43
|
+
getPendingTurn,
|
|
42
44
|
getActiveRunActivityTool,
|
|
43
45
|
getActiveRun,
|
|
44
46
|
resolveReconnectAfterSeq,
|
|
@@ -4281,6 +4283,7 @@ const AssistantChatInner = forwardRef<
|
|
|
4281
4283
|
}
|
|
4282
4284
|
const activeRun = getActiveRun();
|
|
4283
4285
|
const runIdToAbort = reconnectRunIdRef.current ?? activeRun?.runId;
|
|
4286
|
+
const pendingTurn = threadId ? getPendingTurn(threadId) : null;
|
|
4284
4287
|
userStoppedRunRef.current = {
|
|
4285
4288
|
at: Date.now(),
|
|
4286
4289
|
...(runIdToAbort ? { runId: runIdToAbort } : {}),
|
|
@@ -4292,6 +4295,16 @@ const AssistantChatInner = forwardRef<
|
|
|
4292
4295
|
fetch(`${apiUrl}/runs/${encodeURIComponent(runIdToAbort)}/abort`, {
|
|
4293
4296
|
method: "POST",
|
|
4294
4297
|
}).catch(() => {});
|
|
4298
|
+
} else if (pendingTurn && threadId) {
|
|
4299
|
+
clearPendingTurnIfMatches(threadId, pendingTurn.turnId);
|
|
4300
|
+
fetch(
|
|
4301
|
+
`${apiUrl}/runs/turn/${encodeURIComponent(pendingTurn.turnId)}/abort`,
|
|
4302
|
+
{
|
|
4303
|
+
method: "POST",
|
|
4304
|
+
headers: { "Content-Type": "application/json" },
|
|
4305
|
+
body: JSON.stringify({ threadId }),
|
|
4306
|
+
},
|
|
4307
|
+
).catch(() => {});
|
|
4295
4308
|
}
|
|
4296
4309
|
if (isReconnecting) {
|
|
4297
4310
|
reconnectAbortRef.current?.abort();
|
|
@@ -72,6 +72,11 @@ export function openAgentSettings(
|
|
|
72
72
|
const normalizedSection =
|
|
73
73
|
typeof section === "string" ? section : section?.section;
|
|
74
74
|
|
|
75
|
+
const secretHash = normalizedSection?.replace(/^#/, "");
|
|
76
|
+
if (secretHash?.toLowerCase().startsWith("secrets:")) {
|
|
77
|
+
window.location.hash = `#${secretHash}`;
|
|
78
|
+
}
|
|
79
|
+
|
|
75
80
|
openAgentSidebar();
|
|
76
81
|
// Voice mode unmounts the chat surface while its dock is collapsed, so its
|
|
77
82
|
// settings listener does not exist until opening the sidebar remounts it.
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const STORAGE_KEY = "agent-chat-active-run";
|
|
2
|
+
const PENDING_TURN_STORAGE_KEY = "agent-chat-pending-turn";
|
|
2
3
|
export const ACTIVE_RUN_STATE_EVENT = "agent-chat:active-run-state-change";
|
|
3
4
|
|
|
4
5
|
export interface ActiveRunState {
|
|
@@ -8,6 +9,11 @@ export interface ActiveRunState {
|
|
|
8
9
|
activityTool?: string | null;
|
|
9
10
|
}
|
|
10
11
|
|
|
12
|
+
export interface PendingTurnState {
|
|
13
|
+
threadId: string;
|
|
14
|
+
turnId: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
11
17
|
function notifyActiveRunStateChanged(state: ActiveRunState | null): void {
|
|
12
18
|
if (
|
|
13
19
|
typeof window === "undefined" ||
|
|
@@ -88,6 +94,34 @@ export function clearActiveRunIfMatches(threadId: string, runId: string): void {
|
|
|
88
94
|
clearActiveRun();
|
|
89
95
|
}
|
|
90
96
|
|
|
97
|
+
export function setPendingTurn(state: PendingTurnState): void {
|
|
98
|
+
try {
|
|
99
|
+
sessionStorage.setItem(PENDING_TURN_STORAGE_KEY, JSON.stringify(state));
|
|
100
|
+
} catch {}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export function getPendingTurn(threadId: string): PendingTurnState | null {
|
|
104
|
+
try {
|
|
105
|
+
const raw = sessionStorage.getItem(PENDING_TURN_STORAGE_KEY);
|
|
106
|
+
if (!raw) return null;
|
|
107
|
+
const state = JSON.parse(raw) as PendingTurnState;
|
|
108
|
+
return state.threadId === threadId && state.turnId ? state : null;
|
|
109
|
+
} catch {
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export function clearPendingTurnIfMatches(
|
|
115
|
+
threadId: string,
|
|
116
|
+
turnId?: string,
|
|
117
|
+
): void {
|
|
118
|
+
const state = getPendingTurn(threadId);
|
|
119
|
+
if (!state || (turnId && state.turnId !== turnId)) return;
|
|
120
|
+
try {
|
|
121
|
+
sessionStorage.removeItem(PENDING_TURN_STORAGE_KEY);
|
|
122
|
+
} catch {}
|
|
123
|
+
}
|
|
124
|
+
|
|
91
125
|
/** Resume reconnect SSE after the last seen event (0 = replay from the start). */
|
|
92
126
|
export function resolveReconnectAfterSeq(
|
|
93
127
|
threadId: string,
|
|
@@ -11,9 +11,11 @@ import type {
|
|
|
11
11
|
} from "../agent/types.js";
|
|
12
12
|
import type { ReasoningEffort } from "../shared/reasoning-effort.js";
|
|
13
13
|
import {
|
|
14
|
+
clearPendingTurnIfMatches,
|
|
14
15
|
setActiveRun,
|
|
15
16
|
updateActiveRunSeq,
|
|
16
17
|
clearActiveRun,
|
|
18
|
+
setPendingTurn,
|
|
17
19
|
} from "./active-run-state.js";
|
|
18
20
|
import { captureError } from "./analytics.js";
|
|
19
21
|
import { agentNativePath } from "./api-path.js";
|
|
@@ -1634,6 +1636,7 @@ export function createAgentChatAdapter(
|
|
|
1634
1636
|
const content: ContentPart[] = [];
|
|
1635
1637
|
const toolCallCounter = { value: 0 };
|
|
1636
1638
|
const turnId = generateTurnId();
|
|
1639
|
+
if (threadId) setPendingTurn({ threadId, turnId });
|
|
1637
1640
|
let runId: string | null = null;
|
|
1638
1641
|
let lastSeq = -1;
|
|
1639
1642
|
const seenRunSeqs = new Map<string, number>();
|
|
@@ -3279,6 +3282,7 @@ export function createAgentChatAdapter(
|
|
|
3279
3282
|
attemptedRunIds.push(runId);
|
|
3280
3283
|
}
|
|
3281
3284
|
if (runId && threadId) {
|
|
3285
|
+
clearPendingTurnIfMatches(threadId, turnId);
|
|
3282
3286
|
setActiveRun({ threadId, runId, lastSeq: -1 });
|
|
3283
3287
|
}
|
|
3284
3288
|
|
|
@@ -7,10 +7,12 @@ import {
|
|
|
7
7
|
import { useEffect, useMemo, useState } from "react";
|
|
8
8
|
|
|
9
9
|
import { agentNativePath } from "../api-path.js";
|
|
10
|
+
import { openAgentSettings } from "../CommandMenu.js";
|
|
10
11
|
import { useT } from "../i18n.js";
|
|
11
12
|
import {
|
|
12
13
|
buildMcpOAuthStartUrl,
|
|
13
14
|
findMcpIntegrationForText,
|
|
15
|
+
getMcpIntegrationApiFallback,
|
|
14
16
|
getDefaultMcpIntegrations,
|
|
15
17
|
isMcpConnectionFailureText,
|
|
16
18
|
type DefaultMcpIntegration,
|
|
@@ -67,6 +69,12 @@ function canStartOAuth(integration: DefaultMcpIntegration): boolean {
|
|
|
67
69
|
);
|
|
68
70
|
}
|
|
69
71
|
|
|
72
|
+
function hasApiFallback(
|
|
73
|
+
apiFallback: DefaultMcpIntegration["apiFallback"] | null,
|
|
74
|
+
): boolean {
|
|
75
|
+
return Boolean(apiFallback);
|
|
76
|
+
}
|
|
77
|
+
|
|
70
78
|
export function McpConnectionSuggestion({
|
|
71
79
|
text,
|
|
72
80
|
contextText = "",
|
|
@@ -96,6 +104,9 @@ export function McpConnectionSuggestion({
|
|
|
96
104
|
textIntegration.id !== contextIntegration.id
|
|
97
105
|
? null
|
|
98
106
|
: (textIntegration ?? contextIntegration);
|
|
107
|
+
const apiFallback = integration
|
|
108
|
+
? getMcpIntegrationApiFallback(integration)
|
|
109
|
+
: null;
|
|
99
110
|
const servers = useMemo(
|
|
100
111
|
() => [
|
|
101
112
|
...(mcpServersQuery.data?.user ?? []),
|
|
@@ -122,6 +133,11 @@ export function McpConnectionSuggestion({
|
|
|
122
133
|
if (!integration || connecting) return;
|
|
123
134
|
setError(null);
|
|
124
135
|
|
|
136
|
+
if (apiFallback) {
|
|
137
|
+
openAgentSettings(`secrets:${apiFallback.secretKey}`);
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
|
|
125
141
|
if (canStartOAuth(integration)) {
|
|
126
142
|
window.location.assign(
|
|
127
143
|
agentNativePath(
|
|
@@ -163,12 +179,14 @@ export function McpConnectionSuggestion({
|
|
|
163
179
|
setDialogOpen(true);
|
|
164
180
|
};
|
|
165
181
|
|
|
166
|
-
const actionLabel =
|
|
167
|
-
? t("mcpIntegrations.
|
|
168
|
-
: integration
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
182
|
+
const actionLabel = hasApiFallback(apiFallback)
|
|
183
|
+
? t("mcpIntegrations.useApiToken")
|
|
184
|
+
: canStartOAuth(integration)
|
|
185
|
+
? t("mcpIntegrations.connectWithOAuth")
|
|
186
|
+
: integration.availability === "client-restricted" ||
|
|
187
|
+
integration.availability === "provider-setup"
|
|
188
|
+
? t("mcpIntegrations.viewSetup")
|
|
189
|
+
: t("mcpIntegrations.connect");
|
|
172
190
|
|
|
173
191
|
return (
|
|
174
192
|
<>
|
|
@@ -194,7 +212,12 @@ export function McpConnectionSuggestion({
|
|
|
194
212
|
)}
|
|
195
213
|
</div>
|
|
196
214
|
<span className="min-w-0 flex-1 leading-snug text-foreground">
|
|
197
|
-
{t(
|
|
215
|
+
{t(
|
|
216
|
+
hasApiFallback(apiFallback)
|
|
217
|
+
? "mcpIntegrations.connectSuggestionWithApiToken"
|
|
218
|
+
: "mcpIntegrations.connectSuggestion",
|
|
219
|
+
{ name: integration.name },
|
|
220
|
+
)}
|
|
198
221
|
</span>
|
|
199
222
|
<button
|
|
200
223
|
type="button"
|
|
@@ -203,13 +226,20 @@ export function McpConnectionSuggestion({
|
|
|
203
226
|
className="inline-flex shrink-0 items-center gap-1 rounded-md bg-primary px-2.5 py-1.5 text-[11px] font-medium text-primary-foreground hover:bg-primary/90 disabled:pointer-events-none disabled:opacity-60"
|
|
204
227
|
>
|
|
205
228
|
{connecting && <IconLoader2 className="h-3 w-3 animate-spin" />}
|
|
206
|
-
{!connecting &&
|
|
229
|
+
{!connecting &&
|
|
230
|
+
canStartOAuth(integration) &&
|
|
231
|
+
!hasApiFallback(apiFallback) && (
|
|
232
|
+
<IconPlugConnected className="h-3 w-3" />
|
|
233
|
+
)}
|
|
234
|
+
{!connecting && hasApiFallback(apiFallback) && (
|
|
207
235
|
<IconPlugConnected className="h-3 w-3" />
|
|
208
236
|
)}
|
|
209
237
|
{actionLabel}
|
|
210
|
-
{!connecting &&
|
|
211
|
-
|
|
212
|
-
|
|
238
|
+
{!connecting &&
|
|
239
|
+
!canStartOAuth(integration) &&
|
|
240
|
+
!hasApiFallback(apiFallback) && (
|
|
241
|
+
<IconArrowUpRight className="h-3 w-3" />
|
|
242
|
+
)}
|
|
213
243
|
</button>
|
|
214
244
|
<button
|
|
215
245
|
type="button"
|