@agent-native/core 0.95.0 → 0.96.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 +35 -0
- package/corpus/core/docs/content/locales/ar-SA/template-design.mdx +13 -0
- package/corpus/core/docs/content/locales/de-DE/template-design.mdx +18 -0
- package/corpus/core/docs/content/locales/es-ES/template-design.mdx +16 -0
- package/corpus/core/docs/content/locales/fr-FR/template-design.mdx +17 -0
- package/corpus/core/docs/content/locales/hi-IN/template-design.mdx +16 -0
- package/corpus/core/docs/content/locales/ja-JP/template-design.mdx +17 -0
- package/corpus/core/docs/content/locales/ko-KR/template-design.mdx +15 -0
- package/corpus/core/docs/content/locales/pt-BR/template-design.mdx +16 -0
- package/corpus/core/docs/content/locales/zh-CN/template-design.mdx +11 -0
- package/corpus/core/docs/content/locales/zh-TW/template-design.mdx +12 -0
- package/corpus/core/docs/content/template-design.mdx +16 -0
- package/corpus/core/package.json +4 -2
- package/corpus/core/src/a2a/client.ts +11 -1
- package/corpus/core/src/agent/production-agent.ts +107 -27
- package/corpus/core/src/agent/thread-data-builder.ts +48 -22
- package/corpus/core/src/chat-threads/store.ts +20 -1
- package/corpus/core/src/cli/code-agent-executor.ts +1 -0
- package/corpus/core/src/cli/code-agent-runs.ts +14 -0
- package/corpus/core/src/client/AgentPanel.tsx +32 -25
- package/corpus/core/src/client/AssistantChat.tsx +286 -45
- package/corpus/core/src/client/MultiTabAssistantChat.tsx +141 -90
- package/corpus/core/src/client/chat/ChatHistoryList.tsx +404 -0
- package/corpus/core/src/client/chat/index.ts +6 -0
- package/corpus/core/src/client/chat/tool-call-display.tsx +38 -4
- package/corpus/core/src/client/chat/use-reconnect-reader-owner.ts +28 -0
- package/corpus/core/src/client/code-agent-chat-adapter.ts +72 -4
- package/corpus/core/src/client/composer/RealtimeVoiceMode.tsx +52 -11
- package/corpus/core/src/client/composer/TiptapComposer.tsx +157 -20
- package/corpus/core/src/client/composer/VoiceButton.tsx +28 -0
- package/corpus/core/src/client/composer/useRealtimeVoiceMode.tsx +5 -0
- package/corpus/core/src/client/conversation/code-agent-transcript.ts +4 -5
- package/corpus/core/src/client/guided-questions.tsx +11 -2
- package/corpus/core/src/client/index.ts +11 -0
- package/corpus/core/src/client/integrations/IntegrationsPanel.tsx +6 -7
- package/corpus/core/src/client/sse-event-processor.ts +90 -21
- package/corpus/core/src/client/use-chat-threads.ts +10 -1
- package/corpus/core/src/client/voice-provider-status.ts +44 -0
- package/corpus/core/src/code-agents/transcript-normalizer.ts +76 -0
- package/corpus/core/src/connections/catalog.ts +2 -2
- package/corpus/core/src/deploy/build.ts +12 -8
- package/corpus/core/src/integrations/a2a-continuation-processor.ts +35 -5
- package/corpus/core/src/integrations/adapters/slack.ts +74 -21
- package/corpus/core/src/integrations/catalog.ts +2 -2
- package/corpus/core/src/integrations/webhook-handler.ts +14 -0
- package/corpus/core/src/localization/default-messages.ts +6 -0
- package/corpus/core/src/observability/hosted-model-experiment.ts +118 -0
- package/corpus/core/src/observability/routes.ts +17 -0
- package/corpus/core/src/observability/store.ts +4 -1
- package/corpus/core/src/observability/traces.ts +41 -2
- package/corpus/core/src/scripts/agent-engines/list-agent-engines.ts +19 -1
- package/corpus/core/src/scripts/call-agent.ts +53 -3
- package/corpus/core/src/scripts/chat/search-chats.ts +11 -8
- package/corpus/core/src/secrets/register-framework-secrets.ts +1 -1
- package/corpus/core/src/server/agent-chat-plugin.ts +41 -6
- package/corpus/core/src/server/auth.ts +1 -1
- package/corpus/core/src/server/core-routes-plugin.ts +15 -0
- package/corpus/core/src/server/credential-provider.ts +7 -3
- package/corpus/core/src/server/realtime-voice.ts +71 -24
- package/corpus/core/src/server/voice-providers-status.ts +4 -3
- package/corpus/core/src/shared/cache-control.ts +4 -4
- package/corpus/core/src/styles/agent-native.css +1 -0
- package/corpus/core/src/styles/chat-history-list.css +313 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/observability/SKILL.md +20 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/voice-transcription/SKILL.md +8 -4
- package/corpus/core/src/vite/client.ts +1 -0
- package/corpus/templates/analytics/AGENTS.md +7 -0
- package/corpus/templates/analytics/actions/bigquery.ts +26 -2
- package/corpus/templates/analytics/actions/data-source-status.ts +18 -0
- package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +5 -4
- package/corpus/templates/analytics/app/global.css +10 -0
- package/corpus/templates/analytics/app/lib/data-sources.ts +5 -4
- package/corpus/templates/analytics/app/pages/Ask.tsx +25 -2
- package/corpus/templates/analytics/changelog/2026-07-10-analytics-answers-simple-time-bounded-metrics-without-unnece.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-10-analytics-chat-reliably-uses-connected-data-sources-across-s.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-10-chat-threads-now-stay-clear-of-top-actions-and-fade-smoothly.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-10-context-chips-can-now-be-selected-and-removed-one-at-a-time-.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-10-slack-token-setup-marked-legacy.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-10-the-ask-composer-no-longer-carries-dashboard-or-panel-contex.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-10-the-ask-section-stays-highlighted-while-its-chat-history-is-.md +6 -0
- package/corpus/templates/analytics/server/lib/bigquery.ts +90 -14
- package/corpus/templates/analytics/server/lib/credential-keys.ts +6 -2
- package/corpus/templates/analytics/server/plugins/agent-chat.ts +82 -7
- package/corpus/templates/brain/changelog/2026-07-10-slack-backfill-token-marked-legacy.md +6 -0
- package/corpus/templates/brain/server/register-secrets.ts +2 -2
- package/corpus/templates/clips/app/components/library/library-layout.tsx +7 -1
- package/corpus/templates/clips/app/components/library/page-header.tsx +19 -3
- package/corpus/templates/clips/app/routes/_app.library._index.tsx +16 -12
- package/corpus/templates/clips/changelog/2026-07-10-new-recording-appears-once-when-the-library-sidebar-is-open.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-10-slack-token-fallback-guidance.md +6 -0
- package/corpus/templates/clips/server/register-secrets.ts +1 -1
- package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +0 -66
- package/corpus/templates/content/app/routes/_app.local-files.tsx +7 -47
- package/corpus/templates/content/changelog/2026-07-10-local-folders-now-wait-for-an-explicit-pull-before-content-r.md +6 -0
- package/corpus/templates/content/package.json +1 -1
- package/corpus/templates/design/actions/generate-design.ts +128 -31
- package/corpus/templates/design/actions/present-design-variants.ts +37 -9
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +9 -3
- package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +32 -10
- package/corpus/templates/design/app/components/design/QuestionFlow.tsx +2 -2
- package/corpus/templates/design/app/components/design/TweaksPanel.tsx +9 -1
- package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +7 -5
- package/corpus/templates/design/app/components/design/multi-screen/types.ts +3 -0
- package/corpus/templates/design/app/global.css +10 -0
- package/corpus/templates/design/app/hooks/use-question-flow.ts +9 -2
- package/corpus/templates/design/app/i18n/zh-TW.ts +1 -0
- package/corpus/templates/design/app/i18n-data.ts +21 -11
- package/corpus/templates/design/changelog/2026-07-10-editor-panels-are-easier-to-distinguish-and-design-intake-qu.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-interact-mode-now-stays-on-the-full-canvas-matches-edit-visu.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-new-web-designs-open-at-desktop-size-and-adapt-across-mobile.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-tweaks-now-link-to-full-documentation.md +6 -0
- package/corpus/templates/design/server/plugins/agent-chat.ts +2 -0
- package/corpus/templates/mail/app/i18n/ar-SA.ts +3 -3
- package/corpus/templates/mail/app/i18n/de-DE.ts +3 -3
- package/corpus/templates/mail/app/i18n/en-US.ts +4 -3
- package/corpus/templates/mail/app/i18n/es-ES.ts +3 -3
- package/corpus/templates/mail/app/i18n/fr-FR.ts +3 -3
- package/corpus/templates/mail/app/i18n/hi-IN.ts +3 -3
- package/corpus/templates/mail/app/i18n/ja-JP.ts +3 -3
- package/corpus/templates/mail/app/i18n/ko-KR.ts +3 -3
- package/corpus/templates/mail/app/i18n/pt-BR.ts +3 -3
- package/corpus/templates/mail/app/i18n/zh-CN.ts +3 -3
- package/corpus/templates/mail/app/i18n/zh-TW.ts +3 -3
- package/corpus/templates/mail/changelog/2026-07-10-slack-intake-marked-legacy.md +6 -0
- package/corpus/templates/mail/server/lib/env-config.ts +5 -4
- package/corpus/templates/plan/package.json +1 -1
- package/dist/a2a/client.d.ts +7 -0
- package/dist/a2a/client.d.ts.map +1 -1
- package/dist/a2a/client.js +2 -1
- package/dist/a2a/client.js.map +1 -1
- package/dist/agent/production-agent.d.ts +6 -0
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +83 -26
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/agent/thread-data-builder.d.ts +1 -0
- package/dist/agent/thread-data-builder.d.ts.map +1 -1
- package/dist/agent/thread-data-builder.js +42 -23
- package/dist/agent/thread-data-builder.js.map +1 -1
- package/dist/chat-threads/store.d.ts +10 -0
- package/dist/chat-threads/store.d.ts.map +1 -1
- package/dist/chat-threads/store.js +6 -0
- package/dist/chat-threads/store.js.map +1 -1
- package/dist/cli/code-agent-executor.d.ts.map +1 -1
- package/dist/cli/code-agent-executor.js +1 -0
- package/dist/cli/code-agent-executor.js.map +1 -1
- package/dist/cli/code-agent-runs.d.ts +12 -0
- package/dist/cli/code-agent-runs.d.ts.map +1 -1
- package/dist/cli/code-agent-runs.js +1 -0
- package/dist/cli/code-agent-runs.js.map +1 -1
- package/dist/client/AgentPanel.d.ts.map +1 -1
- package/dist/client/AgentPanel.js +3 -3
- package/dist/client/AgentPanel.js.map +1 -1
- package/dist/client/AssistantChat.d.ts +14 -1
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +207 -32
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
- package/dist/client/MultiTabAssistantChat.js +83 -10
- package/dist/client/MultiTabAssistantChat.js.map +1 -1
- package/dist/client/chat/ChatHistoryList.d.ts +88 -0
- package/dist/client/chat/ChatHistoryList.d.ts.map +1 -0
- package/dist/client/chat/ChatHistoryList.js +83 -0
- package/dist/client/chat/ChatHistoryList.js.map +1 -0
- package/dist/client/chat/index.d.ts +1 -0
- package/dist/client/chat/index.d.ts.map +1 -1
- package/dist/client/chat/index.js +1 -0
- package/dist/client/chat/index.js.map +1 -1
- package/dist/client/chat/tool-call-display.d.ts +13 -1
- package/dist/client/chat/tool-call-display.d.ts.map +1 -1
- package/dist/client/chat/tool-call-display.js +11 -3
- package/dist/client/chat/tool-call-display.js.map +1 -1
- package/dist/client/chat/use-reconnect-reader-owner.d.ts +11 -0
- package/dist/client/chat/use-reconnect-reader-owner.d.ts.map +1 -0
- package/dist/client/chat/use-reconnect-reader-owner.js +21 -0
- package/dist/client/chat/use-reconnect-reader-owner.js.map +1 -0
- package/dist/client/code-agent-chat-adapter.d.ts +17 -1
- package/dist/client/code-agent-chat-adapter.d.ts.map +1 -1
- package/dist/client/code-agent-chat-adapter.js +47 -3
- package/dist/client/code-agent-chat-adapter.js.map +1 -1
- package/dist/client/composer/RealtimeVoiceMode.d.ts +11 -1
- package/dist/client/composer/RealtimeVoiceMode.d.ts.map +1 -1
- package/dist/client/composer/RealtimeVoiceMode.js +5 -3
- package/dist/client/composer/RealtimeVoiceMode.js.map +1 -1
- package/dist/client/composer/TiptapComposer.d.ts +25 -2
- package/dist/client/composer/TiptapComposer.d.ts.map +1 -1
- package/dist/client/composer/TiptapComposer.js +96 -5
- package/dist/client/composer/TiptapComposer.js.map +1 -1
- package/dist/client/composer/VoiceButton.d.ts.map +1 -1
- package/dist/client/composer/VoiceButton.js +21 -1
- package/dist/client/composer/VoiceButton.js.map +1 -1
- package/dist/client/composer/useRealtimeVoiceMode.d.ts.map +1 -1
- package/dist/client/composer/useRealtimeVoiceMode.js +5 -0
- package/dist/client/composer/useRealtimeVoiceMode.js.map +1 -1
- package/dist/client/conversation/code-agent-transcript.d.ts +2 -0
- package/dist/client/conversation/code-agent-transcript.d.ts.map +1 -1
- package/dist/client/conversation/code-agent-transcript.js +3 -5
- package/dist/client/conversation/code-agent-transcript.js.map +1 -1
- package/dist/client/guided-questions.d.ts.map +1 -1
- package/dist/client/guided-questions.js +7 -2
- package/dist/client/guided-questions.js.map +1 -1
- package/dist/client/index.d.ts +3 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +3 -1
- package/dist/client/index.js.map +1 -1
- package/dist/client/integrations/IntegrationsPanel.d.ts.map +1 -1
- package/dist/client/integrations/IntegrationsPanel.js +5 -7
- package/dist/client/integrations/IntegrationsPanel.js.map +1 -1
- package/dist/client/sse-event-processor.d.ts.map +1 -1
- package/dist/client/sse-event-processor.js +67 -20
- package/dist/client/sse-event-processor.js.map +1 -1
- package/dist/client/use-chat-threads.d.ts.map +1 -1
- package/dist/client/use-chat-threads.js +9 -1
- package/dist/client/use-chat-threads.js.map +1 -1
- package/dist/client/voice-provider-status.d.ts +10 -0
- package/dist/client/voice-provider-status.d.ts.map +1 -0
- package/dist/client/voice-provider-status.js +32 -0
- package/dist/client/voice-provider-status.js.map +1 -0
- package/dist/code-agents/transcript-normalizer.d.ts +29 -0
- package/dist/code-agents/transcript-normalizer.d.ts.map +1 -1
- package/dist/code-agents/transcript-normalizer.js +55 -0
- package/dist/code-agents/transcript-normalizer.js.map +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/connections/catalog.d.ts +2 -2
- package/dist/connections/catalog.js +2 -2
- package/dist/connections/catalog.js.map +1 -1
- package/dist/deploy/build.d.ts.map +1 -1
- package/dist/deploy/build.js +12 -8
- package/dist/deploy/build.js.map +1 -1
- package/dist/integrations/a2a-continuation-processor.d.ts.map +1 -1
- package/dist/integrations/a2a-continuation-processor.js +25 -5
- package/dist/integrations/a2a-continuation-processor.js.map +1 -1
- package/dist/integrations/adapters/slack.d.ts.map +1 -1
- package/dist/integrations/adapters/slack.js +55 -21
- package/dist/integrations/adapters/slack.js.map +1 -1
- package/dist/integrations/catalog.js +2 -2
- package/dist/integrations/catalog.js.map +1 -1
- package/dist/integrations/webhook-handler.d.ts.map +1 -1
- package/dist/integrations/webhook-handler.js +11 -0
- package/dist/integrations/webhook-handler.js.map +1 -1
- package/dist/localization/default-messages.d.ts +5 -0
- package/dist/localization/default-messages.d.ts.map +1 -1
- package/dist/localization/default-messages.js +5 -0
- package/dist/localization/default-messages.js.map +1 -1
- package/dist/observability/hosted-model-experiment.d.ts +39 -0
- package/dist/observability/hosted-model-experiment.d.ts.map +1 -0
- package/dist/observability/hosted-model-experiment.js +90 -0
- package/dist/observability/hosted-model-experiment.js.map +1 -0
- package/dist/observability/routes.d.ts.map +1 -1
- package/dist/observability/routes.js +16 -0
- package/dist/observability/routes.js.map +1 -1
- package/dist/observability/store.d.ts.map +1 -1
- package/dist/observability/store.js +4 -1
- package/dist/observability/store.js.map +1 -1
- package/dist/observability/traces.d.ts +6 -0
- package/dist/observability/traces.d.ts.map +1 -1
- package/dist/observability/traces.js +28 -2
- package/dist/observability/traces.js.map +1 -1
- package/dist/provider-api/corpus-jobs.d.ts +2 -2
- package/dist/scripts/agent-engines/list-agent-engines.d.ts.map +1 -1
- package/dist/scripts/agent-engines/list-agent-engines.js +19 -1
- package/dist/scripts/agent-engines/list-agent-engines.js.map +1 -1
- package/dist/scripts/call-agent.d.ts.map +1 -1
- package/dist/scripts/call-agent.js +43 -3
- package/dist/scripts/call-agent.js.map +1 -1
- package/dist/scripts/chat/search-chats.d.ts +1 -1
- package/dist/scripts/chat/search-chats.d.ts.map +1 -1
- package/dist/scripts/chat/search-chats.js +11 -8
- package/dist/scripts/chat/search-chats.js.map +1 -1
- package/dist/secrets/register-framework-secrets.js +1 -1
- package/dist/secrets/register-framework-secrets.js.map +1 -1
- package/dist/server/agent-chat-plugin.d.ts +11 -0
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +27 -6
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/auth.js +1 -1
- package/dist/server/auth.js.map +1 -1
- package/dist/server/core-routes-plugin.d.ts +3 -0
- package/dist/server/core-routes-plugin.d.ts.map +1 -1
- package/dist/server/core-routes-plugin.js +13 -0
- package/dist/server/core-routes-plugin.js.map +1 -1
- package/dist/server/credential-provider.d.ts +5 -3
- package/dist/server/credential-provider.d.ts.map +1 -1
- package/dist/server/credential-provider.js +7 -3
- package/dist/server/credential-provider.js.map +1 -1
- package/dist/server/realtime-voice.d.ts.map +1 -1
- package/dist/server/realtime-voice.js +55 -21
- package/dist/server/realtime-voice.js.map +1 -1
- package/dist/server/voice-providers-status.d.ts.map +1 -1
- package/dist/server/voice-providers-status.js +2 -3
- package/dist/server/voice-providers-status.js.map +1 -1
- package/dist/shared/cache-control.d.ts +6 -6
- package/dist/shared/cache-control.d.ts.map +1 -1
- package/dist/shared/cache-control.js +3 -3
- package/dist/shared/cache-control.js.map +1 -1
- package/dist/styles/agent-native.css +1 -0
- package/dist/styles/chat-history-list.css +313 -0
- package/dist/templates/workspace-core/.agents/skills/observability/SKILL.md +20 -0
- package/dist/templates/workspace-core/.agents/skills/voice-transcription/SKILL.md +8 -4
- package/dist/vite/client.d.ts.map +1 -1
- package/dist/vite/client.js +1 -0
- package/dist/vite/client.js.map +1 -1
- package/docs/content/locales/ar-SA/template-design.mdx +13 -0
- package/docs/content/locales/de-DE/template-design.mdx +18 -0
- package/docs/content/locales/es-ES/template-design.mdx +16 -0
- package/docs/content/locales/fr-FR/template-design.mdx +17 -0
- package/docs/content/locales/hi-IN/template-design.mdx +16 -0
- package/docs/content/locales/ja-JP/template-design.mdx +17 -0
- package/docs/content/locales/ko-KR/template-design.mdx +15 -0
- package/docs/content/locales/pt-BR/template-design.mdx +16 -0
- package/docs/content/locales/zh-CN/template-design.mdx +11 -0
- package/docs/content/locales/zh-TW/template-design.mdx +12 -0
- package/docs/content/template-design.mdx +16 -0
- package/package.json +4 -2
- package/src/templates/workspace-core/.agents/skills/observability/SKILL.md +20 -0
- package/src/templates/workspace-core/.agents/skills/voice-transcription/SKILL.md +8 -4
|
@@ -216,6 +216,12 @@ const messages = {
|
|
|
216
216
|
promptTitle: "Talk to your app",
|
|
217
217
|
promptDescription:
|
|
218
218
|
"Voice mode keeps listening while the agent navigates and takes actions.",
|
|
219
|
+
setupTitle: "Set up voice mode",
|
|
220
|
+
setupDescription:
|
|
221
|
+
"Connect Builder to use managed voice with credits, or use your own OpenAI API key.",
|
|
222
|
+
connectBuilder: "Connect Builder",
|
|
223
|
+
useOpenAiKey: "Use OpenAI API key",
|
|
224
|
+
startWithOpenAiKey: "Start with OpenAI key",
|
|
219
225
|
start: "Start voice mode",
|
|
220
226
|
keepDictating: "Keep dictating",
|
|
221
227
|
showChat: "Show chat",
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
export const HOSTED_DEFAULT_MODEL_EXPERIMENT_ID =
|
|
2
|
+
"hosted-default-model-sonnet-5-vs-gpt-5-6-luna-2026-07";
|
|
3
|
+
|
|
4
|
+
export const HOSTED_DEFAULT_MODEL_CONTROL = {
|
|
5
|
+
id: "sonnet-5",
|
|
6
|
+
model: "claude-sonnet-5",
|
|
7
|
+
weight: 80,
|
|
8
|
+
} as const;
|
|
9
|
+
|
|
10
|
+
export const HOSTED_DEFAULT_MODEL_TREATMENT = {
|
|
11
|
+
id: "gpt-5-6-luna",
|
|
12
|
+
model: "gpt-5-6-luna",
|
|
13
|
+
weight: 20,
|
|
14
|
+
} as const;
|
|
15
|
+
|
|
16
|
+
export interface HostedDefaultModelExperimentAssignment {
|
|
17
|
+
experimentId: string;
|
|
18
|
+
variantId: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface HostedDefaultModelExperimentResolution {
|
|
22
|
+
model: string;
|
|
23
|
+
assignment: HostedDefaultModelExperimentAssignment;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
type HostedExperimentEnv = Record<string, string | undefined>;
|
|
27
|
+
|
|
28
|
+
const FIRST_PARTY_HOST_SUFFIX = ".agent-native.com";
|
|
29
|
+
const ENABLED_VALUES = new Set(["1", "true", "on", "yes"]);
|
|
30
|
+
const DISABLED_VALUES = new Set(["0", "false", "off", "no"]);
|
|
31
|
+
|
|
32
|
+
function hostnameFromUrl(value: string | undefined): string | null {
|
|
33
|
+
const trimmed = value?.trim();
|
|
34
|
+
if (!trimmed) return null;
|
|
35
|
+
try {
|
|
36
|
+
const url = /^[a-z][a-z0-9+.-]*:\/\//i.test(trimmed)
|
|
37
|
+
? new URL(trimmed)
|
|
38
|
+
: new URL(`https://${trimmed}`);
|
|
39
|
+
return url.hostname.toLowerCase();
|
|
40
|
+
} catch {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* The rollout is automatic only on first-party hosted app domains. Operators
|
|
47
|
+
* can explicitly enable or disable it for preview and emergency rollback.
|
|
48
|
+
*/
|
|
49
|
+
export function isHostedDefaultModelExperimentEnabled(
|
|
50
|
+
env: HostedExperimentEnv = process.env,
|
|
51
|
+
): boolean {
|
|
52
|
+
const override =
|
|
53
|
+
env.AGENT_NATIVE_HOSTED_MODEL_EXPERIMENT?.trim().toLowerCase();
|
|
54
|
+
if (override && DISABLED_VALUES.has(override)) return false;
|
|
55
|
+
if (override && ENABLED_VALUES.has(override)) return true;
|
|
56
|
+
|
|
57
|
+
const hostnames = [
|
|
58
|
+
env.APP_URL,
|
|
59
|
+
env.BETTER_AUTH_URL,
|
|
60
|
+
env.URL,
|
|
61
|
+
env.DEPLOY_URL,
|
|
62
|
+
env.VERCEL_PROJECT_PRODUCTION_URL,
|
|
63
|
+
env.VERCEL_URL,
|
|
64
|
+
]
|
|
65
|
+
.map(hostnameFromUrl)
|
|
66
|
+
.filter((hostname): hostname is string => Boolean(hostname));
|
|
67
|
+
|
|
68
|
+
return hostnames.some(
|
|
69
|
+
(hostname) =>
|
|
70
|
+
hostname === "agent-native.com" ||
|
|
71
|
+
hostname.endsWith(FIRST_PARTY_HOST_SUFFIX),
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Stable cross-app bucket: the same authenticated user receives the same
|
|
77
|
+
* variant in every hosted template for the life of this experiment id.
|
|
78
|
+
*/
|
|
79
|
+
export function hostedDefaultModelExperimentBucket(userId: string): number {
|
|
80
|
+
const input = `${HOSTED_DEFAULT_MODEL_EXPERIMENT_ID}:${userId.trim().toLowerCase()}`;
|
|
81
|
+
let hash = 0x811c9dc5;
|
|
82
|
+
for (let index = 0; index < input.length; index++) {
|
|
83
|
+
hash ^= input.charCodeAt(index);
|
|
84
|
+
hash = Math.imul(hash, 0x01000193);
|
|
85
|
+
}
|
|
86
|
+
return (hash >>> 0) % 100;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export function resolveHostedDefaultModelExperiment(args: {
|
|
90
|
+
userId: string | null | undefined;
|
|
91
|
+
engineName: string;
|
|
92
|
+
isDefaultModelSelection: boolean;
|
|
93
|
+
supportedModels?: readonly string[];
|
|
94
|
+
env?: HostedExperimentEnv;
|
|
95
|
+
}): HostedDefaultModelExperimentResolution | null {
|
|
96
|
+
const userId = args.userId?.trim();
|
|
97
|
+
if (!userId) return null;
|
|
98
|
+
if (args.engineName !== "builder") return null;
|
|
99
|
+
if (!args.isDefaultModelSelection) return null;
|
|
100
|
+
if (!isHostedDefaultModelExperimentEnabled(args.env)) return null;
|
|
101
|
+
|
|
102
|
+
const variant =
|
|
103
|
+
hostedDefaultModelExperimentBucket(userId) <
|
|
104
|
+
HOSTED_DEFAULT_MODEL_TREATMENT.weight
|
|
105
|
+
? HOSTED_DEFAULT_MODEL_TREATMENT
|
|
106
|
+
: HOSTED_DEFAULT_MODEL_CONTROL;
|
|
107
|
+
if (args.supportedModels && !args.supportedModels.includes(variant.model)) {
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return {
|
|
112
|
+
model: variant.model,
|
|
113
|
+
assignment: {
|
|
114
|
+
experimentId: HOSTED_DEFAULT_MODEL_EXPERIMENT_ID,
|
|
115
|
+
variantId: variant.id,
|
|
116
|
+
},
|
|
117
|
+
};
|
|
118
|
+
}
|
|
@@ -69,6 +69,18 @@ async function resolveOwner(event: H3Event): Promise<string> {
|
|
|
69
69
|
return session.email;
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
+
function canManageExperiments(ownerEmail: string): boolean {
|
|
73
|
+
// Local development keeps the built-in dashboard usable without additional
|
|
74
|
+
// setup. Hosted deployments fail closed unless the operator supplies an
|
|
75
|
+
// explicit allowlist, because experiments affect every user in the app.
|
|
76
|
+
if (process.env.NODE_ENV !== "production") return true;
|
|
77
|
+
const admins = (process.env.AGENT_NATIVE_EXPERIMENT_ADMIN_EMAILS ?? "")
|
|
78
|
+
.split(",")
|
|
79
|
+
.map((email) => email.trim().toLowerCase())
|
|
80
|
+
.filter(Boolean);
|
|
81
|
+
return admins.includes(ownerEmail.trim().toLowerCase());
|
|
82
|
+
}
|
|
83
|
+
|
|
72
84
|
function parseSince(q: Record<string, any>): number {
|
|
73
85
|
const raw = q.since;
|
|
74
86
|
if (typeof raw === "string" && raw.length > 0) {
|
|
@@ -236,6 +248,11 @@ export function createObservabilityHandler() {
|
|
|
236
248
|
return getEvalStats(parseSince(q), { userId: owner });
|
|
237
249
|
}
|
|
238
250
|
|
|
251
|
+
if (parts[0] === "experiments" && !canManageExperiments(owner)) {
|
|
252
|
+
setResponseStatus(event, 403);
|
|
253
|
+
return { error: "Experiment administrator access required" };
|
|
254
|
+
}
|
|
255
|
+
|
|
239
256
|
// POST /experiments — create experiment. Records the calling user as
|
|
240
257
|
// the owner so subsequent PUT / POST results require the same caller.
|
|
241
258
|
if (method === "POST" && parts.length === 1 && parts[0] === "experiments") {
|
|
@@ -972,7 +972,10 @@ export async function updateExperiment(
|
|
|
972
972
|
sets.push("status = ?");
|
|
973
973
|
args.push(updates.status);
|
|
974
974
|
if (updates.status === "running" && !updates.endedAt) {
|
|
975
|
-
|
|
975
|
+
// Preserve the original exposure window when a paused experiment
|
|
976
|
+
// resumes; resetting it would silently discard the first run period from
|
|
977
|
+
// the results.
|
|
978
|
+
sets.push("started_at = COALESCE(started_at, ?)");
|
|
976
979
|
args.push(Date.now());
|
|
977
980
|
}
|
|
978
981
|
}
|
|
@@ -100,6 +100,11 @@ function emitLlmGenerationTrackingEvent(args: {
|
|
|
100
100
|
successfulTools: number;
|
|
101
101
|
failedTools: number;
|
|
102
102
|
createdAt: number;
|
|
103
|
+
experimentAssignments?: Array<{
|
|
104
|
+
experimentId: string;
|
|
105
|
+
variantId: string;
|
|
106
|
+
}>;
|
|
107
|
+
modelSelectionSource?: string;
|
|
103
108
|
}): void {
|
|
104
109
|
const provider = llmProviderFromEngine(args.engineName, args.model);
|
|
105
110
|
const costUsd = costUsdFromCenticents(args.costCentsX100);
|
|
@@ -126,6 +131,7 @@ function emitLlmGenerationTrackingEvent(args: {
|
|
|
126
131
|
tool_calls: args.toolCalls,
|
|
127
132
|
successful_tools: args.successfulTools,
|
|
128
133
|
failed_tools: args.failedTools,
|
|
134
|
+
model_selection_source: args.modelSelectionSource,
|
|
129
135
|
created_at: new Date(args.createdAt).toISOString(),
|
|
130
136
|
created_at_ms: args.createdAt,
|
|
131
137
|
$ai_trace_id: args.runId,
|
|
@@ -145,6 +151,18 @@ function emitLlmGenerationTrackingEvent(args: {
|
|
|
145
151
|
$ai_request_count: 1,
|
|
146
152
|
$ai_total_cost_usd: costUsd,
|
|
147
153
|
};
|
|
154
|
+
if (args.experimentAssignments?.length) {
|
|
155
|
+
properties.experiment_ids = args.experimentAssignments
|
|
156
|
+
.map((assignment) => assignment.experimentId)
|
|
157
|
+
.join(",");
|
|
158
|
+
properties.experiment_variants = args.experimentAssignments
|
|
159
|
+
.map((assignment) => assignment.variantId)
|
|
160
|
+
.join(",");
|
|
161
|
+
if (args.experimentAssignments.length === 1) {
|
|
162
|
+
properties.experiment_id = args.experimentAssignments[0].experimentId;
|
|
163
|
+
properties.experiment_variant = args.experimentAssignments[0].variantId;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
148
166
|
if (error) properties.error_message = error;
|
|
149
167
|
|
|
150
168
|
for (const key of Object.keys(properties)) {
|
|
@@ -245,6 +263,12 @@ export async function instrumentAgentLoop(opts: {
|
|
|
245
263
|
* reads. */
|
|
246
264
|
userId: string | null;
|
|
247
265
|
config: ObservabilityConfig;
|
|
266
|
+
metadata?: Record<string, unknown> | null;
|
|
267
|
+
experimentAssignments?: Array<{
|
|
268
|
+
experimentId: string;
|
|
269
|
+
variantId: string;
|
|
270
|
+
}>;
|
|
271
|
+
modelSelectionSource?: string;
|
|
248
272
|
classifyError?: (error: unknown) =>
|
|
249
273
|
| {
|
|
250
274
|
status?: "success" | "error";
|
|
@@ -268,6 +292,15 @@ export async function instrumentAgentLoop(opts: {
|
|
|
268
292
|
"agent.thread_id": threadId ?? undefined,
|
|
269
293
|
"agent.user_id": userId ?? undefined,
|
|
270
294
|
"agent.model": loopOpts.model,
|
|
295
|
+
"agent.model_selection_source": opts.modelSelectionSource,
|
|
296
|
+
"agent.experiment_id":
|
|
297
|
+
opts.experimentAssignments?.length === 1
|
|
298
|
+
? opts.experimentAssignments[0].experimentId
|
|
299
|
+
: undefined,
|
|
300
|
+
"agent.experiment_variant":
|
|
301
|
+
opts.experimentAssignments?.length === 1
|
|
302
|
+
? opts.experimentAssignments[0].variantId
|
|
303
|
+
: undefined,
|
|
271
304
|
});
|
|
272
305
|
|
|
273
306
|
const spans: TraceSpan[] = [];
|
|
@@ -424,7 +457,7 @@ export async function instrumentAgentLoop(opts: {
|
|
|
424
457
|
let usage: AgentLoopUsage | undefined;
|
|
425
458
|
let runStatus: "success" | "error" = "success";
|
|
426
459
|
let errorMessage: string | null = null;
|
|
427
|
-
let runMetadata: Record<string, unknown> | null = null;
|
|
460
|
+
let runMetadata: Record<string, unknown> | null = opts.metadata ?? null;
|
|
428
461
|
try {
|
|
429
462
|
usage = await runAgentLoop({ ...loopOpts, send: instrumentedSend });
|
|
430
463
|
} catch (err: any) {
|
|
@@ -434,7 +467,11 @@ export async function instrumentAgentLoop(opts: {
|
|
|
434
467
|
classification?.errorMessage === undefined
|
|
435
468
|
? (err?.message ?? String(err))
|
|
436
469
|
: classification.errorMessage;
|
|
437
|
-
|
|
470
|
+
const errorMetadata = classification?.metadata ?? null;
|
|
471
|
+
runMetadata =
|
|
472
|
+
runMetadata || errorMetadata
|
|
473
|
+
? { ...(runMetadata ?? {}), ...(errorMetadata ?? {}) }
|
|
474
|
+
: null;
|
|
438
475
|
throw err;
|
|
439
476
|
} finally {
|
|
440
477
|
const runEnd = Date.now();
|
|
@@ -501,6 +538,8 @@ export async function instrumentAgentLoop(opts: {
|
|
|
501
538
|
successfulTools,
|
|
502
539
|
failedTools,
|
|
503
540
|
createdAt: runStart,
|
|
541
|
+
experimentAssignments: opts.experimentAssignments,
|
|
542
|
+
modelSelectionSource: opts.modelSelectionSource,
|
|
504
543
|
});
|
|
505
544
|
}
|
|
506
545
|
|
|
@@ -15,6 +15,8 @@ import {
|
|
|
15
15
|
normalizeModelForEngine,
|
|
16
16
|
} from "../../agent/engine/index.js";
|
|
17
17
|
import type { ActionTool } from "../../agent/types.js";
|
|
18
|
+
import { resolveHostedDefaultModelExperiment } from "../../observability/hosted-model-experiment.js";
|
|
19
|
+
import { getRequestUserEmail } from "../../server/request-context.js";
|
|
18
20
|
import { getSetting } from "../../settings/index.js";
|
|
19
21
|
|
|
20
22
|
export const tool: ActionTool = {
|
|
@@ -82,13 +84,23 @@ export async function run(args: Record<string, string> = {}): Promise<string> {
|
|
|
82
84
|
? current?.model
|
|
83
85
|
: undefined;
|
|
84
86
|
const currentEngineName = currentEntry?.name ?? "anthropic";
|
|
85
|
-
|
|
87
|
+
let currentModel =
|
|
86
88
|
currentEntry && !envUnavailable
|
|
87
89
|
? normalizeModelForEngine(
|
|
88
90
|
currentEntry,
|
|
89
91
|
currentModelCandidate ?? currentEntry.defaultModel,
|
|
90
92
|
)
|
|
91
93
|
: (currentModelCandidate ?? DEFAULT_MODEL);
|
|
94
|
+
const hostedExperiment =
|
|
95
|
+
currentEntry && !currentModelCandidate
|
|
96
|
+
? resolveHostedDefaultModelExperiment({
|
|
97
|
+
userId: getRequestUserEmail(),
|
|
98
|
+
engineName: currentEntry.name,
|
|
99
|
+
isDefaultModelSelection: true,
|
|
100
|
+
supportedModels: currentEntry.supportedModels,
|
|
101
|
+
})
|
|
102
|
+
: null;
|
|
103
|
+
if (hostedExperiment) currentModel = hostedExperiment.model;
|
|
92
104
|
|
|
93
105
|
const result = {
|
|
94
106
|
engines: engines.map((e) => ({
|
|
@@ -107,6 +119,12 @@ export async function run(args: Record<string, string> = {}): Promise<string> {
|
|
|
107
119
|
: {
|
|
108
120
|
engine: currentEngineName,
|
|
109
121
|
model: currentModel,
|
|
122
|
+
...(hostedExperiment
|
|
123
|
+
? {
|
|
124
|
+
modelSelectionSource: "experiment",
|
|
125
|
+
experimentAssignment: hostedExperiment.assignment,
|
|
126
|
+
}
|
|
127
|
+
: {}),
|
|
110
128
|
},
|
|
111
129
|
};
|
|
112
130
|
|
|
@@ -321,7 +321,14 @@ export async function run(
|
|
|
321
321
|
orgDomain: callerOrgDomain,
|
|
322
322
|
orgSecret: callerOrgSecret,
|
|
323
323
|
onUpdate: onRemotePollUpdate,
|
|
324
|
-
...(callTimeoutMs
|
|
324
|
+
...(callTimeoutMs
|
|
325
|
+
? {
|
|
326
|
+
timeoutMs: callTimeoutMs,
|
|
327
|
+
// Integration callers must keep the timeout task id so the
|
|
328
|
+
// catch below can enqueue durable continuation polling.
|
|
329
|
+
returnRecoverableArtifactsOnTimeout: false,
|
|
330
|
+
}
|
|
331
|
+
: {}),
|
|
325
332
|
});
|
|
326
333
|
responseText =
|
|
327
334
|
formatDownstreamLlmCredentialFailure(agent.name, responseText) ??
|
|
@@ -348,8 +355,23 @@ export async function run(
|
|
|
348
355
|
`The ${agent.name} agent accepted this delegated subtask and will post its own final result to the originating integration thread automatically. ` +
|
|
349
356
|
`Do not call ${agent.name} again for this same subtask. Continue any other requested work, then answer with the completed results you have; if needed, mention that ${agent.name} is posting its result separately.`;
|
|
350
357
|
} else {
|
|
351
|
-
|
|
352
|
-
|
|
358
|
+
// The normal integration path must preserve the timeout task id so
|
|
359
|
+
// it can enqueue a durable continuation. If that enqueue fails,
|
|
360
|
+
// do not hide receiver-verified artifacts that were already
|
|
361
|
+
// returned with the last poll; this mirrors callAgent's default
|
|
362
|
+
// timeout behavior without treating arbitrary remote status text
|
|
363
|
+
// as a completed response.
|
|
364
|
+
const recoverableArtifactText =
|
|
365
|
+
extractRecoverableTimeoutArtifactText(pollErr);
|
|
366
|
+
if (recoverableArtifactText) {
|
|
367
|
+
responseText = expandRelativeUrls(
|
|
368
|
+
recoverableArtifactText,
|
|
369
|
+
agent.url,
|
|
370
|
+
);
|
|
371
|
+
} else {
|
|
372
|
+
const reason = pollErr?.message ?? "unknown error";
|
|
373
|
+
responseText = `The ${agent.name} agent is taking longer than expected and didn't reply in time. (${reason})`;
|
|
374
|
+
}
|
|
353
375
|
}
|
|
354
376
|
} else {
|
|
355
377
|
const reason = pollErr?.message ?? "unknown error";
|
|
@@ -490,6 +512,34 @@ function getA2ATaskTimeoutTaskId(err: unknown): string | null {
|
|
|
490
512
|
return match?.[1] ?? null;
|
|
491
513
|
}
|
|
492
514
|
|
|
515
|
+
/**
|
|
516
|
+
* Mirrors the A2A client's default timeout recovery for the exceptional case
|
|
517
|
+
* where an integration cannot enqueue a durable continuation. Only an
|
|
518
|
+
* explicitly receiver-marked task message is safe to surface as a completed
|
|
519
|
+
* partial result; ordinary working-state text remains a timeout failure.
|
|
520
|
+
*/
|
|
521
|
+
function extractRecoverableTimeoutArtifactText(err: unknown): string {
|
|
522
|
+
const candidate = err as
|
|
523
|
+
| { lastTask?: Task | unknown; name?: unknown }
|
|
524
|
+
| null
|
|
525
|
+
| undefined;
|
|
526
|
+
const lastTask =
|
|
527
|
+
err instanceof A2ATaskTimeoutError
|
|
528
|
+
? err.lastTask
|
|
529
|
+
: candidate?.name === "A2ATaskTimeoutError"
|
|
530
|
+
? (candidate.lastTask as Task | undefined)
|
|
531
|
+
: undefined;
|
|
532
|
+
const message = lastTask?.status?.message;
|
|
533
|
+
if (!message?.metadata?.agentNativeRecoverableArtifacts) return "";
|
|
534
|
+
|
|
535
|
+
return message.parts
|
|
536
|
+
.filter(
|
|
537
|
+
(part): part is { type: "text"; text: string } => part.type === "text",
|
|
538
|
+
)
|
|
539
|
+
.map((part) => part.text)
|
|
540
|
+
.join("\n");
|
|
541
|
+
}
|
|
542
|
+
|
|
493
543
|
async function formatExistingIntegrationContinuationIfRetry(
|
|
494
544
|
agent: {
|
|
495
545
|
name: string;
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Search or list past agent chat threads.
|
|
5
5
|
*
|
|
6
6
|
* Usage:
|
|
7
|
-
* pnpm action search-chats [--query "search term"] [--limit N] [--format json]
|
|
7
|
+
* pnpm action search-chats [--query "search term"] [--limit N] [--format json] [--includeArchived]
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import { searchThreads, listThreads } from "../../chat-threads/store.js";
|
|
@@ -40,15 +40,17 @@ export default async function searchChats(args: string[]): Promise<void> {
|
|
|
40
40
|
console.log(`Usage: pnpm action search-chats [options]
|
|
41
41
|
|
|
42
42
|
Options:
|
|
43
|
-
--query <text>
|
|
44
|
-
--limit N
|
|
45
|
-
--format json
|
|
46
|
-
--
|
|
43
|
+
--query <text> Search chats by title, preview, or content
|
|
44
|
+
--limit N Max results (default: 20)
|
|
45
|
+
--format json Output as JSON
|
|
46
|
+
--includeArchived Also include archived chats (excluded by default)
|
|
47
|
+
--help Show this help message
|
|
47
48
|
|
|
48
49
|
Examples:
|
|
49
50
|
pnpm action search-chats --query "email setup"
|
|
50
51
|
pnpm action search-chats --limit 5
|
|
51
|
-
pnpm action search-chats --format json
|
|
52
|
+
pnpm action search-chats --format json
|
|
53
|
+
pnpm action search-chats --includeArchived`);
|
|
52
54
|
return;
|
|
53
55
|
}
|
|
54
56
|
|
|
@@ -56,10 +58,11 @@ Examples:
|
|
|
56
58
|
const limit = parsed.limit ? parseInt(parsed.limit, 10) : 20;
|
|
57
59
|
if (isNaN(limit) || limit < 1) fail("--limit must be a positive integer");
|
|
58
60
|
|
|
61
|
+
const includeArchived = parsed.includeArchived === "true";
|
|
59
62
|
const query = parsed.query;
|
|
60
63
|
const threads = query
|
|
61
|
-
? await searchThreads(owner, query, limit)
|
|
62
|
-
: await listThreads(owner, limit, 0);
|
|
64
|
+
? await searchThreads(owner, query, limit, { includeArchived })
|
|
65
|
+
: await listThreads(owner, { limit, offset: 0, includeArchived });
|
|
63
66
|
|
|
64
67
|
if (parsed.format === "json") {
|
|
65
68
|
console.log(
|
|
@@ -22,7 +22,7 @@ export function registerFrameworkSecrets(): void {
|
|
|
22
22
|
key: "OPENAI_API_KEY",
|
|
23
23
|
label: "OpenAI API key",
|
|
24
24
|
description:
|
|
25
|
-
"
|
|
25
|
+
"Optional fallback for realtime voice when Builder is not connected, and for OpenAI transcription.",
|
|
26
26
|
docsUrl: "https://platform.openai.com/api-keys",
|
|
27
27
|
scope: "user",
|
|
28
28
|
kind: "api-key",
|
|
@@ -54,11 +54,16 @@ import {
|
|
|
54
54
|
listAgentEngines,
|
|
55
55
|
registerBuiltinEngines,
|
|
56
56
|
} from "../agent/engine/index.js";
|
|
57
|
-
import type {
|
|
57
|
+
import type {
|
|
58
|
+
AgentEngine,
|
|
59
|
+
EngineMessage,
|
|
60
|
+
EngineTool,
|
|
61
|
+
} from "../agent/engine/types.js";
|
|
58
62
|
import {
|
|
59
63
|
createProductionAgentHandler,
|
|
60
64
|
actionsToEngineTools,
|
|
61
65
|
executeAgentToolCall,
|
|
66
|
+
filterInitialEngineTools,
|
|
62
67
|
getActiveRunForThreadAsync,
|
|
63
68
|
abortRunDurably,
|
|
64
69
|
subscribeToRun,
|
|
@@ -1903,6 +1908,11 @@ async function createChatScriptEntries(): Promise<Record<string, ActionEntry>> {
|
|
|
1903
1908
|
description: "Output format",
|
|
1904
1909
|
enum: ["json", "text"],
|
|
1905
1910
|
},
|
|
1911
|
+
includeArchived: {
|
|
1912
|
+
type: "boolean",
|
|
1913
|
+
description:
|
|
1914
|
+
"Also include archived chats in the results. Archived chats are excluded by default.",
|
|
1915
|
+
},
|
|
1906
1916
|
},
|
|
1907
1917
|
},
|
|
1908
1918
|
},
|
|
@@ -1953,6 +1963,11 @@ async function createChatScriptEntries(): Promise<Record<string, ActionEntry>> {
|
|
|
1953
1963
|
description: "(search) Output format",
|
|
1954
1964
|
enum: ["json", "text"],
|
|
1955
1965
|
},
|
|
1966
|
+
includeArchived: {
|
|
1967
|
+
type: "boolean",
|
|
1968
|
+
description:
|
|
1969
|
+
"(search) Also include archived chats in the results. Archived chats are excluded by default, matching the 'archive' action's effect on the chat list.",
|
|
1970
|
+
},
|
|
1956
1971
|
id: {
|
|
1957
1972
|
type: "string",
|
|
1958
1973
|
description:
|
|
@@ -2940,6 +2955,22 @@ export function runA2AAgentLoop(
|
|
|
2940
2955
|
);
|
|
2941
2956
|
}
|
|
2942
2957
|
|
|
2958
|
+
/**
|
|
2959
|
+
* Keep delegated A2A turns on the same compact initial tool surface as
|
|
2960
|
+
* interactive chat. `tool-search` remains in the initial set, while the
|
|
2961
|
+
* complete registry is supplied separately so the run loop can load a matched
|
|
2962
|
+
* schema after a tool-search result.
|
|
2963
|
+
*/
|
|
2964
|
+
export function createA2AEngineToolSurface(
|
|
2965
|
+
availableTools: EngineTool[],
|
|
2966
|
+
initialToolNames?: string[],
|
|
2967
|
+
): { tools: EngineTool[]; availableTools: EngineTool[] } {
|
|
2968
|
+
return {
|
|
2969
|
+
tools: filterInitialEngineTools(availableTools, initialToolNames),
|
|
2970
|
+
availableTools,
|
|
2971
|
+
};
|
|
2972
|
+
}
|
|
2973
|
+
|
|
2943
2974
|
/**
|
|
2944
2975
|
* Verbose framework sections returned by the `get-framework-context` tool.
|
|
2945
2976
|
* Keyed by topic so the agent can request specific sections.
|
|
@@ -2971,9 +3002,9 @@ Use for charts, visualizations, previews. Don't use for simple text/tables or ex
|
|
|
2971
3002
|
"chat-history": `### Chat History
|
|
2972
3003
|
|
|
2973
3004
|
You can search and restore previous chat conversations using \`chat-history\`:
|
|
2974
|
-
- \`chat-history\` (action: "search") — Search or list past chat threads by keyword
|
|
3005
|
+
- \`chat-history\` (action: "search") — Search or list past chat threads by keyword. Archived threads are excluded by default; pass \`includeArchived: true\` to also see them.
|
|
2975
3006
|
- \`chat-history\` (action: "open") — Open a chat thread in the UI as a new tab and focus it
|
|
2976
|
-
- \`chat-history\` (actions: "rename", "pin", "unpin", "archive") — Organize a known chat thread by ID
|
|
3007
|
+
- \`chat-history\` (actions: "rename", "pin", "unpin", "archive") — Organize a known chat thread by ID. Archiving a thread hides it from the default chat list and search.
|
|
2977
3008
|
|
|
2978
3009
|
When the user asks to find a previous conversation, use \`chat-history\` with action "search" first to find matching threads, then action "open" to restore the one they want.`,
|
|
2979
3010
|
|
|
@@ -5077,7 +5108,10 @@ export function createAgentChatPlugin(
|
|
|
5077
5108
|
},
|
|
5078
5109
|
);
|
|
5079
5110
|
|
|
5080
|
-
const
|
|
5111
|
+
const a2aToolSurface = createA2AEngineToolSurface(
|
|
5112
|
+
actionsToEngineTools(a2aActions),
|
|
5113
|
+
options?.initialToolNames,
|
|
5114
|
+
);
|
|
5081
5115
|
|
|
5082
5116
|
// Precise current time rides the user message (not the cached
|
|
5083
5117
|
// system-prompt prefix) — same pattern as the interactive handler.
|
|
@@ -5098,7 +5132,7 @@ export function createAgentChatPlugin(
|
|
|
5098
5132
|
const controller = new AbortController();
|
|
5099
5133
|
|
|
5100
5134
|
console.log(
|
|
5101
|
-
`[A2A] Starting agent loop: ${
|
|
5135
|
+
`[A2A] Starting agent loop: ${a2aToolSurface.tools.length}/${a2aToolSurface.availableTools.length} initial tools, prompt ${systemPrompt.length} chars`,
|
|
5102
5136
|
);
|
|
5103
5137
|
|
|
5104
5138
|
await runA2AAgentLoop(
|
|
@@ -5106,7 +5140,8 @@ export function createAgentChatPlugin(
|
|
|
5106
5140
|
engine: a2aEngine,
|
|
5107
5141
|
model,
|
|
5108
5142
|
systemPrompt,
|
|
5109
|
-
tools:
|
|
5143
|
+
tools: a2aToolSurface.tools,
|
|
5144
|
+
availableTools: a2aToolSurface.availableTools,
|
|
5110
5145
|
messages: a2aMessages,
|
|
5111
5146
|
actions: a2aActions,
|
|
5112
5147
|
send: (event) => {
|
|
@@ -1627,7 +1627,7 @@ function loginHtmlResponse(loginHtml: string, event: H3Event): Response {
|
|
|
1627
1627
|
headers: {
|
|
1628
1628
|
"Content-Type": "text/html; charset=utf-8",
|
|
1629
1629
|
// The sign-in document is part of the public server shell. Keep it on the
|
|
1630
|
-
// same
|
|
1630
|
+
// same long-fresh/long-SWR CDN policy as React Router SSR so hosted
|
|
1631
1631
|
// template roots do not invoke origin just to render anonymous login UI.
|
|
1632
1632
|
// The login HTML is env-INDEPENDENT (a Google-only app always renders a
|
|
1633
1633
|
// working button), so a cached copy is never "wrong" — never downgrade
|
|
@@ -298,6 +298,7 @@ const BUILDER_WAITLIST_USE_CASES = new Set([
|
|
|
298
298
|
BUILDER_WAITLIST_DEFAULT_USE_CASE,
|
|
299
299
|
"design_publish_app",
|
|
300
300
|
"docs_build_online_waitlist",
|
|
301
|
+
"docs_edit_online_waitlist",
|
|
301
302
|
]);
|
|
302
303
|
const BUILDER_WAITLIST_FORM_TIMEOUT_MS = 8000;
|
|
303
304
|
const BUILDER_WAITLIST_TEXT_LIMIT = 4000;
|
|
@@ -320,6 +321,7 @@ export interface BuilderWaitlistBody {
|
|
|
320
321
|
appUrl?: unknown;
|
|
321
322
|
pageUrl?: unknown;
|
|
322
323
|
source?: unknown;
|
|
324
|
+
template?: unknown;
|
|
323
325
|
useCase?: unknown;
|
|
324
326
|
}
|
|
325
327
|
|
|
@@ -352,6 +354,13 @@ function normalizeBuilderWaitlistUseCase(value: unknown): string {
|
|
|
352
354
|
: BUILDER_WAITLIST_DEFAULT_USE_CASE;
|
|
353
355
|
}
|
|
354
356
|
|
|
357
|
+
function normalizeBuilderWaitlistTemplate(value: unknown): string | undefined {
|
|
358
|
+
const template = cleanBuilderWaitlistText(value, 100);
|
|
359
|
+
return template && /^[a-z0-9][a-z0-9-]{0,99}$/.test(template)
|
|
360
|
+
? template
|
|
361
|
+
: undefined;
|
|
362
|
+
}
|
|
363
|
+
|
|
355
364
|
function isValidWaitlistEmail(email: string): boolean {
|
|
356
365
|
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
|
|
357
366
|
}
|
|
@@ -506,6 +515,7 @@ export function buildBuilderWaitlistFormPayload(
|
|
|
506
515
|
getOrigin(event);
|
|
507
516
|
const source =
|
|
508
517
|
cleanBuilderWaitlistText(body.source, 100) ?? BUILDER_WAITLIST_FORM_SOURCE;
|
|
518
|
+
const template = normalizeBuilderWaitlistTemplate(body.template);
|
|
509
519
|
const useCase = normalizeBuilderWaitlistUseCase(body.useCase);
|
|
510
520
|
|
|
511
521
|
return {
|
|
@@ -515,6 +525,7 @@ export function buildBuilderWaitlistFormPayload(
|
|
|
515
525
|
appUrl,
|
|
516
526
|
prompt: cleanBuilderWaitlistText(body.prompt),
|
|
517
527
|
source,
|
|
528
|
+
template,
|
|
518
529
|
useCase,
|
|
519
530
|
},
|
|
520
531
|
_hp: "",
|
|
@@ -522,6 +533,7 @@ export function buildBuilderWaitlistFormPayload(
|
|
|
522
533
|
submitterEmail: sessionEmail,
|
|
523
534
|
pageUrl: appUrl,
|
|
524
535
|
source,
|
|
536
|
+
template,
|
|
525
537
|
useCase,
|
|
526
538
|
},
|
|
527
539
|
};
|
|
@@ -2021,6 +2033,7 @@ export function createCoreRoutesPlugin(
|
|
|
2021
2033
|
body,
|
|
2022
2034
|
);
|
|
2023
2035
|
const waitlistSource = waitlistPayload.data.source;
|
|
2036
|
+
const waitlistTemplate = waitlistPayload.data.template;
|
|
2024
2037
|
const waitlistUseCase = waitlistPayload.data.useCase;
|
|
2025
2038
|
let formSubmission: { submitted: boolean; formId?: string };
|
|
2026
2039
|
try {
|
|
@@ -2039,6 +2052,7 @@ export function createCoreRoutesPlugin(
|
|
|
2039
2052
|
err instanceof Error ? err.message : "unknown_waitlist_error",
|
|
2040
2053
|
source: waitlistSource,
|
|
2041
2054
|
stage: "waitlist",
|
|
2055
|
+
template: waitlistTemplate ?? null,
|
|
2042
2056
|
useCase: waitlistUseCase,
|
|
2043
2057
|
},
|
|
2044
2058
|
);
|
|
@@ -2057,6 +2071,7 @@ export function createCoreRoutesPlugin(
|
|
|
2057
2071
|
formSubmitted: formSubmission.submitted,
|
|
2058
2072
|
source: waitlistSource,
|
|
2059
2073
|
stage: "waitlist",
|
|
2074
|
+
template: waitlistTemplate ?? null,
|
|
2060
2075
|
useCase: waitlistUseCase,
|
|
2061
2076
|
},
|
|
2062
2077
|
);
|
|
@@ -78,6 +78,8 @@ const APP_PROVIDED_DEPLOY_CREDENTIAL_KEYS = new Set([
|
|
|
78
78
|
"OPENAI_API_KEY",
|
|
79
79
|
"OPENAI_BASE_URL",
|
|
80
80
|
"OPENROUTER_API_KEY",
|
|
81
|
+
"GOOGLE_CLIENT_ID",
|
|
82
|
+
"GOOGLE_CLIENT_SECRET",
|
|
81
83
|
"GOOGLE_GENERATIVE_AI_API_KEY",
|
|
82
84
|
"GROQ_API_KEY",
|
|
83
85
|
"MISTRAL_API_KEY",
|
|
@@ -93,9 +95,11 @@ function isAppProvidedDeployCredentialKey(key: string | undefined): boolean {
|
|
|
93
95
|
* single-tenant contexts. In hosted production with a shared database, every
|
|
94
96
|
* signed-in user needs their own user/org/workspace credential for
|
|
95
97
|
* identity-bearing provider keys so one deploy key does not silently
|
|
96
|
-
* impersonate another tenant. App-provided
|
|
97
|
-
* they
|
|
98
|
-
* that
|
|
98
|
+
* impersonate another tenant. App-provided service credentials are different:
|
|
99
|
+
* they configure the deployed app itself rather than identifying a user. This
|
|
100
|
+
* includes LLM keys that let the app developer pay for model usage and OAuth
|
|
101
|
+
* client credentials whose per-user identity remains in scoped OAuth tokens.
|
|
102
|
+
* Key-aware callers may use those env vars.
|
|
99
103
|
*
|
|
100
104
|
* @deprecated Use `canUseDeployCredentialFallbackForRequest()` for generic
|
|
101
105
|
* provider secrets. This stricter helper remains for legacy call sites with
|