@agent-native/core 0.131.7 → 0.132.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 +2 -2
- package/corpus/core/CHANGELOG.md +123 -0
- package/corpus/core/docs/content/durable-background-runs.mdx +15 -6
- package/corpus/core/docs/design/durable-agent-runs.md +15 -11
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/a2a/activity.ts +127 -10
- package/corpus/core/src/a2a/index.ts +3 -0
- package/corpus/core/src/agent/durable-background.ts +38 -28
- package/corpus/core/src/agent/harness/background.ts +12 -2
- package/corpus/core/src/agent/production-agent.ts +18 -15
- package/corpus/core/src/agent/run-store.ts +45 -3
- package/corpus/core/src/application-state/handlers.ts +45 -0
- package/corpus/core/src/application-state/index.ts +3 -0
- package/corpus/core/src/application-state/store.ts +38 -34
- package/corpus/core/src/audit/redact.ts +104 -18
- package/corpus/core/src/cli/create.ts +115 -16
- package/corpus/core/src/client/AgentPanel.tsx +2 -7
- package/corpus/core/src/client/AssistantChat.tsx +10 -2
- package/corpus/core/src/client/MultiTabAssistantChat.tsx +3 -0
- package/corpus/core/src/client/RunStuckBanner.tsx +29 -6
- package/corpus/core/src/client/agent-chat.ts +4 -9
- package/corpus/core/src/client/application-state.ts +115 -12
- package/corpus/core/src/client/dynamic-suggestions.ts +4 -12
- package/corpus/core/src/client/frame-protocol.ts +5 -1
- package/corpus/core/src/client/guided-questions.tsx +12 -23
- package/corpus/core/src/db/client.ts +148 -28
- package/corpus/core/src/db/create-get-db.ts +39 -6
- package/corpus/core/src/db/runtime-diagnostics.ts +41 -6
- package/corpus/core/src/deploy/build.ts +26 -33
- package/corpus/core/src/feature-flags/store.ts +10 -5
- package/corpus/core/src/integrations/a2a-continuations-store.ts +11 -0
- package/corpus/core/src/integrations/config-store.ts +13 -0
- package/corpus/core/src/integrations/google-docs-poller.ts +26 -2
- package/corpus/core/src/mcp-client/routes.ts +33 -2
- package/corpus/core/src/onboarding/plugin.ts +31 -25
- package/corpus/core/src/org/accept-pending.ts +2 -0
- package/corpus/core/src/org/auto-join-domain.ts +2 -0
- package/corpus/core/src/org/context.ts +35 -10
- package/corpus/core/src/org/handlers.ts +6 -0
- package/corpus/core/src/org/request-org-cache.ts +71 -0
- package/corpus/core/src/resources/store.ts +10 -9
- package/corpus/core/src/scripts/runner.ts +6 -3
- package/corpus/core/src/secrets/storage.ts +97 -5
- package/corpus/core/src/server/action-change.ts +33 -0
- package/corpus/core/src/server/action-routes.ts +11 -9
- package/corpus/core/src/server/agent-teams.ts +10 -2
- package/corpus/core/src/server/better-auth-instance.ts +39 -12
- package/corpus/core/src/server/core-routes-plugin.ts +19 -2
- package/corpus/core/src/server/credential-provider.ts +57 -14
- package/corpus/core/src/server/http-response-telemetry.ts +1 -0
- package/corpus/core/src/server/poll.ts +95 -57
- package/corpus/core/src/server/voice-providers-status.ts +19 -4
- package/corpus/core/src/workspace-files/tool.ts +18 -11
- package/corpus/templates/analytics/.agents/skills/dashboard-management/SKILL.md +38 -0
- package/corpus/templates/analytics/actions/dashboard-mutation-api.ts +1 -1
- package/corpus/templates/analytics/actions/ensure-native-v2-dashboards.ts +299 -0
- package/corpus/templates/analytics/actions/list-native-v2-dashboard-templates.ts +34 -0
- package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +82 -0
- package/corpus/templates/analytics/app/components/layout/NewDashboardDialog.tsx +2 -2
- package/corpus/templates/analytics/app/hooks/use-dashboard-chat-context.ts +40 -34
- package/corpus/templates/analytics/app/hooks/use-user-pref.ts +3 -3
- package/corpus/templates/analytics/app/i18n-data.ts +40 -0
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/PanelEditorDialog.tsx +18 -10
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +14 -0
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/types.ts +1 -0
- package/corpus/templates/analytics/app/routes/chart.tsx +3 -0
- package/corpus/templates/analytics/changelog/2026-07-30-analytics-dashboards-now-expose-native-funnel-heatmap-callou.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-30-analytics-now-ships-reusable-native-v2-dashboard-manifests-w.md +6 -0
- package/corpus/templates/analytics/server/lib/dashboard-report-render.ts +81 -1
- package/corpus/templates/analytics/server/lib/native-v2-dashboards.ts +457 -0
- package/corpus/templates/analytics/server/lib/report-chart-svg.ts +73 -2
- package/corpus/templates/analytics/server/plugins/agent-chat.ts +1 -1
- package/corpus/templates/analytics/shared/dashboard-funnel.ts +83 -0
- package/corpus/templates/clips/actions/generate-workflow.ts +6 -4
- package/corpus/templates/clips/actions/reconcile-workflow-generation.ts +257 -0
- package/corpus/templates/clips/app/hooks/use-auto-title.ts +166 -4
- package/corpus/templates/clips/app/routes/r.$recordingId.tsx +1 -1
- package/corpus/templates/clips/changelog/2026-07-27-stopped-agent-runs-no-longer-leave-generated-workflow-cards-.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-30-workflow-generation-now-stops-retrying-after-repeated-failur.md +6 -0
- package/corpus/templates/clips/shared/workflow.ts +5 -0
- package/corpus/templates/content/changelog/2026-07-30-long-running-delegated-requests-now-continue-reliably.md +6 -0
- package/corpus/templates/content/netlify.toml +3 -0
- package/corpus/templates/content/server/plugins/agent-chat.ts +1 -0
- package/corpus/templates/slides/.agents/skills/create-deck/SKILL.md +2 -1
- package/corpus/templates/slides/actions/patch-deck.ts +25 -1
- package/corpus/templates/slides/app/components/deck/DeckCard.tsx +17 -4
- package/corpus/templates/slides/app/components/deck/SlideRenderer.tsx +9 -1
- package/corpus/templates/slides/app/components/layout/Layout.tsx +1 -1
- package/corpus/templates/slides/app/context/DeckContext.tsx +11 -3
- package/corpus/templates/slides/app/lib/sanitize-slide-html.ts +39 -11
- package/corpus/templates/slides/app/pages/Index.tsx +2 -2
- package/corpus/templates/slides/changelog/2026-07-30-slide-previews-keep-their-aspect-ratio-isolate-embedded-styl.md +6 -0
- package/corpus/templates/slides/changelog/2026-07-30-slides-no-longer-lose-decks-while-organization-access-is-loa.md +6 -0
- package/corpus/toolkit/CHANGELOG.md +8 -0
- package/corpus/toolkit/package.json +1 -1
- package/corpus/toolkit/src/composer/runtime-adapters.tsx +16 -11
- package/dist/a2a/activity.d.ts +22 -4
- package/dist/a2a/activity.d.ts.map +1 -1
- package/dist/a2a/activity.js +97 -11
- package/dist/a2a/activity.js.map +1 -1
- package/dist/a2a/index.d.ts +1 -1
- package/dist/a2a/index.d.ts.map +1 -1
- package/dist/a2a/index.js +1 -1
- package/dist/a2a/index.js.map +1 -1
- package/dist/agent/durable-background.d.ts +13 -8
- package/dist/agent/durable-background.d.ts.map +1 -1
- package/dist/agent/durable-background.js +36 -28
- package/dist/agent/durable-background.js.map +1 -1
- package/dist/agent/harness/background.d.ts.map +1 -1
- package/dist/agent/harness/background.js +12 -2
- package/dist/agent/harness/background.js.map +1 -1
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +18 -15
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/agent/run-store.d.ts +2 -0
- package/dist/agent/run-store.d.ts.map +1 -1
- package/dist/agent/run-store.js +44 -3
- package/dist/agent/run-store.js.map +1 -1
- package/dist/application-state/handlers.d.ts +15 -0
- package/dist/application-state/handlers.d.ts.map +1 -1
- package/dist/application-state/handlers.js +42 -2
- package/dist/application-state/handlers.js.map +1 -1
- package/dist/application-state/index.d.ts +2 -2
- package/dist/application-state/index.d.ts.map +1 -1
- package/dist/application-state/index.js +2 -2
- package/dist/application-state/index.js.map +1 -1
- package/dist/application-state/store.d.ts +11 -0
- package/dist/application-state/store.d.ts.map +1 -1
- package/dist/application-state/store.js +37 -40
- package/dist/application-state/store.js.map +1 -1
- package/dist/audit/redact.d.ts +25 -2
- package/dist/audit/redact.d.ts.map +1 -1
- package/dist/audit/redact.js +85 -21
- package/dist/audit/redact.js.map +1 -1
- package/dist/cli/create.d.ts +8 -1
- package/dist/cli/create.d.ts.map +1 -1
- package/dist/cli/create.js +98 -16
- package/dist/cli/create.js.map +1 -1
- package/dist/client/AgentPanel.d.ts.map +1 -1
- package/dist/client/AgentPanel.js +2 -7
- package/dist/client/AgentPanel.js.map +1 -1
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +10 -2
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
- package/dist/client/MultiTabAssistantChat.js +1 -1
- package/dist/client/MultiTabAssistantChat.js.map +1 -1
- package/dist/client/RunStuckBanner.d.ts +11 -1
- package/dist/client/RunStuckBanner.d.ts.map +1 -1
- package/dist/client/RunStuckBanner.js +20 -7
- package/dist/client/RunStuckBanner.js.map +1 -1
- package/dist/client/agent-chat.d.ts.map +1 -1
- package/dist/client/agent-chat.js +4 -6
- package/dist/client/agent-chat.js.map +1 -1
- package/dist/client/application-state.d.ts +11 -0
- package/dist/client/application-state.d.ts.map +1 -1
- package/dist/client/application-state.js +87 -9
- package/dist/client/application-state.js.map +1 -1
- package/dist/client/dynamic-suggestions.d.ts.map +1 -1
- package/dist/client/dynamic-suggestions.js +4 -13
- package/dist/client/dynamic-suggestions.js.map +1 -1
- package/dist/client/frame-protocol.d.ts +1 -0
- package/dist/client/frame-protocol.d.ts.map +1 -1
- package/dist/client/frame-protocol.js.map +1 -1
- package/dist/client/guided-questions.d.ts.map +1 -1
- package/dist/client/guided-questions.js +6 -22
- package/dist/client/guided-questions.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/db/client.d.ts +57 -10
- package/dist/db/client.d.ts.map +1 -1
- package/dist/db/client.js +122 -31
- package/dist/db/client.js.map +1 -1
- package/dist/db/create-get-db.d.ts.map +1 -1
- package/dist/db/create-get-db.js +31 -7
- package/dist/db/create-get-db.js.map +1 -1
- package/dist/db/runtime-diagnostics.d.ts +1 -0
- package/dist/db/runtime-diagnostics.d.ts.map +1 -1
- package/dist/db/runtime-diagnostics.js +31 -6
- package/dist/db/runtime-diagnostics.js.map +1 -1
- package/dist/deploy/build.d.ts +5 -20
- package/dist/deploy/build.d.ts.map +1 -1
- package/dist/deploy/build.js +18 -30
- package/dist/deploy/build.js.map +1 -1
- package/dist/feature-flags/store.d.ts.map +1 -1
- package/dist/feature-flags/store.js +10 -5
- package/dist/feature-flags/store.js.map +1 -1
- package/dist/integrations/a2a-continuations-store.d.ts.map +1 -1
- package/dist/integrations/a2a-continuations-store.js +12 -0
- package/dist/integrations/a2a-continuations-store.js.map +1 -1
- package/dist/integrations/config-store.d.ts +1 -0
- package/dist/integrations/config-store.d.ts.map +1 -1
- package/dist/integrations/config-store.js +11 -0
- package/dist/integrations/config-store.js.map +1 -1
- package/dist/integrations/google-docs-poller.d.ts.map +1 -1
- package/dist/integrations/google-docs-poller.js +19 -2
- package/dist/integrations/google-docs-poller.js.map +1 -1
- package/dist/mcp/screen-memory-stdio.d.ts +7 -7
- package/dist/mcp/screen-memory-stdio.d.ts.map +1 -1
- package/dist/mcp-client/routes.d.ts.map +1 -1
- package/dist/mcp-client/routes.js +30 -2
- package/dist/mcp-client/routes.js.map +1 -1
- package/dist/notifications/routes.d.ts +6 -6
- package/dist/onboarding/plugin.d.ts.map +1 -1
- package/dist/onboarding/plugin.js +12 -8
- package/dist/onboarding/plugin.js.map +1 -1
- package/dist/org/accept-pending.d.ts.map +1 -1
- package/dist/org/accept-pending.js +2 -0
- package/dist/org/accept-pending.js.map +1 -1
- package/dist/org/auto-join-domain.d.ts.map +1 -1
- package/dist/org/auto-join-domain.js +2 -0
- package/dist/org/auto-join-domain.js.map +1 -1
- package/dist/org/context.d.ts.map +1 -1
- package/dist/org/context.js +29 -9
- package/dist/org/context.js.map +1 -1
- package/dist/org/handlers.d.ts.map +1 -1
- package/dist/org/handlers.js +5 -0
- package/dist/org/handlers.js.map +1 -1
- package/dist/org/request-org-cache.d.ts +16 -0
- package/dist/org/request-org-cache.d.ts.map +1 -0
- package/dist/org/request-org-cache.js +62 -0
- package/dist/org/request-org-cache.js.map +1 -0
- package/dist/progress/routes.d.ts +1 -1
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/resources/store.d.ts.map +1 -1
- package/dist/resources/store.js +11 -9
- package/dist/resources/store.js.map +1 -1
- package/dist/scripts/runner.d.ts.map +1 -1
- package/dist/scripts/runner.js +3 -3
- package/dist/scripts/runner.js.map +1 -1
- package/dist/secrets/storage.d.ts.map +1 -1
- package/dist/secrets/storage.js +82 -5
- package/dist/secrets/storage.js.map +1 -1
- package/dist/server/action-change.d.ts +20 -0
- package/dist/server/action-change.d.ts.map +1 -1
- package/dist/server/action-change.js +29 -0
- package/dist/server/action-change.js.map +1 -1
- package/dist/server/action-routes.d.ts.map +1 -1
- package/dist/server/action-routes.js +7 -8
- package/dist/server/action-routes.js.map +1 -1
- package/dist/server/agent-teams.d.ts.map +1 -1
- package/dist/server/agent-teams.js +10 -2
- package/dist/server/agent-teams.js.map +1 -1
- package/dist/server/better-auth-instance.d.ts.map +1 -1
- package/dist/server/better-auth-instance.js +31 -14
- package/dist/server/better-auth-instance.js.map +1 -1
- package/dist/server/core-routes-plugin.d.ts +1 -0
- package/dist/server/core-routes-plugin.d.ts.map +1 -1
- package/dist/server/core-routes-plugin.js +18 -4
- package/dist/server/core-routes-plugin.js.map +1 -1
- package/dist/server/credential-provider.d.ts +16 -0
- package/dist/server/credential-provider.d.ts.map +1 -1
- package/dist/server/credential-provider.js +49 -13
- package/dist/server/credential-provider.js.map +1 -1
- package/dist/server/http-response-telemetry.d.ts.map +1 -1
- package/dist/server/http-response-telemetry.js +1 -0
- package/dist/server/http-response-telemetry.js.map +1 -1
- package/dist/server/poll.d.ts +6 -0
- package/dist/server/poll.d.ts.map +1 -1
- package/dist/server/poll.js +84 -47
- package/dist/server/poll.js.map +1 -1
- package/dist/server/realtime-token.d.ts +1 -1
- package/dist/server/voice-providers-status.d.ts.map +1 -1
- package/dist/server/voice-providers-status.js +12 -3
- package/dist/server/voice-providers-status.js.map +1 -1
- package/dist/workspace-files/tool.d.ts.map +1 -1
- package/dist/workspace-files/tool.js +18 -11
- package/dist/workspace-files/tool.js.map +1 -1
- package/docs/content/durable-background-runs.mdx +15 -6
- package/docs/design/durable-agent-runs.md +15 -11
- package/package.json +3 -3
- package/src/a2a/activity.ts +127 -10
- package/src/a2a/index.ts +3 -0
- package/src/agent/durable-background.ts +38 -28
- package/src/agent/harness/background.ts +12 -2
- package/src/agent/production-agent.ts +18 -15
- package/src/agent/run-store.ts +45 -3
- package/src/application-state/handlers.ts +45 -0
- package/src/application-state/index.ts +3 -0
- package/src/application-state/store.ts +38 -34
- package/src/audit/redact.ts +104 -18
- package/src/cli/create.ts +115 -16
- package/src/client/AgentPanel.tsx +2 -7
- package/src/client/AssistantChat.tsx +10 -2
- package/src/client/MultiTabAssistantChat.tsx +3 -0
- package/src/client/RunStuckBanner.tsx +29 -6
- package/src/client/agent-chat.ts +4 -9
- package/src/client/application-state.ts +115 -12
- package/src/client/dynamic-suggestions.ts +4 -12
- package/src/client/frame-protocol.ts +5 -1
- package/src/client/guided-questions.tsx +12 -23
- package/src/db/client.ts +148 -28
- package/src/db/create-get-db.ts +39 -6
- package/src/db/runtime-diagnostics.ts +41 -6
- package/src/deploy/build.ts +26 -33
- package/src/feature-flags/store.ts +10 -5
- package/src/integrations/a2a-continuations-store.ts +11 -0
- package/src/integrations/config-store.ts +13 -0
- package/src/integrations/google-docs-poller.ts +26 -2
- package/src/mcp-client/routes.ts +33 -2
- package/src/onboarding/plugin.ts +31 -25
- package/src/org/accept-pending.ts +2 -0
- package/src/org/auto-join-domain.ts +2 -0
- package/src/org/context.ts +35 -10
- package/src/org/handlers.ts +6 -0
- package/src/org/request-org-cache.ts +71 -0
- package/src/resources/store.ts +10 -9
- package/src/scripts/runner.ts +6 -3
- package/src/secrets/storage.ts +97 -5
- package/src/server/action-change.ts +33 -0
- package/src/server/action-routes.ts +11 -9
- package/src/server/agent-teams.ts +10 -2
- package/src/server/better-auth-instance.ts +39 -12
- package/src/server/core-routes-plugin.ts +19 -2
- package/src/server/credential-provider.ts +57 -14
- package/src/server/http-response-telemetry.ts +1 -0
- package/src/server/poll.ts +95 -57
- package/src/server/voice-providers-status.ts +19 -4
- package/src/workspace-files/tool.ts +18 -11
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"voice-providers-status.js","sourceRoot":"","sources":["../../src/server/voice-providers-status.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,EACL,kBAAkB,EAClB,SAAS,EACT,iBAAiB,GAElB,MAAM,IAAI,CAAC;AAEZ,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EACL,mCAAmC,EACnC,aAAa,GACd,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,gCAAgC,EAAE,MAAM,8BAA8B,CAAC;AAChF,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAyB7D,MAAM,UAAU,iCAAiC;IAC/C,OAAO,kBAAkB,CAAC,KAAK,EAAE,KAAc,EAAE,EAAE;QACjD,IAAI,SAAS,CAAC,KAAK,CAAC,KAAK,KAAK,EAAE,CAAC;YAC/B,iBAAiB,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;YAC9B,OAAO,EAAE,KAAK,EAAE,oBAAoB,EAAE,CAAC;QACzC,CAAC;QAED,MAAM,OAAO,GAAG,MAAM,UAAU,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;QAC1D,MAAM,MAAM,GAAG,OAAO,EAAE,KAAK;YAC3B,CAAC,CAAC,MAAM,aAAa,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC;YAC9C,CAAC,CAAC,IAAI,CAAC;QACT,MAAM,cAAc,GAAG;YACrB,SAAS,EAAE,OAAO,EAAE,KAAK;YACzB,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI,SAAS;SAClC,CAAC;QACF,MAAM,kBAAkB,GAAG,KAAK,EAAK,EAAoB,EAAc,EAAE,CACvE,cAAc,CAAC,SAAS;YACtB,CAAC,CAAC,qBAAqB,CAAC,cAAc,EAAE,EAAE,CAAC;YAC3C,CAAC,CAAC,EAAE,EAAE,CAAC;QAEX,KAAK,UAAU,MAAM,CAAC,GAAW;YAC/B,IAAI,CAAC;gBACH,IAAI,GAAG,KAAK,gCAAgC,EAAE,CAAC;oBAC7C,MAAM,QAAQ,GAAG,MAAM,gCAAgC,CAAC;
|
|
1
|
+
{"version":3,"file":"voice-providers-status.js","sourceRoot":"","sources":["../../src/server/voice-providers-status.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * GET /_agent-native/voice-providers/status\n *\n * Reports which voice transcription providers are configured for the\n * current user. The desktop Settings UI uses this to show \"Connect\" vs\n * \"Connected\" status pills next to each provider option.\n *\n * Resolution mirrors `transcribe-voice.ts`: we read request-scoped encrypted\n * secrets (user, org, workspace), with env fallback only outside authenticated\n * request contexts. Each lookup is wrapped in try/catch — one provider's\n * failure must never break the whole response.\n *\n * Returns booleans only — never the actual key material.\n */\nimport {\n defineEventHandler,\n getMethod,\n setResponseStatus,\n type H3Event,\n} from \"h3\";\n\nimport { getOrgContext } from \"../org/context.js\";\nimport { getSession } from \"./auth.js\";\nimport {\n prefetchSecrets,\n resolveHasCompleteBuilderConnection,\n resolveSecret,\n} from \"./credential-provider.js\";\nimport { resolveGoogleRealtimeCredentials } from \"./google-realtime-session.js\";\nimport { runWithRequestContext } from \"./request-context.js\";\n\nexport interface VoiceProvidersStatus {\n builder: boolean;\n gemini: boolean;\n openai: boolean;\n groq: boolean;\n /**\n * Google Speech-to-Text realtime streaming is BYOK-only for v1. This reports\n * whether a service-account credential is configured; the actual stream runs\n * through the dedicated WebSocket -> StreamingRecognize path, not the batch\n * transcribe route.\n */\n googleRealtime: boolean;\n /** Always true — the Web Speech API is available in WebKit-based clients. */\n browser: true;\n /**\n * Apple's SFSpeechRecognizer + AVAudioEngine, exposed by the Tauri\n * desktop client. Always reported as `true` from the server — the\n * desktop client gates this on macOS at the Tauri-command boundary, so\n * non-macOS hosts return a clear error instead of attempting to use it.\n */\n native: true;\n}\n\nexport function createVoiceProvidersStatusHandler() {\n return defineEventHandler(async (event: H3Event) => {\n if (getMethod(event) !== \"GET\") {\n setResponseStatus(event, 405);\n return { error: \"Method not allowed\" };\n }\n\n const session = await getSession(event).catch(() => null);\n const orgCtx = session?.email\n ? await getOrgContext(event).catch(() => null)\n : null;\n const requestContext = {\n userEmail: session?.email,\n orgId: orgCtx?.orgId ?? undefined,\n };\n const withRequestContext = async <T>(fn: () => Promise<T>): Promise<T> =>\n requestContext.userEmail\n ? runWithRequestContext(requestContext, fn)\n : fn();\n\n async function hasKey(key: string): Promise<boolean> {\n try {\n if (key === \"GOOGLE_APPLICATION_CREDENTIALS\") {\n // Same identity, passed explicitly — the context is here only so this\n // scope sweep shares the prefetched per-request memo below.\n const resolved = await withRequestContext(() =>\n resolveGoogleRealtimeCredentials({\n userEmail: session?.email,\n orgId: orgCtx?.orgId ?? undefined,\n }),\n );\n return typeof resolved === \"string\" && resolved.length > 0;\n }\n const resolved = await withRequestContext(() => resolveSecret(key));\n return typeof resolved === \"string\" && resolved.length > 0;\n } catch {\n return false;\n }\n }\n\n // One read per scope for every key below, instead of one per key per scope.\n await withRequestContext(() =>\n prefetchSecrets([\n \"GEMINI_API_KEY\",\n \"OPENAI_API_KEY\",\n \"GROQ_API_KEY\",\n \"GOOGLE_APPLICATION_CREDENTIALS\",\n ]),\n );\n\n let builder = false;\n try {\n builder =\n (await withRequestContext(() =>\n resolveHasCompleteBuilderConnection(),\n )) === true;\n } catch {\n builder = false;\n }\n\n const [gemini, openai, groq, googleRealtime] = await Promise.all([\n hasKey(\"GEMINI_API_KEY\"),\n hasKey(\"OPENAI_API_KEY\"),\n hasKey(\"GROQ_API_KEY\"),\n hasKey(\"GOOGLE_APPLICATION_CREDENTIALS\"),\n ]);\n\n const status: VoiceProvidersStatus = {\n builder,\n gemini,\n openai,\n groq,\n googleRealtime,\n browser: true,\n native: true,\n };\n return status;\n });\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool.d.ts","sourceRoot":"","sources":["../../src/workspace-files/tool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AA2BhE,wBAAgB,wBAAwB,IAAI,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,
|
|
1
|
+
{"version":3,"file":"tool.d.ts","sourceRoot":"","sources":["../../src/workspace-files/tool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AA2BhE,wBAAgB,wBAAwB,IAAI,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CA6OtE"}
|
|
@@ -69,12 +69,15 @@ export function createWorkspaceFilesTool() {
|
|
|
69
69
|
description: 'MIME type for new files. Default: "text/plain". Use "application/json" for JSON, "text/markdown" for Markdown.',
|
|
70
70
|
},
|
|
71
71
|
offset: {
|
|
72
|
-
type: "
|
|
73
|
-
|
|
72
|
+
type: "integer",
|
|
73
|
+
minimum: 0,
|
|
74
|
+
description: "Non-negative character offset to start reading from (for paging large files). Default: 0.",
|
|
74
75
|
},
|
|
75
76
|
maxChars: {
|
|
76
|
-
type: "
|
|
77
|
-
|
|
77
|
+
type: "integer",
|
|
78
|
+
minimum: 1,
|
|
79
|
+
maximum: MAX_READ_CHARS,
|
|
80
|
+
description: `Positive maximum characters to return when reading. Default: ${DEFAULT_READ_CHARS}. Max: ${MAX_READ_CHARS}.`,
|
|
78
81
|
},
|
|
79
82
|
pattern: {
|
|
80
83
|
type: "string",
|
|
@@ -135,14 +138,17 @@ export function createWorkspaceFilesTool() {
|
|
|
135
138
|
if (!path)
|
|
136
139
|
return "Error: path is required for read.";
|
|
137
140
|
const rawOffset = Number(args.offset);
|
|
138
|
-
const offset = Number.isFinite(rawOffset) && rawOffset > 0
|
|
141
|
+
const offset = Number.isFinite(rawOffset) && rawOffset > 0
|
|
142
|
+
? Math.floor(rawOffset)
|
|
143
|
+
: 0;
|
|
139
144
|
const rawMax = Number(args.maxChars);
|
|
140
145
|
const maxChars = Number.isFinite(rawMax) && rawMax > 0
|
|
141
|
-
? Math.min(rawMax, MAX_READ_CHARS)
|
|
146
|
+
? Math.min(Math.max(1, Math.floor(rawMax)), MAX_READ_CHARS)
|
|
142
147
|
: DEFAULT_READ_CHARS;
|
|
148
|
+
// The sentinel character distinguishes an exact page from a truncated one.
|
|
143
149
|
const file = await readWorkspaceFile(scope, path, {
|
|
144
150
|
offset,
|
|
145
|
-
maxChars,
|
|
151
|
+
maxChars: maxChars + 1,
|
|
146
152
|
});
|
|
147
153
|
if (!file) {
|
|
148
154
|
return JSON.stringify({
|
|
@@ -150,19 +156,20 @@ export function createWorkspaceFilesTool() {
|
|
|
150
156
|
error: `File not found: "${path}"`,
|
|
151
157
|
});
|
|
152
158
|
}
|
|
153
|
-
const truncated = file.content.length
|
|
159
|
+
const truncated = file.content.length > maxChars;
|
|
160
|
+
const content = file.content.slice(0, maxChars);
|
|
154
161
|
return JSON.stringify({
|
|
155
162
|
ok: true,
|
|
156
163
|
path: file.path,
|
|
157
164
|
contentType: file.contentType,
|
|
158
165
|
sizeBytes: file.sizeBytes,
|
|
159
166
|
updatedAt: file.updatedAt,
|
|
160
|
-
content
|
|
167
|
+
content,
|
|
161
168
|
...(truncated
|
|
162
169
|
? {
|
|
163
170
|
truncated: true,
|
|
164
|
-
nextOffset: offset +
|
|
165
|
-
hint: `File has more content. Call again with offset: ${offset +
|
|
171
|
+
nextOffset: offset + content.length,
|
|
172
|
+
hint: `File has more content. Call again with offset: ${offset + content.length}`,
|
|
166
173
|
}
|
|
167
174
|
: {}),
|
|
168
175
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool.js","sourceRoot":"","sources":["../../src/workspace-files/tool.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `workspace-files` bridge tool.\n *\n * A single tool with an `action` discriminator covering write, append, read,\n * list, delete, and grep. It is kept for `run-code` workspaceRead/workspaceWrite\n * compatibility and delegates storage to the Resources table.\n *\n * Scope is automatically resolved from the active request context:\n * - org scope when a request orgId is present (shared across users in the org)\n * - user scope otherwise (personal to the requesting user's email)\n */\n\nimport type { ActionEntry } from \"../agent/production-agent.js\";\nimport {\n getRequestOrgId,\n getRequestUserEmail,\n} from \"../server/request-context.js\";\nimport {\n writeWorkspaceFile,\n appendWorkspaceFile,\n readWorkspaceFile,\n listWorkspaceFiles,\n deleteWorkspaceFile,\n grepWorkspaceFiles,\n type WorkspaceFilesScope,\n} from \"./store.js\";\n\nconst MAX_READ_CHARS = 100_000;\nconst DEFAULT_READ_CHARS = 40_000;\n\n/** Resolve scope from the current request context (org-preferred). */\nfunction resolveScope(): WorkspaceFilesScope | null {\n const orgId = getRequestOrgId();\n if (orgId) return { scope: \"org\", scopeId: orgId };\n const email = getRequestUserEmail();\n if (email) return { scope: \"user\", scopeId: email };\n return null;\n}\n\nexport function createWorkspaceFilesTool(): Record<string, ActionEntry> {\n return {\n \"workspace-files\": {\n agentTool: false,\n readOnly: false,\n tool: {\n description: [\n \"Bridge-only workspace file storage backed by Resources. Files are scoped to the current org/user and appear in the Resources workspace.\",\n \"Use scratch/... for temporary intermediate results; scratch files are hidden from the Resources view by default and expire. Use durable folder names for files the user explicitly wants to keep/manage.\",\n \"Use this to stage large intermediate results (fetched pages, per-item analysis memos, API payloads) so they don't consume context window, then read them back selectively for synthesis.\",\n \"\",\n \"Typical fusion-style workflow:\",\n \" 1. Fan out: for each item, fetch data and `write` a per-item memo file.\",\n \" 2. Synthesize: `list` files, then `read` each memo (with offset/maxChars to page large ones).\",\n \" 3. Optionally `grep` across all memos to find patterns.\",\n \" 4. `delete` temp files when no longer needed.\",\n \"\",\n \"Actions:\",\n \" write — create or overwrite a file. Max 2 MB per file.\",\n \" append — append text to a file (or create if absent).\",\n \" read — read content, optionally with offset/maxChars for paging large files.\",\n \" list — list files (with optional path prefix filter) showing name, size, updated.\",\n \" delete — delete a file by path.\",\n \" grep — search content across files for a substring or regex.\",\n ].join(\"\\n\"),\n parameters: {\n type: \"object\",\n properties: {\n action: {\n type: \"string\",\n enum: [\"write\", \"append\", \"read\", \"list\", \"delete\", \"grep\"],\n description: \"Operation to perform.\",\n },\n path: {\n type: \"string\",\n description:\n 'File path relative to the scope root, e.g. \"scratch/analysis/q2-memos/acme.md\". Required for write/append/read/delete. Optional for list/grep (acts as prefix filter).',\n },\n content: {\n type: \"string\",\n description:\n \"Text content to write or append. Required for write/append.\",\n },\n contentType: {\n type: \"string\",\n description:\n 'MIME type for new files. Default: \"text/plain\". Use \"application/json\" for JSON, \"text/markdown\" for Markdown.',\n },\n offset: {\n type: \"number\",\n description:\n \"Character offset to start reading from (for paging large files). Default: 0.\",\n },\n maxChars: {\n type: \"number\",\n description: `Maximum characters to return when reading. Default: ${DEFAULT_READ_CHARS}. Max: ${MAX_READ_CHARS}.`,\n },\n pattern: {\n type: \"string\",\n description:\n \"Search pattern for grep. Required for grep action. A plain substring by default; set useRegex to true for a regex.\",\n },\n useRegex: {\n type: \"boolean\",\n description:\n \"When true, treat `pattern` as a JavaScript regex (case-insensitive). Default: false.\",\n },\n },\n required: [\"action\"],\n },\n },\n\n run: async (args: Record<string, unknown>): Promise<string> => {\n const scope = resolveScope();\n if (!scope) {\n return \"Error: workspace-files requires an authenticated request context.\";\n }\n\n const action = String(args.action ?? \"\").trim();\n\n try {\n switch (action) {\n case \"write\": {\n const path = String(args.path ?? \"\").trim();\n if (!path) return \"Error: path is required for write.\";\n const content = String(args.content ?? \"\");\n const contentType = String(args.contentType ?? \"text/plain\");\n const meta = await writeWorkspaceFile(\n scope,\n path,\n content,\n contentType,\n );\n return JSON.stringify({\n ok: true,\n action: \"write\",\n resourceId: meta.id,\n path: meta.path,\n contentType: meta.contentType,\n sizeBytes: meta.sizeBytes,\n updatedAt: meta.updatedAt,\n });\n }\n\n case \"append\": {\n const path = String(args.path ?? \"\").trim();\n if (!path) return \"Error: path is required for append.\";\n const content = String(args.content ?? \"\");\n const contentType = String(args.contentType ?? \"text/plain\");\n const meta = await appendWorkspaceFile(\n scope,\n path,\n content,\n contentType,\n );\n return JSON.stringify({\n ok: true,\n action: \"append\",\n resourceId: meta.id,\n path: meta.path,\n contentType: meta.contentType,\n sizeBytes: meta.sizeBytes,\n updatedAt: meta.updatedAt,\n });\n }\n\n case \"read\": {\n const path = String(args.path ?? \"\").trim();\n if (!path) return \"Error: path is required for read.\";\n const rawOffset = Number(args.offset);\n const offset =\n Number.isFinite(rawOffset) && rawOffset > 0 ? rawOffset : 0;\n const rawMax = Number(args.maxChars);\n const maxChars =\n Number.isFinite(rawMax) && rawMax > 0\n ? Math.min(rawMax, MAX_READ_CHARS)\n : DEFAULT_READ_CHARS;\n\n const file = await readWorkspaceFile(scope, path, {\n offset,\n maxChars,\n });\n if (!file) {\n return JSON.stringify({\n ok: false,\n error: `File not found: \"${path}\"`,\n });\n }\n\n const truncated = file.content.length >= maxChars;\n return JSON.stringify({\n ok: true,\n path: file.path,\n contentType: file.contentType,\n sizeBytes: file.sizeBytes,\n updatedAt: file.updatedAt,\n content: file.content,\n ...(truncated\n ? {\n truncated: true,\n nextOffset: offset + file.content.length,\n hint: `File has more content. Call again with offset: ${offset + file.content.length}`,\n }\n : {}),\n });\n }\n\n case \"list\": {\n const prefix = args.path ? String(args.path).trim() : undefined;\n const files = await listWorkspaceFiles(\n scope,\n prefix || undefined,\n );\n return JSON.stringify({\n ok: true,\n count: files.length,\n files: files.map((f) => ({\n path: f.path,\n sizeBytes: f.sizeBytes,\n contentType: f.contentType,\n updatedAt: f.updatedAt,\n })),\n });\n }\n\n case \"delete\": {\n const path = String(args.path ?? \"\").trim();\n if (!path) return \"Error: path is required for delete.\";\n const deleted = await deleteWorkspaceFile(scope, path);\n return JSON.stringify({\n ok: true,\n deleted,\n path,\n });\n }\n\n case \"grep\": {\n const pattern = String(args.pattern ?? \"\").trim();\n if (!pattern) return \"Error: pattern is required for grep.\";\n const prefix = args.path ? String(args.path).trim() : undefined;\n const useRegex =\n args.useRegex === true || String(args.useRegex) === \"true\";\n const matches = await grepWorkspaceFiles(scope, pattern, {\n pathPrefix: prefix || undefined,\n useRegex,\n maxMatchesPerFile: 20,\n maxFiles: 50,\n });\n return JSON.stringify({\n ok: true,\n pattern,\n matchCount: matches.length,\n matches: matches.map((m) => ({\n path: m.path,\n line: m.lineNumber,\n text: m.line,\n })),\n });\n }\n\n default:\n return `Error: unknown action \"${action}\". Valid actions: write, append, read, list, delete, grep.`;\n }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n return JSON.stringify({ ok: false, error: msg });\n }\n },\n },\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"tool.js","sourceRoot":"","sources":["../../src/workspace-files/tool.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `workspace-files` bridge tool.\n *\n * A single tool with an `action` discriminator covering write, append, read,\n * list, delete, and grep. It is kept for `run-code` workspaceRead/workspaceWrite\n * compatibility and delegates storage to the Resources table.\n *\n * Scope is automatically resolved from the active request context:\n * - org scope when a request orgId is present (shared across users in the org)\n * - user scope otherwise (personal to the requesting user's email)\n */\n\nimport type { ActionEntry } from \"../agent/production-agent.js\";\nimport {\n getRequestOrgId,\n getRequestUserEmail,\n} from \"../server/request-context.js\";\nimport {\n writeWorkspaceFile,\n appendWorkspaceFile,\n readWorkspaceFile,\n listWorkspaceFiles,\n deleteWorkspaceFile,\n grepWorkspaceFiles,\n type WorkspaceFilesScope,\n} from \"./store.js\";\n\nconst MAX_READ_CHARS = 100_000;\nconst DEFAULT_READ_CHARS = 40_000;\n\n/** Resolve scope from the current request context (org-preferred). */\nfunction resolveScope(): WorkspaceFilesScope | null {\n const orgId = getRequestOrgId();\n if (orgId) return { scope: \"org\", scopeId: orgId };\n const email = getRequestUserEmail();\n if (email) return { scope: \"user\", scopeId: email };\n return null;\n}\n\nexport function createWorkspaceFilesTool(): Record<string, ActionEntry> {\n return {\n \"workspace-files\": {\n agentTool: false,\n readOnly: false,\n tool: {\n description: [\n \"Bridge-only workspace file storage backed by Resources. Files are scoped to the current org/user and appear in the Resources workspace.\",\n \"Use scratch/... for temporary intermediate results; scratch files are hidden from the Resources view by default and expire. Use durable folder names for files the user explicitly wants to keep/manage.\",\n \"Use this to stage large intermediate results (fetched pages, per-item analysis memos, API payloads) so they don't consume context window, then read them back selectively for synthesis.\",\n \"\",\n \"Typical fusion-style workflow:\",\n \" 1. Fan out: for each item, fetch data and `write` a per-item memo file.\",\n \" 2. Synthesize: `list` files, then `read` each memo (with offset/maxChars to page large ones).\",\n \" 3. Optionally `grep` across all memos to find patterns.\",\n \" 4. `delete` temp files when no longer needed.\",\n \"\",\n \"Actions:\",\n \" write — create or overwrite a file. Max 2 MB per file.\",\n \" append — append text to a file (or create if absent).\",\n \" read — read content, optionally with offset/maxChars for paging large files.\",\n \" list — list files (with optional path prefix filter) showing name, size, updated.\",\n \" delete — delete a file by path.\",\n \" grep — search content across files for a substring or regex.\",\n ].join(\"\\n\"),\n parameters: {\n type: \"object\",\n properties: {\n action: {\n type: \"string\",\n enum: [\"write\", \"append\", \"read\", \"list\", \"delete\", \"grep\"],\n description: \"Operation to perform.\",\n },\n path: {\n type: \"string\",\n description:\n 'File path relative to the scope root, e.g. \"scratch/analysis/q2-memos/acme.md\". Required for write/append/read/delete. Optional for list/grep (acts as prefix filter).',\n },\n content: {\n type: \"string\",\n description:\n \"Text content to write or append. Required for write/append.\",\n },\n contentType: {\n type: \"string\",\n description:\n 'MIME type for new files. Default: \"text/plain\". Use \"application/json\" for JSON, \"text/markdown\" for Markdown.',\n },\n offset: {\n type: \"integer\",\n minimum: 0,\n description:\n \"Non-negative character offset to start reading from (for paging large files). Default: 0.\",\n },\n maxChars: {\n type: \"integer\",\n minimum: 1,\n maximum: MAX_READ_CHARS,\n description: `Positive maximum characters to return when reading. Default: ${DEFAULT_READ_CHARS}. Max: ${MAX_READ_CHARS}.`,\n },\n pattern: {\n type: \"string\",\n description:\n \"Search pattern for grep. Required for grep action. A plain substring by default; set useRegex to true for a regex.\",\n },\n useRegex: {\n type: \"boolean\",\n description:\n \"When true, treat `pattern` as a JavaScript regex (case-insensitive). Default: false.\",\n },\n },\n required: [\"action\"],\n },\n },\n\n run: async (args: Record<string, unknown>): Promise<string> => {\n const scope = resolveScope();\n if (!scope) {\n return \"Error: workspace-files requires an authenticated request context.\";\n }\n\n const action = String(args.action ?? \"\").trim();\n\n try {\n switch (action) {\n case \"write\": {\n const path = String(args.path ?? \"\").trim();\n if (!path) return \"Error: path is required for write.\";\n const content = String(args.content ?? \"\");\n const contentType = String(args.contentType ?? \"text/plain\");\n const meta = await writeWorkspaceFile(\n scope,\n path,\n content,\n contentType,\n );\n return JSON.stringify({\n ok: true,\n action: \"write\",\n resourceId: meta.id,\n path: meta.path,\n contentType: meta.contentType,\n sizeBytes: meta.sizeBytes,\n updatedAt: meta.updatedAt,\n });\n }\n\n case \"append\": {\n const path = String(args.path ?? \"\").trim();\n if (!path) return \"Error: path is required for append.\";\n const content = String(args.content ?? \"\");\n const contentType = String(args.contentType ?? \"text/plain\");\n const meta = await appendWorkspaceFile(\n scope,\n path,\n content,\n contentType,\n );\n return JSON.stringify({\n ok: true,\n action: \"append\",\n resourceId: meta.id,\n path: meta.path,\n contentType: meta.contentType,\n sizeBytes: meta.sizeBytes,\n updatedAt: meta.updatedAt,\n });\n }\n\n case \"read\": {\n const path = String(args.path ?? \"\").trim();\n if (!path) return \"Error: path is required for read.\";\n const rawOffset = Number(args.offset);\n const offset =\n Number.isFinite(rawOffset) && rawOffset > 0\n ? Math.floor(rawOffset)\n : 0;\n const rawMax = Number(args.maxChars);\n const maxChars =\n Number.isFinite(rawMax) && rawMax > 0\n ? Math.min(Math.max(1, Math.floor(rawMax)), MAX_READ_CHARS)\n : DEFAULT_READ_CHARS;\n\n // The sentinel character distinguishes an exact page from a truncated one.\n const file = await readWorkspaceFile(scope, path, {\n offset,\n maxChars: maxChars + 1,\n });\n if (!file) {\n return JSON.stringify({\n ok: false,\n error: `File not found: \"${path}\"`,\n });\n }\n\n const truncated = file.content.length > maxChars;\n const content = file.content.slice(0, maxChars);\n return JSON.stringify({\n ok: true,\n path: file.path,\n contentType: file.contentType,\n sizeBytes: file.sizeBytes,\n updatedAt: file.updatedAt,\n content,\n ...(truncated\n ? {\n truncated: true,\n nextOffset: offset + content.length,\n hint: `File has more content. Call again with offset: ${offset + content.length}`,\n }\n : {}),\n });\n }\n\n case \"list\": {\n const prefix = args.path ? String(args.path).trim() : undefined;\n const files = await listWorkspaceFiles(\n scope,\n prefix || undefined,\n );\n return JSON.stringify({\n ok: true,\n count: files.length,\n files: files.map((f) => ({\n path: f.path,\n sizeBytes: f.sizeBytes,\n contentType: f.contentType,\n updatedAt: f.updatedAt,\n })),\n });\n }\n\n case \"delete\": {\n const path = String(args.path ?? \"\").trim();\n if (!path) return \"Error: path is required for delete.\";\n const deleted = await deleteWorkspaceFile(scope, path);\n return JSON.stringify({\n ok: true,\n deleted,\n path,\n });\n }\n\n case \"grep\": {\n const pattern = String(args.pattern ?? \"\").trim();\n if (!pattern) return \"Error: pattern is required for grep.\";\n const prefix = args.path ? String(args.path).trim() : undefined;\n const useRegex =\n args.useRegex === true || String(args.useRegex) === \"true\";\n const matches = await grepWorkspaceFiles(scope, pattern, {\n pathPrefix: prefix || undefined,\n useRegex,\n maxMatchesPerFile: 20,\n maxFiles: 50,\n });\n return JSON.stringify({\n ok: true,\n pattern,\n matchCount: matches.length,\n matches: matches.map((m) => ({\n path: m.path,\n line: m.lineNumber,\n text: m.line,\n })),\n });\n }\n\n default:\n return `Error: unknown action \"${action}\". Valid actions: write, append, read, list, delete, grep.`;\n }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n return JSON.stringify({ ok: false, error: msg });\n }\n },\n },\n };\n}\n"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: "Durable Background Runs"
|
|
3
|
-
description: "Long agent-chat turns can run on a separate 15-minute Netlify background function instead of the synchronous request, so multi-step work finishes server-side without the client babysitting continuations.
|
|
3
|
+
description: "Long agent-chat turns can run on a separate 15-minute Netlify background function instead of the synchronous request, so multi-step work finishes server-side without the client babysitting continuations. Enabled by default on deployed Netlify apps with an explicit opt-out; a foreground circuit-breaker keeps chat working even if the worker never starts."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Durable Background Runs
|
|
@@ -10,7 +10,8 @@ description: "Long agent-chat turns can run on a separate 15-minute Netlify back
|
|
|
10
10
|
**Who is this for:** anyone deploying an agent-native app who wants long,
|
|
11
11
|
multi-step agent turns to complete server-side, and anyone wondering what the
|
|
12
12
|
`AGENT_CHAT_DURABLE_BACKGROUND` flag and the second Netlify function do. This
|
|
13
|
-
is
|
|
13
|
+
is enabled by default on deployed Netlify apps and entirely inside the
|
|
14
|
+
framework — there is no app code to write.
|
|
14
15
|
|
|
15
16
|
</Callout>
|
|
16
17
|
|
|
@@ -108,14 +109,17 @@ normal API calls always run synchronously on `server`.
|
|
|
108
109
|
The foreground chat POST decides **per turn**. It dispatches to the background
|
|
109
110
|
function only when all three hold:
|
|
110
111
|
|
|
111
|
-
-
|
|
112
|
+
- the app is deployed on Netlify and `AGENT_CHAT_DURABLE_BACKGROUND` is not
|
|
113
|
+
explicitly falsy (`false` / `0` / `no` / `off`), or a non-Netlify hosted app
|
|
114
|
+
explicitly opts in with a truthy value (`true` / `1` / `yes` / `on`),
|
|
112
115
|
- the app is running hosted (on the platform, not local dev), and
|
|
113
116
|
- `A2A_SECRET` is set (the dispatch is an HMAC-signed self-call; without the
|
|
114
117
|
secret it cannot be signed, so the turn stays inline).
|
|
115
118
|
|
|
116
|
-
If
|
|
119
|
+
If the app is local, `A2A_SECRET` is missing, or the flag is explicitly
|
|
120
|
+
disabled, the turn runs inline exactly as before. The setting is read at
|
|
117
121
|
**both build time** (to decide whether to emit the background function) and
|
|
118
|
-
**runtime** (to decide whether to dispatch), so
|
|
122
|
+
**runtime** (to decide whether to dispatch), so changing it requires a redeploy.
|
|
119
123
|
|
|
120
124
|
## The lifecycle and the circuit-breaker {#lifecycle}
|
|
121
125
|
|
|
@@ -190,7 +194,12 @@ one long invocation, not purely additive.
|
|
|
190
194
|
|
|
191
195
|
<Callout id="doc-block-gjoj2d" tone="info">
|
|
192
196
|
|
|
193
|
-
Durable runs are
|
|
197
|
+
Durable runs are enabled by default for deployed Netlify apps. Set
|
|
198
|
+
`AGENT_CHAT_DURABLE_BACKGROUND=false` to opt out, or set it to `true` on another
|
|
199
|
+
host. `A2A_SECRET` is still required. Redeploy after changing the setting, and
|
|
200
|
+
verify a turn actually used the worker by checking that its run reaches
|
|
201
|
+
`dispatch_mode=background-processing` rather than falling back to inline
|
|
202
|
+
recovery.
|
|
194
203
|
|
|
195
204
|
</Callout>
|
|
196
205
|
|
|
@@ -200,7 +200,8 @@ itself checkpoint).
|
|
|
200
200
|
|
|
201
201
|
> Status: **Phase 0 shipped. Phase 1 + Phase 2 implemented** (the host-agnostic
|
|
202
202
|
> durable-background worker and the Netlify 15-min `-background` optimization),
|
|
203
|
-
>
|
|
203
|
+
> default-on for deployed Netlify apps with an explicit opt-out via
|
|
204
|
+
> `AGENT_CHAT_DURABLE_BACKGROUND=false`. Internal per-step
|
|
204
205
|
> checkpointing (the Option A core of Phase 1) is recommended-not-yet-built; the
|
|
205
206
|
> worker today gets its durability from the long single invocation plus
|
|
206
207
|
> server-chained continuations rather than per-step idempotent checkpoints. See
|
|
@@ -251,13 +252,14 @@ checkpointed and durable runs remove the ceiling itself.
|
|
|
251
252
|
|
|
252
253
|
# Final layered architecture
|
|
253
254
|
|
|
254
|
-
Status: implemented (
|
|
255
|
+
Status: implemented (default-on for deployed Netlify, explicit opt-out)
|
|
255
256
|
Owner: core / run-manager + deploy
|
|
256
257
|
|
|
257
|
-
Durable background runs ship as **two layers**.
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
258
|
+
Durable background runs ship as **two layers**. Deployed Netlify apps enable the
|
|
259
|
+
path by default and can opt out with an explicit falsy
|
|
260
|
+
`AGENT_CHAT_DURABLE_BACKGROUND` value. Other hosted platforms retain explicit
|
|
261
|
+
opt-in. When off, the agent-chat run path and deploy output are byte-for-byte
|
|
262
|
+
the pre-existing synchronous behavior.
|
|
261
263
|
|
|
262
264
|
### Layer 1 (portable baseline) — host-agnostic durable execution
|
|
263
265
|
|
|
@@ -600,8 +602,9 @@ Already strong; make the new claim match:
|
|
|
600
602
|
|
|
601
603
|
> Status: \*\*Slices 0–1 implemented and the Slice-3 background-aware stale window
|
|
602
604
|
>
|
|
603
|
-
> - background→background continuation chaining are implemented\*\*,
|
|
604
|
-
>
|
|
605
|
+
> - background→background continuation chaining are implemented\*\*, default-on
|
|
606
|
+
> for deployed Netlify apps with `AGENT_CHAT_DURABLE_BACKGROUND=false` as the
|
|
607
|
+
> opt-out. The host-agnostic baseline
|
|
605
608
|
> (Layer 1) carries the run on any host; the Netlify `-background` emit (Layer 2)
|
|
606
609
|
> is the deploy-time optimization. Slice 2's richer reconnect-first client UX and
|
|
607
610
|
> the internal per-step checkpointing (Option A) remain follow-ups; Slice 4
|
|
@@ -618,9 +621,10 @@ just writes a run event. Dispatch to it from a temporary test route via
|
|
|
618
621
|
stub writes an event to `agent_run_events` from the background function, visible
|
|
619
622
|
via `GET /runs/:id/events`. This de-risks the only genuinely new infra.
|
|
620
623
|
|
|
621
|
-
**Slice 1 — route the real chat loop through the background function
|
|
622
|
-
|
|
623
|
-
|
|
624
|
+
**Slice 1 — route the real chat loop through the background function.** On
|
|
625
|
+
deployed Netlify it is enabled by default; `AGENT_CHAT_DURABLE_BACKGROUND=false`
|
|
626
|
+
opts out. Other hosted platforms require explicit opt-in, and all hosts require
|
|
627
|
+
`A2A_SECRET`: the foreground handler inserts the run row, dispatches, returns the SSE
|
|
624
628
|
stream from `subscribeToRun`. The background `_process-run` claims the run and
|
|
625
629
|
calls the same `startRun` + `runAgentLoop` the inline path uses, with
|
|
626
630
|
`softTimeoutMs ≈ 13min` (new `backgroundFunction` option in
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-native/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.132.0",
|
|
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": {
|
|
@@ -395,8 +395,8 @@
|
|
|
395
395
|
"y-protocols": "^1.0.7",
|
|
396
396
|
"yjs": "^13.6.31",
|
|
397
397
|
"zod": "^4.3.6",
|
|
398
|
-
"@agent-native/
|
|
399
|
-
"@agent-native/
|
|
398
|
+
"@agent-native/recap-cli": "0.5.1",
|
|
399
|
+
"@agent-native/toolkit": "^0.12.1"
|
|
400
400
|
},
|
|
401
401
|
"devDependencies": {
|
|
402
402
|
"@ai-sdk/anthropic": "^3.0.71",
|
package/src/a2a/activity.ts
CHANGED
|
@@ -1,16 +1,27 @@
|
|
|
1
1
|
import { sanitizeToolErrorText } from "../agent/tool-error-redaction.js";
|
|
2
2
|
import type { AgentChatEvent } from "../agent/types.js";
|
|
3
|
+
import { redactArgsToJson, redactTextToSummary } from "../audit/redact.js";
|
|
3
4
|
import type { DataPart, Part } from "./types.js";
|
|
4
5
|
|
|
5
6
|
export const A2A_AGENT_ACTIVITY_KIND = "agent-native/agent-activity";
|
|
6
7
|
export const A2A_AGENT_ACTIVITY_VERSION = 1;
|
|
7
8
|
export const MAX_A2A_ACTIVITY_REASONING_CHARS = 32_768;
|
|
8
9
|
export const MAX_A2A_ACTIVITY_RESPONSE_CHARS = 32_768;
|
|
9
|
-
export const MAX_A2A_ACTIVITY_TOTAL_CHARS = 98_304;
|
|
10
10
|
export const MAX_A2A_ACTIVITY_REASONING_SEGMENTS = 128;
|
|
11
11
|
export const MAX_A2A_ACTIVITY_TOOL_CALLS = 64;
|
|
12
12
|
export const MAX_A2A_ACTIVITY_TOOL_NAME_CHARS = 96;
|
|
13
13
|
export const MAX_A2A_ACTIVITY_TOOL_ID_CHARS = 128;
|
|
14
|
+
export const MAX_A2A_ACTIVITY_TOOL_INPUT_CHARS = 1024;
|
|
15
|
+
export const MAX_A2A_ACTIVITY_TOOL_RESULT_CHARS = 512;
|
|
16
|
+
/**
|
|
17
|
+
* Shared ceiling for every recorded tool input/result across the snapshot. The
|
|
18
|
+
* per-call caps alone allow 64 × 1536 chars, which would push a busy run past
|
|
19
|
+
* `MAX_A2A_ACTIVITY_TOTAL_CHARS` and make `parseA2AAgentActivityPart` reject
|
|
20
|
+
* the whole snapshot — trading missing arguments for a missing trace.
|
|
21
|
+
*/
|
|
22
|
+
export const MAX_A2A_ACTIVITY_TOOL_PAYLOAD_CHARS = 16_384;
|
|
23
|
+
export const MAX_A2A_ACTIVITY_TOTAL_CHARS =
|
|
24
|
+
98_304 + MAX_A2A_ACTIVITY_TOOL_PAYLOAD_CHARS;
|
|
14
25
|
|
|
15
26
|
export type A2AAgentActivityPhase =
|
|
16
27
|
| "reasoning"
|
|
@@ -25,6 +36,13 @@ export interface A2AAgentActivityToolCall {
|
|
|
25
36
|
name: string;
|
|
26
37
|
id?: string;
|
|
27
38
|
status: A2AAgentActivityToolStatus;
|
|
39
|
+
/**
|
|
40
|
+
* Redacted, size-capped JSON of the call's arguments. Absent when the call
|
|
41
|
+
* had none, or when the snapshot's shared payload budget was already spent.
|
|
42
|
+
*/
|
|
43
|
+
input?: string;
|
|
44
|
+
/** Redacted, size-capped head of the tool result (`tool_done` only). */
|
|
45
|
+
result?: string;
|
|
28
46
|
}
|
|
29
47
|
|
|
30
48
|
export interface A2AAgentActivitySnapshot extends Record<string, unknown> {
|
|
@@ -68,9 +86,11 @@ export function createA2AAgentActivityState(
|
|
|
68
86
|
}
|
|
69
87
|
|
|
70
88
|
/**
|
|
71
|
-
* Converts internal loop events into a bounded activity snapshot.
|
|
72
|
-
*
|
|
73
|
-
* results
|
|
89
|
+
* Converts internal loop events into a bounded activity snapshot. Reasoning
|
|
90
|
+
* text is carried verbatim (it was already emitted to the local chat); tool
|
|
91
|
+
* arguments and results are carried only in redacted, size-capped form so the
|
|
92
|
+
* delegated run stays diagnosable without the snapshot becoming a secondary
|
|
93
|
+
* store of secrets or payloads.
|
|
74
94
|
*/
|
|
75
95
|
export function applyA2AAgentActivityEvent(
|
|
76
96
|
state: A2AAgentActivityState,
|
|
@@ -91,14 +111,26 @@ export function applyA2AAgentActivityEvent(
|
|
|
91
111
|
);
|
|
92
112
|
changed = true;
|
|
93
113
|
break;
|
|
94
|
-
case "tool_start":
|
|
114
|
+
case "tool_start": {
|
|
95
115
|
next.activePhase = "tool";
|
|
96
|
-
|
|
116
|
+
const input = captureToolInput(
|
|
117
|
+
event.input,
|
|
118
|
+
remainingPayloadBudget(next.toolCalls),
|
|
119
|
+
);
|
|
120
|
+
next.toolCalls = appendToolCall(next.toolCalls, {
|
|
121
|
+
...toolFromEvent(event),
|
|
122
|
+
...(input ? { input } : {}),
|
|
123
|
+
});
|
|
97
124
|
changed = true;
|
|
98
125
|
break;
|
|
126
|
+
}
|
|
99
127
|
case "tool_done":
|
|
100
128
|
next.activePhase = "tool";
|
|
101
|
-
next.toolCalls = settleToolCall(
|
|
129
|
+
next.toolCalls = settleToolCall(
|
|
130
|
+
next.toolCalls,
|
|
131
|
+
toolFromEvent(event),
|
|
132
|
+
event,
|
|
133
|
+
);
|
|
102
134
|
changed = true;
|
|
103
135
|
break;
|
|
104
136
|
case "text":
|
|
@@ -203,6 +235,49 @@ function toolFromEvent(
|
|
|
203
235
|
};
|
|
204
236
|
}
|
|
205
237
|
|
|
238
|
+
function payloadChars(tool: A2AAgentActivityToolCall): number {
|
|
239
|
+
return (tool.input?.length ?? 0) + (tool.result?.length ?? 0);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function remainingPayloadBudget(
|
|
243
|
+
current: A2AAgentActivityToolCall[],
|
|
244
|
+
excludeIndex = -1,
|
|
245
|
+
): number {
|
|
246
|
+
const used = current.reduce(
|
|
247
|
+
(total, tool, index) =>
|
|
248
|
+
index === excludeIndex ? total : total + payloadChars(tool),
|
|
249
|
+
0,
|
|
250
|
+
);
|
|
251
|
+
return Math.max(0, MAX_A2A_ACTIVITY_TOOL_PAYLOAD_CHARS - used);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Redacted, capped JSON of the arguments, or `undefined` when there is nothing
|
|
256
|
+
* to record or the shared budget cannot fit a whole (still-parseable) capture.
|
|
257
|
+
* A partial JSON string would be worse than none — the reader could not tell a
|
|
258
|
+
* clipped object from a different one.
|
|
259
|
+
*/
|
|
260
|
+
function captureToolInput(input: unknown, budget: number): string | undefined {
|
|
261
|
+
const cap = Math.min(MAX_A2A_ACTIVITY_TOOL_INPUT_CHARS, budget);
|
|
262
|
+
if (cap < MAX_A2A_ACTIVITY_TOOL_INPUT_CHARS / 8) return undefined;
|
|
263
|
+
const json = redactArgsToJson(input, { maxJson: cap, maxString: 256 });
|
|
264
|
+
// JSON.stringify escapes control characters, so the result is already safe
|
|
265
|
+
// for the snapshot without a `sanitizeText` pass — which would rewrite
|
|
266
|
+
// `"token":"[redacted]"` into unparseable JSON.
|
|
267
|
+
if (!json || json === "{}" || json.length > cap) return undefined;
|
|
268
|
+
return json;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
function captureToolResult(
|
|
272
|
+
result: string | undefined,
|
|
273
|
+
budget: number,
|
|
274
|
+
): string | undefined {
|
|
275
|
+
const cap = Math.min(MAX_A2A_ACTIVITY_TOOL_RESULT_CHARS, budget);
|
|
276
|
+
if (!result || cap <= 0) return undefined;
|
|
277
|
+
const summary = redactTextToSummary(result, cap);
|
|
278
|
+
return summary ? sanitizeText(summary, cap) || undefined : undefined;
|
|
279
|
+
}
|
|
280
|
+
|
|
206
281
|
function appendBoundedSegment(
|
|
207
282
|
current: string[],
|
|
208
283
|
addition: string,
|
|
@@ -244,6 +319,7 @@ function appendToolCall(
|
|
|
244
319
|
function settleToolCall(
|
|
245
320
|
current: A2AAgentActivityToolCall[],
|
|
246
321
|
tool: A2AAgentActivityToolCall,
|
|
322
|
+
event: Extract<AgentChatEvent, { type: "tool_done" }>,
|
|
247
323
|
): A2AAgentActivityToolCall[] {
|
|
248
324
|
for (let index = current.length - 1; index >= 0; index -= 1) {
|
|
249
325
|
const existing = current[index];
|
|
@@ -251,12 +327,32 @@ function settleToolCall(
|
|
|
251
327
|
(tool.id && tool.id === existing.id) ||
|
|
252
328
|
(!tool.id && tool.name === existing.name)
|
|
253
329
|
) {
|
|
330
|
+
// The matching `tool_start` already paid for its input; reuse it rather
|
|
331
|
+
// than re-capturing (and re-charging) the same arguments.
|
|
332
|
+
let budget = remainingPayloadBudget(current, index);
|
|
333
|
+
const input =
|
|
334
|
+
existing.input ?? captureToolInput(event.input, budget) ?? undefined;
|
|
335
|
+
budget -= input?.length ?? 0;
|
|
336
|
+
const result = captureToolResult(event.result, budget);
|
|
337
|
+
const settled: A2AAgentActivityToolCall = {
|
|
338
|
+
...tool,
|
|
339
|
+
...(input ? { input } : {}),
|
|
340
|
+
...(result ? { result } : {}),
|
|
341
|
+
};
|
|
254
342
|
return current.map((value, itemIndex) =>
|
|
255
|
-
itemIndex === index ?
|
|
343
|
+
itemIndex === index ? settled : value,
|
|
256
344
|
);
|
|
257
345
|
}
|
|
258
346
|
}
|
|
259
|
-
|
|
347
|
+
let budget = remainingPayloadBudget(current);
|
|
348
|
+
const input = captureToolInput(event.input, budget);
|
|
349
|
+
budget -= input?.length ?? 0;
|
|
350
|
+
const result = captureToolResult(event.result, budget);
|
|
351
|
+
return appendToolCall(current, {
|
|
352
|
+
...tool,
|
|
353
|
+
...(input ? { input } : {}),
|
|
354
|
+
...(result ? { result } : {}),
|
|
355
|
+
});
|
|
260
356
|
}
|
|
261
357
|
|
|
262
358
|
function sanitizeText(value: string, maxChars: number): string {
|
|
@@ -320,12 +416,31 @@ function isSafeToolCall(value: unknown): value is A2AAgentActivityToolCall {
|
|
|
320
416
|
if (!isRecord(value) || !isSafeToolName(value.name)) return false;
|
|
321
417
|
return (
|
|
322
418
|
(value.id === undefined || isSafeToolId(value.id)) &&
|
|
419
|
+
(value.input === undefined ||
|
|
420
|
+
isSafeCapturedText(value.input, MAX_A2A_ACTIVITY_TOOL_INPUT_CHARS)) &&
|
|
421
|
+
(value.result === undefined ||
|
|
422
|
+
isSafeCapturedText(value.result, MAX_A2A_ACTIVITY_TOOL_RESULT_CHARS)) &&
|
|
323
423
|
(value.status === "running" ||
|
|
324
424
|
value.status === "completed" ||
|
|
325
425
|
value.status === "failed")
|
|
326
426
|
);
|
|
327
427
|
}
|
|
328
428
|
|
|
429
|
+
/**
|
|
430
|
+
* Captured input/result are producer-side redacted strings. Unlike reasoning
|
|
431
|
+
* text they are NOT re-sanitized on read: `sanitizeToolErrorText` rewrites
|
|
432
|
+
* `"token":"…"` into unparseable JSON, so a round-trip equality check would
|
|
433
|
+
* reject every legitimate capture. Bound the length and reject raw control
|
|
434
|
+
* characters instead.
|
|
435
|
+
*/
|
|
436
|
+
function isSafeCapturedText(value: unknown, maxChars: number): value is string {
|
|
437
|
+
return (
|
|
438
|
+
typeof value === "string" &&
|
|
439
|
+
value.length <= maxChars &&
|
|
440
|
+
!/[\u0000-\u0008\u000b-\u001f\u007f]/.test(value)
|
|
441
|
+
);
|
|
442
|
+
}
|
|
443
|
+
|
|
329
444
|
function isSafeText(value: unknown, maxChars: number): value is string {
|
|
330
445
|
return (
|
|
331
446
|
typeof value === "string" &&
|
|
@@ -365,7 +480,9 @@ function activityCharacterCount(data: Record<string, unknown>): number {
|
|
|
365
480
|
return (
|
|
366
481
|
total +
|
|
367
482
|
(typeof tool.name === "string" ? tool.name.length : 0) +
|
|
368
|
-
(typeof tool.id === "string" ? tool.id.length : 0)
|
|
483
|
+
(typeof tool.id === "string" ? tool.id.length : 0) +
|
|
484
|
+
(typeof tool.input === "string" ? tool.input.length : 0) +
|
|
485
|
+
(typeof tool.result === "string" ? tool.result.length : 0)
|
|
369
486
|
);
|
|
370
487
|
}, 0)
|
|
371
488
|
: 0;
|
package/src/a2a/index.ts
CHANGED
|
@@ -11,7 +11,10 @@ export {
|
|
|
11
11
|
MAX_A2A_ACTIVITY_TOOL_CALLS,
|
|
12
12
|
MAX_A2A_ACTIVITY_TOTAL_CHARS,
|
|
13
13
|
MAX_A2A_ACTIVITY_TOOL_ID_CHARS,
|
|
14
|
+
MAX_A2A_ACTIVITY_TOOL_INPUT_CHARS,
|
|
14
15
|
MAX_A2A_ACTIVITY_TOOL_NAME_CHARS,
|
|
16
|
+
MAX_A2A_ACTIVITY_TOOL_PAYLOAD_CHARS,
|
|
17
|
+
MAX_A2A_ACTIVITY_TOOL_RESULT_CHARS,
|
|
15
18
|
applyA2AAgentActivityEvent,
|
|
16
19
|
buildA2AAgentActivityPart,
|
|
17
20
|
buildA2AAgentActivitySnapshot,
|