@agent-native/core 0.149.2 → 0.149.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/corpus/README.md +1 -1
- package/corpus/templates/analytics/.agents/skills/actions/SKILL.md +54 -488
- package/corpus/templates/analytics/.agents/skills/actions/references/action-fields.md +136 -0
- package/corpus/templates/analytics/.agents/skills/actions/references/examples.md +94 -0
- package/corpus/templates/analytics/.agents/skills/actions/references/provider-apis.md +95 -0
- package/corpus/templates/analytics/.agents/skills/create-skill/SKILL.md +9 -35
- package/corpus/templates/analytics/.agents/skills/creative-context/SKILL.md +4 -2
- package/corpus/templates/analytics/.agents/skills/frontend-design/SKILL.md +4 -5
- package/corpus/templates/analytics/.agents/skills/turn-into-app/SKILL.md +18 -31
- package/corpus/templates/analytics/AGENTS.md +25 -32
- package/corpus/templates/analytics/app/global.css +1 -1
- package/corpus/templates/analytics/changelog/2026-08-11-full-page-chat-composers-stay-at-a-focused-750px-width.md +6 -0
- package/corpus/templates/assets/.agents/skills/actions/SKILL.md +54 -488
- package/corpus/templates/assets/.agents/skills/actions/references/action-fields.md +136 -0
- package/corpus/templates/assets/.agents/skills/actions/references/examples.md +94 -0
- package/corpus/templates/assets/.agents/skills/actions/references/provider-apis.md +95 -0
- package/corpus/templates/assets/.agents/skills/create-skill/SKILL.md +9 -35
- package/corpus/templates/assets/.agents/skills/creative-context/SKILL.md +4 -2
- package/corpus/templates/assets/.agents/skills/frontend-design/SKILL.md +4 -5
- package/corpus/templates/assets/.agents/skills/turn-into-app/SKILL.md +18 -31
- package/corpus/templates/assets/AGENTS.md +6 -9
- package/corpus/templates/assets/app/global.css +1 -1
- package/corpus/templates/assets/changelog/2026-08-11-full-page-chat-composers-stay-at-a-focused-750px-width.md +6 -0
- package/corpus/templates/brain/.agents/skills/actions/SKILL.md +54 -488
- package/corpus/templates/brain/.agents/skills/actions/references/action-fields.md +136 -0
- package/corpus/templates/brain/.agents/skills/actions/references/examples.md +94 -0
- package/corpus/templates/brain/.agents/skills/actions/references/provider-apis.md +95 -0
- package/corpus/templates/brain/.agents/skills/create-skill/SKILL.md +9 -35
- package/corpus/templates/brain/.agents/skills/frontend-design/SKILL.md +4 -5
- package/corpus/templates/brain/.agents/skills/turn-into-app/SKILL.md +18 -31
- package/corpus/templates/brain/AGENTS.md +5 -12
- package/corpus/templates/brain/app/global.css +1 -1
- package/corpus/templates/brain/changelog/2026-08-11-full-page-chat-composers-stay-at-a-focused-750px-width.md +6 -0
- package/corpus/templates/calendar/.agents/skills/actions/SKILL.md +54 -488
- package/corpus/templates/calendar/.agents/skills/actions/references/action-fields.md +136 -0
- package/corpus/templates/calendar/.agents/skills/actions/references/examples.md +94 -0
- package/corpus/templates/calendar/.agents/skills/actions/references/provider-apis.md +95 -0
- package/corpus/templates/calendar/.agents/skills/create-skill/SKILL.md +9 -35
- package/corpus/templates/calendar/.agents/skills/frontend-design/SKILL.md +4 -5
- package/corpus/templates/calendar/.agents/skills/turn-into-app/SKILL.md +18 -31
- package/corpus/templates/calendar/AGENTS.md +8 -9
- package/corpus/templates/chat/.agents/skills/actions/SKILL.md +54 -488
- package/corpus/templates/chat/.agents/skills/actions/references/action-fields.md +136 -0
- package/corpus/templates/chat/.agents/skills/actions/references/examples.md +94 -0
- package/corpus/templates/chat/.agents/skills/actions/references/provider-apis.md +95 -0
- package/corpus/templates/chat/.agents/skills/create-skill/SKILL.md +9 -35
- package/corpus/templates/chat/.agents/skills/frontend-design/SKILL.md +4 -5
- package/corpus/templates/chat/.agents/skills/turn-into-app/SKILL.md +18 -31
- package/corpus/templates/chat/AGENTS.md +32 -80
- package/corpus/templates/clips/.agents/skills/actions/SKILL.md +54 -488
- package/corpus/templates/clips/.agents/skills/actions/references/action-fields.md +136 -0
- package/corpus/templates/clips/.agents/skills/actions/references/examples.md +94 -0
- package/corpus/templates/clips/.agents/skills/actions/references/provider-apis.md +95 -0
- package/corpus/templates/clips/.agents/skills/create-skill/SKILL.md +9 -35
- package/corpus/templates/clips/.agents/skills/frontend-design/SKILL.md +4 -5
- package/corpus/templates/clips/.agents/skills/turn-into-app/SKILL.md +18 -31
- package/corpus/templates/clips/AGENTS.md +25 -31
- package/corpus/templates/content/.agents/skills/actions/SKILL.md +54 -488
- package/corpus/templates/content/.agents/skills/actions/references/action-fields.md +136 -0
- package/corpus/templates/content/.agents/skills/actions/references/examples.md +94 -0
- package/corpus/templates/content/.agents/skills/actions/references/provider-apis.md +95 -0
- package/corpus/templates/content/.agents/skills/create-skill/SKILL.md +9 -35
- package/corpus/templates/content/.agents/skills/creative-context/SKILL.md +4 -2
- package/corpus/templates/content/.agents/skills/frontend-design/SKILL.md +4 -5
- package/corpus/templates/content/.agents/skills/turn-into-app/SKILL.md +18 -31
- package/corpus/templates/content/AGENTS.md +5 -9
- package/corpus/templates/crm/.agents/skills/turn-into-app/SKILL.md +18 -31
- package/corpus/templates/crm/AGENTS.md +7 -11
- package/corpus/templates/crm/app/global.css +1 -1
- package/corpus/templates/crm/changelog/2026-08-11-full-page-chat-composers-stay-at-a-focused-750px-width.md +6 -0
- package/corpus/templates/design/.agents/skills/actions/SKILL.md +54 -488
- package/corpus/templates/design/.agents/skills/actions/references/action-fields.md +136 -0
- package/corpus/templates/design/.agents/skills/actions/references/examples.md +94 -0
- package/corpus/templates/design/.agents/skills/actions/references/provider-apis.md +95 -0
- package/corpus/templates/design/.agents/skills/create-skill/SKILL.md +9 -35
- package/corpus/templates/design/.agents/skills/creative-context/SKILL.md +4 -2
- package/corpus/templates/design/.agents/skills/frontend-design/SKILL.md +4 -5
- package/corpus/templates/design/.agents/skills/turn-into-app/SKILL.md +18 -31
- package/corpus/templates/design/.generated/bridge/editor-chrome.generated.ts +70 -3
- package/corpus/templates/design/AGENTS.md +13 -21
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +12 -0
- package/corpus/templates/design/app/components/design/LayersPanel.tsx +19 -2
- package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +115 -7
- package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +82 -7
- package/corpus/templates/design/app/components/design/design-trace.ts +120 -0
- package/corpus/templates/design/app/components/design/dnd-debug.ts +2 -1
- package/corpus/templates/design/app/components/design/edit-panel/position-layout-properties.tsx +40 -26
- package/corpus/templates/design/app/components/design/multi-screen/board-surface-html.ts +4 -1
- package/corpus/templates/design/app/components/design/multi-screen/frame-geometry.ts +12 -3
- package/corpus/templates/design/app/components/design/multi-screen/screen-content-cache.ts +4 -0
- package/corpus/templates/design/app/components/design/multi-screen/types.ts +7 -0
- package/corpus/templates/design/app/components/editor/PromptDialog.tsx +3 -2
- package/corpus/templates/design/app/components/layout/Sidebar.tsx +2 -2
- package/corpus/templates/design/app/hooks/useDesignHotkeys.ts +3 -0
- package/corpus/templates/design/app/i18n-data.ts +1 -0
- package/corpus/templates/design/app/pages/DesignSystemSetup.tsx +5 -5
- package/corpus/templates/design/app/pages/DesignSystems.tsx +3 -2
- package/corpus/templates/design/app/pages/design-editor/canvas-primitive-insert.ts +100 -13
- package/corpus/templates/design/app/pages/design-editor/cross-screen-text-color.ts +1 -1
- package/corpus/templates/design/app/pages/design-editor/data-operations.ts +14 -0
- package/corpus/templates/design/changelog/2026-08-10-marquee-selecting-layers-far-down-a-tall-screen-now-selects-.md +6 -0
- package/corpus/templates/design/changelog/2026-08-10-the-frame-tool-draws-a-plain-frame-by-default-with-screen-av.md +6 -0
- package/corpus/templates/design/e2e/global-setup.ts +27 -32
- package/corpus/templates/design/playwright.config.ts +3 -5
- package/corpus/templates/design/shared/breakpoint-media.ts +9 -2
- package/corpus/templates/dispatch/.agents/skills/actions/SKILL.md +54 -488
- package/corpus/templates/dispatch/.agents/skills/actions/references/action-fields.md +136 -0
- package/corpus/templates/dispatch/.agents/skills/actions/references/examples.md +94 -0
- package/corpus/templates/dispatch/.agents/skills/actions/references/provider-apis.md +95 -0
- package/corpus/templates/dispatch/.agents/skills/create-skill/SKILL.md +9 -35
- package/corpus/templates/dispatch/.agents/skills/frontend-design/SKILL.md +4 -5
- package/corpus/templates/dispatch/.agents/skills/turn-into-app/SKILL.md +18 -31
- package/corpus/templates/dispatch/AGENTS.md +9 -16
- package/corpus/templates/factory/.agents/skills/actions/SKILL.md +54 -488
- package/corpus/templates/factory/.agents/skills/actions/references/action-fields.md +136 -0
- package/corpus/templates/factory/.agents/skills/actions/references/examples.md +94 -0
- package/corpus/templates/factory/.agents/skills/actions/references/provider-apis.md +95 -0
- package/corpus/templates/factory/.agents/skills/create-skill/SKILL.md +9 -35
- package/corpus/templates/factory/.agents/skills/frontend-design/SKILL.md +4 -5
- package/corpus/templates/factory/.agents/skills/turn-into-app/SKILL.md +18 -31
- package/corpus/templates/factory/AGENTS.md +10 -24
- package/corpus/templates/forms/.agents/skills/actions/SKILL.md +54 -488
- package/corpus/templates/forms/.agents/skills/actions/references/action-fields.md +136 -0
- package/corpus/templates/forms/.agents/skills/actions/references/examples.md +94 -0
- package/corpus/templates/forms/.agents/skills/actions/references/provider-apis.md +95 -0
- package/corpus/templates/forms/.agents/skills/create-skill/SKILL.md +9 -35
- package/corpus/templates/forms/.agents/skills/frontend-design/SKILL.md +4 -5
- package/corpus/templates/forms/.agents/skills/turn-into-app/SKILL.md +18 -31
- package/corpus/templates/forms/AGENTS.md +11 -17
- package/corpus/templates/forms/app/global.css +1 -0
- package/corpus/templates/forms/changelog/2026-08-11-full-page-chat-composers-stay-at-a-focused-750px-width.md +6 -0
- package/corpus/templates/macros/.agents/skills/frontend-design/SKILL.md +4 -5
- package/corpus/templates/macros/.agents/skills/turn-into-app/SKILL.md +18 -31
- package/corpus/templates/macros/AGENTS.md +8 -8
- package/corpus/templates/mail/.agents/skills/actions/SKILL.md +54 -488
- package/corpus/templates/mail/.agents/skills/actions/references/action-fields.md +136 -0
- package/corpus/templates/mail/.agents/skills/actions/references/examples.md +94 -0
- package/corpus/templates/mail/.agents/skills/actions/references/provider-apis.md +95 -0
- package/corpus/templates/mail/.agents/skills/create-skill/SKILL.md +9 -35
- package/corpus/templates/mail/.agents/skills/frontend-design/SKILL.md +4 -5
- package/corpus/templates/mail/.agents/skills/turn-into-app/SKILL.md +18 -31
- package/corpus/templates/mail/AGENTS.md +5 -6
- package/corpus/templates/plan/.agents/skills/actions/SKILL.md +54 -488
- package/corpus/templates/plan/.agents/skills/actions/references/action-fields.md +136 -0
- package/corpus/templates/plan/.agents/skills/actions/references/examples.md +94 -0
- package/corpus/templates/plan/.agents/skills/actions/references/provider-apis.md +95 -0
- package/corpus/templates/plan/.agents/skills/create-skill/SKILL.md +9 -35
- package/corpus/templates/plan/.agents/skills/frontend-design/SKILL.md +4 -5
- package/corpus/templates/plan/.agents/skills/turn-into-app/SKILL.md +18 -31
- package/corpus/templates/plan/AGENTS.md +5 -14
- package/corpus/templates/plan/changelog/2026-08-11-plan-no-longer-reloads-when-runtime-state-changes.md +6 -0
- package/corpus/templates/plan/vite.config.ts +5 -0
- package/corpus/templates/slides/.agents/skills/actions/SKILL.md +54 -488
- package/corpus/templates/slides/.agents/skills/actions/references/action-fields.md +136 -0
- package/corpus/templates/slides/.agents/skills/actions/references/examples.md +94 -0
- package/corpus/templates/slides/.agents/skills/actions/references/provider-apis.md +95 -0
- package/corpus/templates/slides/.agents/skills/create-deck/SKILL.md +2 -2
- package/corpus/templates/slides/.agents/skills/create-skill/SKILL.md +9 -35
- package/corpus/templates/slides/.agents/skills/creative-context/SKILL.md +6 -3
- package/corpus/templates/slides/.agents/skills/deck-management/SKILL.md +6 -1
- package/corpus/templates/slides/.agents/skills/frontend-design/SKILL.md +4 -5
- package/corpus/templates/slides/.agents/skills/image-generation-via-a2a/SKILL.md +3 -2
- package/corpus/templates/slides/.agents/skills/slide-editing/SKILL.md +3 -0
- package/corpus/templates/slides/.agents/skills/slide-images/SKILL.md +3 -3
- package/corpus/templates/slides/.agents/skills/turn-into-app/SKILL.md +18 -31
- package/corpus/templates/slides/AGENTS.md +22 -25
- package/corpus/templates/slides/actions/get-deck-reference-context.ts +2 -2
- package/corpus/templates/slides/actions/get-deck.ts +57 -9
- package/corpus/templates/slides/actions/import-file.ts +2 -1
- package/corpus/templates/slides/actions/patch-deck.ts +45 -2
- package/corpus/templates/slides/actions/update-slide.ts +1 -1
- package/corpus/templates/slides/app/components/comments/SlideCommentsPanel.tsx +2 -2
- package/corpus/templates/slides/app/components/deck/DeckCard.tsx +1 -23
- package/corpus/templates/slides/app/components/design-system/DesignSystemCard.tsx +2 -2
- package/corpus/templates/slides/app/components/design-system/DesignSystemSetup.tsx +6 -6
- package/corpus/templates/slides/app/components/editor/AnimationsPanel.tsx +3 -3
- package/corpus/templates/slides/app/components/editor/DeckEditorSkeleton.tsx +4 -4
- package/corpus/templates/slides/app/components/editor/EditorSidebar.tsx +1 -1
- package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +428 -180
- package/corpus/templates/slides/app/components/editor/ExportMenu.tsx +294 -266
- package/corpus/templates/slides/app/components/editor/PromptDialog.tsx +7 -5
- package/corpus/templates/slides/app/components/editor/SlideContextToolbar.tsx +1 -1
- package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +40 -12
- package/corpus/templates/slides/app/components/editor/SpeakerNotesPanel.tsx +6 -12
- package/corpus/templates/slides/app/components/editor/editor-command-model.ts +35 -0
- package/corpus/templates/slides/app/components/layout/Sidebar.tsx +8 -10
- package/corpus/templates/slides/app/context/DeckContext.tsx +2 -1
- package/corpus/templates/slides/app/global.css +76 -1
- package/corpus/templates/slides/app/i18n/en-US.ts +1 -0
- package/corpus/templates/slides/app/lib/create-deck-generation.ts +51 -23
- package/corpus/templates/slides/app/lib/slide-animation-elements.ts +68 -5
- package/corpus/templates/slides/app/pages/DeckEditor.tsx +13 -6
- package/corpus/templates/slides/app/pages/DesignSystems.tsx +2 -2
- package/corpus/templates/slides/app/pages/Index.tsx +87 -74
- package/corpus/templates/slides/app/root.tsx +43 -0
- package/corpus/templates/slides/changelog/2026-08-11-faster-slides-chat-deck-reads.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-11-slides-chat-can-read-one-slide-without-loading-the-full-deck.md +6 -0
- package/corpus/templates/slides/changelog/2026-08-11-slides-clearly-indicate-when-an-ai-agent-is-editing-alongsid.md +6 -0
- package/corpus/templates/slides/package.json +1 -0
- package/corpus/templates/slides/server/lib/validate-slide-animations.ts +163 -0
- package/corpus/templates/slides/server/plugins/agent-chat.ts +4 -3
- package/corpus/templates/slides/shared/api.ts +46 -15
- package/corpus/templates/tasks/.agents/skills/actions/SKILL.md +54 -488
- package/corpus/templates/tasks/.agents/skills/actions/references/action-fields.md +136 -0
- package/corpus/templates/tasks/.agents/skills/actions/references/examples.md +94 -0
- package/corpus/templates/tasks/.agents/skills/actions/references/provider-apis.md +95 -0
- package/corpus/templates/tasks/.agents/skills/agent-watchdog/SKILL.md +1 -0
- package/corpus/templates/tasks/.agents/skills/create-skill/SKILL.md +9 -35
- package/corpus/templates/tasks/.agents/skills/efficient-fable/SKILL.md +1 -0
- package/corpus/templates/tasks/.agents/skills/efficient-frontier/SKILL.md +1 -0
- package/corpus/templates/tasks/.agents/skills/frontend-design/SKILL.md +4 -5
- package/corpus/templates/tasks/.agents/skills/plan-arbiter/SKILL.md +1 -0
- package/corpus/templates/tasks/.agents/skills/plow-ahead/SKILL.md +1 -0
- package/corpus/templates/tasks/.agents/skills/quick-recap/SKILL.md +1 -0
- package/corpus/templates/tasks/.agents/skills/read-the-damn-docs/SKILL.md +1 -0
- package/corpus/templates/tasks/.agents/skills/stay-within-limits/SKILL.md +1 -0
- package/corpus/templates/tasks/.agents/skills/turn-into-app/SKILL.md +18 -31
- package/corpus/templates/tasks/AGENTS.md +5 -20
- package/dist/agent/production-agent.js +376 -345
- package/dist/agent/run-manager.js +156 -14
- package/dist/agent/run-store.d.ts +11 -10
- package/dist/agent/run-store.js +17 -13
- package/dist/client/AssistantChat.d.ts +6 -2
- package/dist/client/AssistantChat.js +216 -131
- package/dist/client/active-run-state.d.ts +9 -1
- package/dist/client/active-run-state.js +34 -3
- package/dist/client/agent-chat-adapter.d.ts +8 -0
- package/dist/client/agent-chat-adapter.js +114 -28
- package/dist/client/chat/message-components.d.ts +7 -1
- package/dist/client/chat/message-components.js +32 -5
- package/dist/client/chat/run-recovery.d.ts +1 -0
- package/dist/client/chat/run-recovery.js +8 -0
- package/dist/client/chat/tool-call-display.d.ts +2 -0
- package/dist/client/chat/tool-call-display.js +2 -0
- package/dist/client/chat-first/apps-rail.js +1 -1
- package/dist/client/chat-first/chat-history.d.ts +1 -1
- package/dist/client/chat-first/chat-history.js +5 -2
- package/dist/client/sse-event-processor.d.ts +4 -2
- package/dist/client/sse-event-processor.js +36 -6
- package/dist/client/use-run-stuck-detection.d.ts +2 -0
- package/dist/client/use-run-stuck-detection.js +85 -9
- package/dist/collab/routes.d.ts +1 -1
- package/dist/deploy/build.d.ts +4 -0
- package/dist/deploy/build.js +5 -0
- package/dist/deploy/workspace-deploy.js +5 -0
- package/dist/integrations/adapters/slack.d.ts +0 -4
- package/dist/integrations/adapters/slack.js +6 -30
- package/dist/integrations/catalog.js +1 -1
- package/dist/integrations/pending-tasks-store.d.ts +0 -8
- package/dist/integrations/pending-tasks-store.js +0 -21
- package/dist/integrations/slack-manifest.d.ts +2 -2
- package/dist/integrations/slack-manifest.js +0 -3
- package/dist/notifications/routes.d.ts +3 -3
- package/dist/observability/routes.d.ts +3 -3
- package/dist/provider-api/actions/custom-provider-registration.d.ts +4 -4
- package/dist/provider-api/actions/provider-api.d.ts +8 -8
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/scripts/docs/source-search.js +2 -2
- package/dist/secrets/routes.d.ts +9 -9
- package/dist/server/agent-chat/framework-prompts.js +7 -2
- package/dist/server/agent-chat/prompt-resources.js +2 -2
- package/dist/server/agent-chat/skill-frontmatter.d.ts +31 -2
- package/dist/server/agent-chat/skill-frontmatter.js +41 -15
- package/dist/server/agent-chat-plugin.js +3 -3
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/agents-bundle.d.ts +16 -19
- package/dist/server/agents-bundle.js +19 -35
- package/dist/server/better-auth-instance.d.ts +1 -0
- package/dist/server/better-auth-instance.js +17 -2
- package/dist/server/prompts/framework-core-compact.d.ts +6 -1
- package/dist/server/prompts/framework-core-compact.js +12 -9
- package/dist/server/prompts/framework-core.d.ts +6 -1
- package/dist/server/prompts/framework-core.js +11 -9
- package/dist/server/prompts/index.d.ts +1 -1
- package/dist/server/prompts/index.js +1 -1
- package/dist/server/prompts/shared-rules.d.ts +15 -11
- package/dist/server/prompts/shared-rules.js +17 -13
- package/dist/server/realtime-token.d.ts +1 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/dist/templates/chat/.agents/skills/actions/SKILL.md +54 -488
- package/dist/templates/chat/.agents/skills/actions/references/action-fields.md +136 -0
- package/dist/templates/chat/.agents/skills/actions/references/examples.md +94 -0
- package/dist/templates/chat/.agents/skills/actions/references/provider-apis.md +95 -0
- package/dist/templates/chat/.agents/skills/create-skill/SKILL.md +9 -35
- package/dist/templates/chat/.agents/skills/frontend-design/SKILL.md +4 -5
- package/dist/templates/chat/.agents/skills/turn-into-app/SKILL.md +18 -31
- package/dist/templates/chat/AGENTS.md +32 -80
- package/dist/templates/default/.agents/skills/actions/SKILL.md +54 -488
- package/dist/templates/default/.agents/skills/actions/references/action-fields.md +136 -0
- package/dist/templates/default/.agents/skills/actions/references/examples.md +94 -0
- package/dist/templates/default/.agents/skills/actions/references/provider-apis.md +95 -0
- package/dist/templates/default/.agents/skills/create-skill/SKILL.md +9 -35
- package/dist/templates/default/.agents/skills/frontend-design/SKILL.md +4 -5
- package/dist/templates/default/.agents/skills/turn-into-app/SKILL.md +18 -31
- package/dist/templates/headless/.agents/skills/actions/SKILL.md +54 -488
- package/dist/templates/headless/.agents/skills/actions/references/action-fields.md +136 -0
- package/dist/templates/headless/.agents/skills/actions/references/examples.md +94 -0
- package/dist/templates/headless/.agents/skills/actions/references/provider-apis.md +95 -0
- package/dist/templates/headless/.agents/skills/turn-into-app/SKILL.md +18 -31
- package/dist/templates/workspace-core/.agents/skills/actions/SKILL.md +54 -488
- package/dist/templates/workspace-core/.agents/skills/actions/references/action-fields.md +136 -0
- package/dist/templates/workspace-core/.agents/skills/actions/references/examples.md +94 -0
- package/dist/templates/workspace-core/.agents/skills/actions/references/provider-apis.md +95 -0
- package/dist/templates/workspace-core/.agents/skills/adding-workspace-apps/SKILL.md +1 -0
- package/dist/templates/workspace-core/.agents/skills/agent-page/SKILL.md +1 -0
- package/dist/templates/workspace-core/.agents/skills/create-skill/SKILL.md +9 -35
- package/dist/templates/workspace-core/.agents/skills/frontend-design/SKILL.md +4 -5
- package/dist/templates/workspace-core/.agents/skills/recurring-jobs/SKILL.md +21 -29
- package/dist/templates/workspace-core/.agents/skills/turn-into-app/SKILL.md +18 -31
- package/dist/templates/workspace-core/.agents/skills/workspace-conventions/SKILL.md +7 -17
- package/dist/templates/workspace-core/.agents/skills/writing-agent-instructions/SKILL.md +3 -3
- package/dist/templates/workspace-core/AGENTS.md +7 -16
- package/docs/content/messaging.mdx +6 -7
- package/package.json +1 -1
- package/src/templates/chat/.agents/skills/actions/SKILL.md +54 -488
- package/src/templates/chat/.agents/skills/actions/references/action-fields.md +136 -0
- package/src/templates/chat/.agents/skills/actions/references/examples.md +94 -0
- package/src/templates/chat/.agents/skills/actions/references/provider-apis.md +95 -0
- package/src/templates/chat/.agents/skills/create-skill/SKILL.md +9 -35
- package/src/templates/chat/.agents/skills/frontend-design/SKILL.md +4 -5
- package/src/templates/chat/.agents/skills/turn-into-app/SKILL.md +18 -31
- package/src/templates/chat/AGENTS.md +32 -80
- package/src/templates/default/.agents/skills/actions/SKILL.md +54 -488
- package/src/templates/default/.agents/skills/actions/references/action-fields.md +136 -0
- package/src/templates/default/.agents/skills/actions/references/examples.md +94 -0
- package/src/templates/default/.agents/skills/actions/references/provider-apis.md +95 -0
- package/src/templates/default/.agents/skills/create-skill/SKILL.md +9 -35
- package/src/templates/default/.agents/skills/frontend-design/SKILL.md +4 -5
- package/src/templates/default/.agents/skills/turn-into-app/SKILL.md +18 -31
- package/src/templates/headless/.agents/skills/actions/SKILL.md +54 -488
- package/src/templates/headless/.agents/skills/actions/references/action-fields.md +136 -0
- package/src/templates/headless/.agents/skills/actions/references/examples.md +94 -0
- package/src/templates/headless/.agents/skills/actions/references/provider-apis.md +95 -0
- package/src/templates/headless/.agents/skills/turn-into-app/SKILL.md +18 -31
- package/src/templates/workspace-core/.agents/skills/actions/SKILL.md +54 -488
- package/src/templates/workspace-core/.agents/skills/actions/references/action-fields.md +136 -0
- package/src/templates/workspace-core/.agents/skills/actions/references/examples.md +94 -0
- package/src/templates/workspace-core/.agents/skills/actions/references/provider-apis.md +95 -0
- package/src/templates/workspace-core/.agents/skills/adding-workspace-apps/SKILL.md +1 -0
- package/src/templates/workspace-core/.agents/skills/agent-page/SKILL.md +1 -0
- package/src/templates/workspace-core/.agents/skills/create-skill/SKILL.md +9 -35
- package/src/templates/workspace-core/.agents/skills/frontend-design/SKILL.md +4 -5
- package/src/templates/workspace-core/.agents/skills/recurring-jobs/SKILL.md +21 -29
- package/src/templates/workspace-core/.agents/skills/turn-into-app/SKILL.md +18 -31
- package/src/templates/workspace-core/.agents/skills/workspace-conventions/SKILL.md +7 -17
- package/src/templates/workspace-core/.agents/skills/writing-agent-instructions/SKILL.md +3 -3
- package/src/templates/workspace-core/AGENTS.md +7 -16
|
@@ -13,7 +13,7 @@ import { extractMcpToolResultImages } from "../mcp-client/index.js";
|
|
|
13
13
|
import { isMcpToolAllowedForRequest } from "../mcp-client/visibility.js";
|
|
14
14
|
import { shouldInferSentimentForTurn } from "../observability/sentiment.js";
|
|
15
15
|
import { completeRun as completeProgressRun, startRun as startProgressRun, updateRunProgress, } from "../progress/registry.js";
|
|
16
|
-
import {
|
|
16
|
+
import { isRuntimeVisibleScope, parseSkillFrontmatter, } from "../server/agent-chat/skill-frontmatter.js";
|
|
17
17
|
import { canUseDeployCredentialFallbackForRequest, getProviderCredentialAuthFailure, readDeployCredentialEnv, } from "../server/credential-provider.js";
|
|
18
18
|
import { readBody } from "../server/h3-helpers.js";
|
|
19
19
|
import { getRequestRunContext, ensureRequestRunContext, getRequestContext, getRequestOrgId, getRequestUserEmail, runWithRequestContext, } from "../server/request-context.js";
|
|
@@ -1199,9 +1199,9 @@ function escapeReferenceAttribute(value) {
|
|
|
1199
1199
|
return value.replace(/&/g, "&").replace(/"/g, """);
|
|
1200
1200
|
}
|
|
1201
1201
|
function isRuntimeVisibleSkillContent(content) {
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
return scope
|
|
1202
|
+
// Route through the shared normalizer so an unrecognized `scope:` stays
|
|
1203
|
+
// invisible here too. A local `!== "dev"` check silently readmits it.
|
|
1204
|
+
return isRuntimeVisibleScope(parseSkillFrontmatter(content).scope);
|
|
1205
1205
|
}
|
|
1206
1206
|
export async function resolveSkillReferenceContent(ref) {
|
|
1207
1207
|
if (!ref.path && !ref.name)
|
|
@@ -4289,370 +4289,401 @@ export async function runAgentLoop(opts) {
|
|
|
4289
4289
|
tool: toolCall.name,
|
|
4290
4290
|
input: toolCall.input,
|
|
4291
4291
|
});
|
|
4292
|
-
|
|
4293
|
-
|
|
4294
|
-
|
|
4295
|
-
|
|
4296
|
-
|
|
4297
|
-
|
|
4298
|
-
|
|
4299
|
-
|
|
4300
|
-
|
|
4301
|
-
|
|
4302
|
-
|
|
4303
|
-
|
|
4304
|
-
|
|
4305
|
-
|
|
4306
|
-
|
|
4307
|
-
|
|
4308
|
-
|
|
4309
|
-
|
|
4310
|
-
|
|
4311
|
-
|
|
4312
|
-
|
|
4313
|
-
|
|
4314
|
-
|
|
4315
|
-
|
|
4316
|
-
|
|
4317
|
-
|
|
4318
|
-
|
|
4319
|
-
|
|
4320
|
-
|
|
4321
|
-
|
|
4322
|
-
|
|
4323
|
-
|
|
4324
|
-
|
|
4325
|
-
|
|
4326
|
-
|
|
4327
|
-
|
|
4328
|
-
|
|
4329
|
-
|
|
4330
|
-
|
|
4331
|
-
|
|
4332
|
-
|
|
4333
|
-
|
|
4334
|
-
|
|
4335
|
-
|
|
4336
|
-
|
|
4337
|
-
|
|
4338
|
-
|
|
4339
|
-
|
|
4340
|
-
|
|
4341
|
-
|
|
4342
|
-
|
|
4343
|
-
|
|
4344
|
-
|
|
4345
|
-
|
|
4346
|
-
|
|
4347
|
-
//
|
|
4348
|
-
//
|
|
4349
|
-
//
|
|
4350
|
-
|
|
4292
|
+
let toolDoneEmitted = false;
|
|
4293
|
+
const emitToolDone = (event) => {
|
|
4294
|
+
send(event);
|
|
4295
|
+
toolDoneEmitted = true;
|
|
4296
|
+
};
|
|
4297
|
+
// Every tool_start must have exactly one matching tool_done. Keeping the
|
|
4298
|
+
// whole post-start path inside this finally block turns unexpected
|
|
4299
|
+
// synchronous failures in validation, cache handling, or future branches
|
|
4300
|
+
// into an explicit tool error instead of leaving run-manager's in-flight
|
|
4301
|
+
// counter latched forever.
|
|
4302
|
+
try {
|
|
4303
|
+
const toolCallSchemaError = toolCallErrors.get(toolCall.id);
|
|
4304
|
+
if (toolCallSchemaError && !toolInputNormalized) {
|
|
4305
|
+
const result = finalizeToolErrorResult(toolInputSchemaErrorResult(toolCall.name, toolCallSchemaError.input, toolCallSchemaError.error, actionEntry?.tool.parameters));
|
|
4306
|
+
emitToolDone({
|
|
4307
|
+
type: "tool_done",
|
|
4308
|
+
id: toolCall.id,
|
|
4309
|
+
tool: toolCall.name,
|
|
4310
|
+
input: toolCall.input,
|
|
4311
|
+
result,
|
|
4312
|
+
isError: true,
|
|
4313
|
+
completedSideEffect: false,
|
|
4314
|
+
});
|
|
4315
|
+
recordToolResult(result, true);
|
|
4316
|
+
return {
|
|
4317
|
+
type: "tool-result",
|
|
4318
|
+
toolCallId: toolCall.id,
|
|
4319
|
+
toolName: toolCall.name,
|
|
4320
|
+
toolInput: wireToolInput,
|
|
4321
|
+
content: result,
|
|
4322
|
+
isError: true,
|
|
4323
|
+
};
|
|
4324
|
+
}
|
|
4325
|
+
const rawToolInputError = validateRawToolInput(actionEntry, toolCall.input);
|
|
4326
|
+
if (rawToolInputError) {
|
|
4327
|
+
const result = finalizeToolErrorResult(toolInputSchemaErrorResult(toolCall.name, toolCall.input, rawToolInputError, actionEntry.tool.parameters));
|
|
4328
|
+
emitToolDone({
|
|
4329
|
+
type: "tool_done",
|
|
4330
|
+
id: toolCall.id,
|
|
4331
|
+
tool: toolCall.name,
|
|
4332
|
+
input: toolCall.input,
|
|
4333
|
+
result,
|
|
4334
|
+
isError: true,
|
|
4335
|
+
completedSideEffect: false,
|
|
4336
|
+
});
|
|
4337
|
+
recordToolResult(result, true);
|
|
4338
|
+
return {
|
|
4339
|
+
type: "tool-result",
|
|
4340
|
+
toolCallId: toolCall.id,
|
|
4341
|
+
toolName: toolCall.name,
|
|
4342
|
+
toolInput: wireToolInput,
|
|
4343
|
+
content: result,
|
|
4344
|
+
isError: true,
|
|
4345
|
+
};
|
|
4346
|
+
}
|
|
4347
|
+
// dedupe: false opts a read-only tool out of the guard entirely — the
|
|
4348
|
+
// cacheKey stays null so it never gets skipped-as-duplicate and never
|
|
4349
|
+
// populates the cache (see the success handler below, which also
|
|
4350
|
+
// leaves dedupe:false results uncached and un-cleared).
|
|
4351
|
+
const cacheKey = actionEntry.readOnly === true && actionEntry.dedupe !== false
|
|
4352
|
+
? toolCallCacheKey(toolCall.name, toolCall.input)
|
|
4353
|
+
: null;
|
|
4354
|
+
if (cacheKey && readOnlyToolResultCache.has(cacheKey)) {
|
|
4355
|
+
const previousResult = readOnlyToolResultCache.get(cacheKey) ?? "";
|
|
4356
|
+
// `contextMessages` (not `messages`) is what the model actually sees
|
|
4357
|
+
// this iteration — context-xray eviction/summarization and
|
|
4358
|
+
// observational-memory trimming can drop the earlier result from
|
|
4359
|
+
// view even though it's still cached here. Only strike-count the
|
|
4360
|
+
// repeat when the model could have looked back and found it itself.
|
|
4361
|
+
const visible = isCachedToolResultVisibleInContext(contextMessages, toolCall, previousResult);
|
|
4362
|
+
let result;
|
|
4363
|
+
if (visible) {
|
|
4364
|
+
const repeats = (duplicateReadOnlyToolCalls.get(cacheKey) ?? 0) + 1;
|
|
4365
|
+
duplicateReadOnlyToolCalls.set(cacheKey, repeats);
|
|
4366
|
+
result = visibleDuplicateReadOnlyToolResult(toolCall.name);
|
|
4367
|
+
if (repeats >= 3) {
|
|
4368
|
+
requestedActionStop ??= {
|
|
4369
|
+
message: "I stopped because the agent kept asking for the same read-only context it already had. Please send the request again if you want me to retry from a fresh turn.",
|
|
4370
|
+
errorCode: "duplicate_read_only_tool",
|
|
4371
|
+
};
|
|
4372
|
+
}
|
|
4373
|
+
}
|
|
4374
|
+
else {
|
|
4375
|
+
// The earlier result was trimmed out of the model's visible
|
|
4376
|
+
// context — this isn't a repetitive loop, the model legitimately
|
|
4377
|
+
// can't see the answer anymore. Re-serve it in full and don't
|
|
4378
|
+
// count a strike.
|
|
4379
|
+
duplicateReadOnlyToolCalls.set(cacheKey, 0);
|
|
4380
|
+
result = resurfacedDuplicateReadOnlyToolResult(toolCall.name, previousResult);
|
|
4381
|
+
}
|
|
4382
|
+
emitToolDone({
|
|
4383
|
+
type: "tool_done",
|
|
4384
|
+
id: toolCall.id,
|
|
4385
|
+
tool: toolCall.name,
|
|
4386
|
+
input: toolCall.input,
|
|
4387
|
+
result,
|
|
4388
|
+
completedSideEffect: false,
|
|
4389
|
+
});
|
|
4390
|
+
recordToolResult(result, false);
|
|
4391
|
+
return {
|
|
4392
|
+
type: "tool-result",
|
|
4393
|
+
toolCallId: toolCall.id,
|
|
4394
|
+
toolName: toolCall.name,
|
|
4395
|
+
toolInput: wireToolInput,
|
|
4396
|
+
content: result,
|
|
4397
|
+
};
|
|
4398
|
+
}
|
|
4399
|
+
if (opts.executionMode === "plan" &&
|
|
4400
|
+
!isPlanModeToolCallAllowed(toolCall.name, toolCall.input, actionEntry)) {
|
|
4401
|
+
const result = planModeBlockedMessage(toolCall.name);
|
|
4402
|
+
emitToolDone({
|
|
4403
|
+
type: "tool_done",
|
|
4404
|
+
id: toolCall.id,
|
|
4405
|
+
tool: toolCall.name,
|
|
4406
|
+
input: toolCall.input,
|
|
4407
|
+
result,
|
|
4408
|
+
isError: true,
|
|
4409
|
+
completedSideEffect: false,
|
|
4410
|
+
});
|
|
4411
|
+
recordToolResult(result, true);
|
|
4412
|
+
return {
|
|
4413
|
+
type: "tool-result",
|
|
4414
|
+
toolCallId: toolCall.id,
|
|
4415
|
+
toolName: toolCall.name,
|
|
4416
|
+
toolInput: wireToolInput,
|
|
4417
|
+
content: result,
|
|
4418
|
+
isError: true,
|
|
4419
|
+
};
|
|
4420
|
+
}
|
|
4351
4421
|
let result;
|
|
4352
|
-
|
|
4353
|
-
|
|
4354
|
-
|
|
4355
|
-
|
|
4356
|
-
|
|
4422
|
+
let isError = false;
|
|
4423
|
+
let mcpApp;
|
|
4424
|
+
let toolResultImages;
|
|
4425
|
+
try {
|
|
4426
|
+
// The run may have been aborted while we waited above for an
|
|
4427
|
+
// interrupted tool's ledger result (the wait can poll for minutes).
|
|
4428
|
+
// Re-check before invoking the action: starting it now would spawn a
|
|
4429
|
+
// fresh zombie execution — a duplicate side effect / double charge —
|
|
4430
|
+
// which the ledger-recovery path exists to prevent. The Promise.race
|
|
4431
|
+
// "Run aborted" leg below only rejects AFTER the action is invoked, so
|
|
4432
|
+
// it cannot guard this. Throw here instead, handled like any abort.
|
|
4433
|
+
if (signal.aborted) {
|
|
4434
|
+
throw new Error("Run aborted");
|
|
4435
|
+
}
|
|
4436
|
+
const timeoutSignal = AbortSignal.timeout(toolTimeoutMs);
|
|
4437
|
+
const actionUserEmail = opts.ownerEmail ?? getRequestUserEmail();
|
|
4438
|
+
const actionOrgId = opts.orgId ?? getRequestOrgId() ?? null;
|
|
4439
|
+
const actionContext = {
|
|
4440
|
+
send,
|
|
4441
|
+
userEmail: actionUserEmail ?? undefined,
|
|
4442
|
+
orgId: actionOrgId,
|
|
4443
|
+
appId: opts.appId,
|
|
4444
|
+
caller: opts.actionCaller ?? "tool",
|
|
4445
|
+
automation: opts.automation,
|
|
4446
|
+
networkProtocol: opts.networkProtocol,
|
|
4447
|
+
networkId: opts.networkId,
|
|
4448
|
+
networkPeer: opts.networkPeer,
|
|
4449
|
+
delegationDepth: opts.delegationDepth,
|
|
4450
|
+
visitedApps: opts.visitedApps,
|
|
4451
|
+
attachments: opts.attachments,
|
|
4452
|
+
signal,
|
|
4453
|
+
// Audit attribution: the action name + the agent thread/turn that
|
|
4454
|
+
// triggered this call, so a mutation can be traced to its run.
|
|
4455
|
+
actionName: toolCall.name,
|
|
4456
|
+
...(wasApproved ? { approvedToolCallKey: approvalKey } : {}),
|
|
4457
|
+
...(opts.threadId ? { threadId: opts.threadId } : {}),
|
|
4458
|
+
...(opts.runId ? { runId: opts.runId } : {}),
|
|
4459
|
+
...(opts.turnId ? { turnId: opts.turnId } : {}),
|
|
4460
|
+
};
|
|
4461
|
+
const requestContext = getRequestContext();
|
|
4462
|
+
const invokeAction = () => actionEntry.run(toolCall.input, actionContext);
|
|
4463
|
+
// Keep a reference to the action promise so we can attach a zombie-
|
|
4464
|
+
// detection continuation AFTER Promise.race abandons it on run abort.
|
|
4465
|
+
// The promise itself is not awaited here — Promise.race owns the await.
|
|
4466
|
+
const actionPromise = Promise.resolve(runWithRequestContext({
|
|
4467
|
+
...(requestContext ?? {}),
|
|
4468
|
+
...(actionUserEmail ? { userEmail: actionUserEmail } : {}),
|
|
4469
|
+
...(actionOrgId ? { orgId: actionOrgId } : {}),
|
|
4470
|
+
...(requestContext?.run ? { run: requestContext.run } : {}),
|
|
4471
|
+
}, invokeAction));
|
|
4472
|
+
// When the run is aborted (soft-timeout / user cancel) while this tool
|
|
4473
|
+
// call is in flight, Promise.race below will throw "Run aborted" and the
|
|
4474
|
+
// action's promise becomes a zombie — it keeps running but its result is
|
|
4475
|
+
// never returned to the loop. If the zombie eventually resolves, write
|
|
4476
|
+
// the result to the durable ledger keyed by (threadId, toolKey) so the
|
|
4477
|
+
// next continuation chunk can recover it instead of re-executing the
|
|
4478
|
+
// side effect.
|
|
4479
|
+
if (opts.threadId && !actionEntry.readOnly) {
|
|
4480
|
+
const ledgerThreadId = opts.threadId;
|
|
4481
|
+
const ledgerToolKey = toolCallCacheKey(toolCall.name, toolCall.input);
|
|
4482
|
+
actionPromise
|
|
4483
|
+
.then((zombieRaw) => {
|
|
4484
|
+
const zombieMcp = isMcpActionResult(zombieRaw)
|
|
4485
|
+
? zombieRaw
|
|
4486
|
+
: null;
|
|
4487
|
+
if (zombieMcp &&
|
|
4488
|
+
zombieMcp.raw &&
|
|
4489
|
+
typeof zombieMcp.raw === "object" &&
|
|
4490
|
+
zombieMcp.raw.isError === true) {
|
|
4491
|
+
return;
|
|
4492
|
+
}
|
|
4493
|
+
const zombieText = zombieMcp ? zombieMcp.text : zombieRaw;
|
|
4494
|
+
const zombieStr = typeof zombieText === "string"
|
|
4495
|
+
? zombieText
|
|
4496
|
+
: JSON.stringify(zombieText, null, 2);
|
|
4497
|
+
void writeLedgerEntry(ledgerThreadId, ledgerToolKey, zombieStr);
|
|
4498
|
+
})
|
|
4499
|
+
.catch(() => {
|
|
4500
|
+
// Action errored in the zombie — no result to ledger.
|
|
4501
|
+
});
|
|
4502
|
+
}
|
|
4503
|
+
const raw = await Promise.race([
|
|
4504
|
+
actionPromise,
|
|
4505
|
+
new Promise((_, reject) => {
|
|
4506
|
+
timeoutSignal.addEventListener("abort", () => reject(new Error(`Tool call timed out after ${toolTimeoutMs / 1000} seconds`)));
|
|
4507
|
+
}),
|
|
4508
|
+
// Stop waiting on the tool when the run itself is aborted (e.g. the
|
|
4509
|
+
// run-manager soft timeout, or a user cancel). Without this leg the
|
|
4510
|
+
// loop blocks on an in-flight tool for up to TOOL_TIMEOUT_MS after
|
|
4511
|
+
// the run signal has already fired.
|
|
4512
|
+
new Promise((_, reject) => {
|
|
4513
|
+
if (signal.aborted) {
|
|
4514
|
+
reject(new Error("Run aborted"));
|
|
4515
|
+
return;
|
|
4516
|
+
}
|
|
4517
|
+
signal.addEventListener("abort", () => reject(new Error("Run aborted")), { once: true });
|
|
4518
|
+
}),
|
|
4519
|
+
]);
|
|
4520
|
+
const mcpResult = isMcpActionResult(raw) ? raw : null;
|
|
4521
|
+
const rawForAgent = mcpResult ? mcpResult.text : raw;
|
|
4522
|
+
if (mcpResult &&
|
|
4523
|
+
mcpResult.raw &&
|
|
4524
|
+
typeof mcpResult.raw === "object" &&
|
|
4525
|
+
mcpResult.raw.isError === true) {
|
|
4526
|
+
isError = true;
|
|
4527
|
+
}
|
|
4528
|
+
mcpApp = mcpResult?.mcpApp;
|
|
4529
|
+
// Demo mode is browser-local presentation state. The agent and MCP
|
|
4530
|
+
// layers always receive the real, access-scoped tool result.
|
|
4531
|
+
let resultForAgent = rawForAgent;
|
|
4532
|
+
// Vision images for the model: MCP tools return standard `image`
|
|
4533
|
+
// content parts; first-party actions opt in via the well-known
|
|
4534
|
+
// `_agentImages` result field (stripped from the JSON the model
|
|
4535
|
+
// reads). The images array
|
|
4536
|
+
// never touches the ledger — only the compact text notes appended
|
|
4537
|
+
// below are persisted.
|
|
4538
|
+
let imageNotes = [];
|
|
4539
|
+
if (mcpResult) {
|
|
4540
|
+
const mcpImages = extractMcpToolResultImages(mcpResult.raw);
|
|
4541
|
+
if (mcpImages.length > 0)
|
|
4542
|
+
toolResultImages = mcpImages;
|
|
4543
|
+
}
|
|
4544
|
+
else {
|
|
4545
|
+
const extracted = extractAgentImagesFromActionResult(resultForAgent);
|
|
4546
|
+
resultForAgent = extracted.value;
|
|
4547
|
+
imageNotes = extracted.notes;
|
|
4548
|
+
if (extracted.images.length > 0) {
|
|
4549
|
+
toolResultImages = extracted.images;
|
|
4550
|
+
}
|
|
4551
|
+
}
|
|
4552
|
+
if (toolResultImages) {
|
|
4553
|
+
imageNotes = [
|
|
4554
|
+
...describeToolResultImages(toolResultImages),
|
|
4555
|
+
...imageNotes,
|
|
4556
|
+
];
|
|
4557
|
+
}
|
|
4558
|
+
let resultStr = typeof resultForAgent === "string"
|
|
4559
|
+
? resultForAgent
|
|
4560
|
+
: JSON.stringify(resultForAgent, null, 2);
|
|
4561
|
+
if (resultStr.length > toolMaxResultChars) {
|
|
4562
|
+
const truncated = resultStr.slice(0, toolMaxResultChars);
|
|
4563
|
+
resultStr = `${truncated}\n\n...[truncated — full result was ${resultStr.length.toLocaleString()} chars; only first ${toolMaxResultChars.toLocaleString()} shown]`;
|
|
4564
|
+
}
|
|
4565
|
+
// Image notes go after truncation so they always survive into the
|
|
4566
|
+
// persisted result string (the durable record that an image existed).
|
|
4567
|
+
if (imageNotes.length > 0) {
|
|
4568
|
+
resultStr = `${resultStr}\n\n${imageNotes.join("\n")}`;
|
|
4569
|
+
}
|
|
4570
|
+
result = resultStr;
|
|
4571
|
+
if (toolCall.name === TOOL_SEARCH_ACTION_NAME && !isError) {
|
|
4572
|
+
const added = expandActiveTools(extractToolSearchResultNames(rawForAgent));
|
|
4573
|
+
if (added.length > 0) {
|
|
4574
|
+
result += `\n\nLoaded matching tool schemas for next step: ${added.join(", ")}`;
|
|
4575
|
+
}
|
|
4576
|
+
}
|
|
4577
|
+
}
|
|
4578
|
+
catch (err) {
|
|
4579
|
+
if (isAgentActionStopError(err)) {
|
|
4580
|
+
const message = sanitizeToolErrorValue(err.message) ||
|
|
4581
|
+
`Stopped after ${toolCall.name} failed.`;
|
|
4582
|
+
result = sanitizeToolErrorValue(err.toolResult || message);
|
|
4357
4583
|
requestedActionStop ??= {
|
|
4358
|
-
message
|
|
4359
|
-
errorCode:
|
|
4584
|
+
message,
|
|
4585
|
+
...(err.errorCode ? { errorCode: err.errorCode } : {}),
|
|
4360
4586
|
};
|
|
4361
4587
|
}
|
|
4588
|
+
else {
|
|
4589
|
+
const message = sanitizeToolErrorValue(err);
|
|
4590
|
+
result = `Error running ${toolCall.name}: ${message}${rateLimitRecoveryHint(message)}`;
|
|
4591
|
+
}
|
|
4592
|
+
isError = true;
|
|
4362
4593
|
}
|
|
4363
|
-
|
|
4364
|
-
|
|
4365
|
-
// context — this isn't a repetitive loop, the model legitimately
|
|
4366
|
-
// can't see the answer anymore. Re-serve it in full and don't
|
|
4367
|
-
// count a strike.
|
|
4368
|
-
duplicateReadOnlyToolCalls.set(cacheKey, 0);
|
|
4369
|
-
result = resurfacedDuplicateReadOnlyToolResult(toolCall.name, previousResult);
|
|
4594
|
+
if (isError) {
|
|
4595
|
+
result = finalizeToolErrorResult(result);
|
|
4370
4596
|
}
|
|
4371
|
-
|
|
4372
|
-
|
|
4373
|
-
|
|
4374
|
-
|
|
4375
|
-
|
|
4376
|
-
|
|
4377
|
-
|
|
4378
|
-
}
|
|
4379
|
-
|
|
4380
|
-
|
|
4381
|
-
|
|
4382
|
-
|
|
4383
|
-
|
|
4384
|
-
|
|
4385
|
-
|
|
4386
|
-
|
|
4387
|
-
|
|
4388
|
-
|
|
4389
|
-
|
|
4390
|
-
|
|
4391
|
-
|
|
4597
|
+
// Side-channel warnings raised anywhere inside the action's call stack
|
|
4598
|
+
// (see `action-warnings.ts`). Drained here rather than in the success
|
|
4599
|
+
// branch so an action that warns and then throws still surfaces it, and
|
|
4600
|
+
// so nothing stays pending to bleed into a later tool's result.
|
|
4601
|
+
const agentWarnings = drainAgentWarnings();
|
|
4602
|
+
if (agentWarnings.length > 0) {
|
|
4603
|
+
result = `${result}\n\n${formatAgentWarningsForToolResult(agentWarnings)}`;
|
|
4604
|
+
}
|
|
4605
|
+
// Auto-refresh the UI after a successful mutating tool call. Any call
|
|
4606
|
+
// that isn't read-only — by its own per-call Plan-mode effect, else the
|
|
4607
|
+
// action's readOnly flag — is assumed to mutate. The client's useDbSync
|
|
4608
|
+
// listener sees a change event with source:"action" and invalidates
|
|
4609
|
+
// ["action"] queries so list-* / get-* refetch. This makes refresh after
|
|
4610
|
+
// agent writes reliable without the model needing to remember to call
|
|
4611
|
+
// `refresh-screen` itself.
|
|
4612
|
+
if (!isError) {
|
|
4613
|
+
try {
|
|
4614
|
+
const { actionCallIsReadOnly, notifyActionChangeInBackground } = await import("../server/action-change.js");
|
|
4615
|
+
if (!actionCallIsReadOnly(actionEntry, toolCall.input, false)) {
|
|
4616
|
+
const owner = opts.ownerEmail ?? getRequestUserEmail() ?? undefined;
|
|
4617
|
+
const orgId = opts.orgId ?? getRequestOrgId() ?? undefined;
|
|
4618
|
+
notifyActionChangeInBackground({
|
|
4619
|
+
actionName: toolCall.name,
|
|
4620
|
+
...(owner ? { owner } : {}),
|
|
4621
|
+
...(orgId ? { orgId } : {}),
|
|
4622
|
+
});
|
|
4623
|
+
}
|
|
4624
|
+
}
|
|
4625
|
+
catch (error) {
|
|
4626
|
+
// poll module may be unavailable in non-server contexts — keep the
|
|
4627
|
+
// tool result, but make the failed background refresh observable.
|
|
4628
|
+
console.warn("Could not notify the action-change poller after a tool call", error);
|
|
4629
|
+
}
|
|
4630
|
+
}
|
|
4631
|
+
emitToolDone({
|
|
4392
4632
|
type: "tool_done",
|
|
4393
4633
|
id: toolCall.id,
|
|
4394
4634
|
tool: toolCall.name,
|
|
4395
4635
|
input: toolCall.input,
|
|
4396
4636
|
result,
|
|
4397
|
-
isError: true,
|
|
4398
|
-
|
|
4637
|
+
...(isError ? { isError: true } : {}),
|
|
4638
|
+
...(isError
|
|
4639
|
+
? { completedSideEffect: false }
|
|
4640
|
+
: actionEntry.readOnly !== true
|
|
4641
|
+
? { completedSideEffect: true }
|
|
4642
|
+
: {}),
|
|
4643
|
+
...(mcpApp ? { mcpApp } : {}),
|
|
4644
|
+
...(actionEntry.chatUI ? { chatUI: actionEntry.chatUI } : {}),
|
|
4399
4645
|
});
|
|
4400
|
-
recordToolResult(result,
|
|
4646
|
+
recordToolResult(result, isError);
|
|
4647
|
+
if (!isError) {
|
|
4648
|
+
if (cacheKey) {
|
|
4649
|
+
readOnlyToolResultCache.set(cacheKey, result);
|
|
4650
|
+
}
|
|
4651
|
+
else if (actionEntry.readOnly !== true) {
|
|
4652
|
+
// A genuine write invalidates all cached reads. A dedupe:false
|
|
4653
|
+
// read-only tool also has a null cacheKey (see above) but must NOT
|
|
4654
|
+
// clear the cache — it isn't a write and other tools' cached reads
|
|
4655
|
+
// are still valid.
|
|
4656
|
+
readOnlyToolResultCache.clear();
|
|
4657
|
+
duplicateReadOnlyToolCalls.clear();
|
|
4658
|
+
}
|
|
4659
|
+
}
|
|
4401
4660
|
return {
|
|
4402
4661
|
type: "tool-result",
|
|
4403
4662
|
toolCallId: toolCall.id,
|
|
4404
4663
|
toolName: toolCall.name,
|
|
4405
4664
|
toolInput: wireToolInput,
|
|
4406
4665
|
content: result,
|
|
4407
|
-
isError:
|
|
4666
|
+
...(isError ? { isError } : {}),
|
|
4667
|
+
...(!isError && toolResultImages && toolResultImages.length > 0
|
|
4668
|
+
? { images: toolResultImages }
|
|
4669
|
+
: {}),
|
|
4408
4670
|
};
|
|
4409
4671
|
}
|
|
4410
|
-
|
|
4411
|
-
|
|
4412
|
-
|
|
4413
|
-
|
|
4414
|
-
|
|
4415
|
-
|
|
4416
|
-
|
|
4417
|
-
|
|
4418
|
-
|
|
4419
|
-
|
|
4420
|
-
|
|
4421
|
-
// it cannot guard this. Throw here instead, handled like any abort.
|
|
4422
|
-
if (signal.aborted) {
|
|
4423
|
-
throw new Error("Run aborted");
|
|
4424
|
-
}
|
|
4425
|
-
const timeoutSignal = AbortSignal.timeout(toolTimeoutMs);
|
|
4426
|
-
const actionUserEmail = opts.ownerEmail ?? getRequestUserEmail();
|
|
4427
|
-
const actionOrgId = opts.orgId ?? getRequestOrgId() ?? null;
|
|
4428
|
-
const actionContext = {
|
|
4429
|
-
send,
|
|
4430
|
-
userEmail: actionUserEmail ?? undefined,
|
|
4431
|
-
orgId: actionOrgId,
|
|
4432
|
-
appId: opts.appId,
|
|
4433
|
-
caller: opts.actionCaller ?? "tool",
|
|
4434
|
-
automation: opts.automation,
|
|
4435
|
-
networkProtocol: opts.networkProtocol,
|
|
4436
|
-
networkId: opts.networkId,
|
|
4437
|
-
networkPeer: opts.networkPeer,
|
|
4438
|
-
delegationDepth: opts.delegationDepth,
|
|
4439
|
-
visitedApps: opts.visitedApps,
|
|
4440
|
-
attachments: opts.attachments,
|
|
4441
|
-
signal,
|
|
4442
|
-
// Audit attribution: the action name + the agent thread/turn that
|
|
4443
|
-
// triggered this call, so a mutation can be traced to its run.
|
|
4444
|
-
actionName: toolCall.name,
|
|
4445
|
-
...(wasApproved ? { approvedToolCallKey: approvalKey } : {}),
|
|
4446
|
-
...(opts.threadId ? { threadId: opts.threadId } : {}),
|
|
4447
|
-
...(opts.runId ? { runId: opts.runId } : {}),
|
|
4448
|
-
...(opts.turnId ? { turnId: opts.turnId } : {}),
|
|
4449
|
-
};
|
|
4450
|
-
const requestContext = getRequestContext();
|
|
4451
|
-
const invokeAction = () => actionEntry.run(toolCall.input, actionContext);
|
|
4452
|
-
// Keep a reference to the action promise so we can attach a zombie-
|
|
4453
|
-
// detection continuation AFTER Promise.race abandons it on run abort.
|
|
4454
|
-
// The promise itself is not awaited here — Promise.race owns the await.
|
|
4455
|
-
const actionPromise = Promise.resolve(runWithRequestContext({
|
|
4456
|
-
...(requestContext ?? {}),
|
|
4457
|
-
...(actionUserEmail ? { userEmail: actionUserEmail } : {}),
|
|
4458
|
-
...(actionOrgId ? { orgId: actionOrgId } : {}),
|
|
4459
|
-
...(requestContext?.run ? { run: requestContext.run } : {}),
|
|
4460
|
-
}, invokeAction));
|
|
4461
|
-
// When the run is aborted (soft-timeout / user cancel) while this tool
|
|
4462
|
-
// call is in flight, Promise.race below will throw "Run aborted" and the
|
|
4463
|
-
// action's promise becomes a zombie — it keeps running but its result is
|
|
4464
|
-
// never returned to the loop. If the zombie eventually resolves, write
|
|
4465
|
-
// the result to the durable ledger keyed by (threadId, toolKey) so the
|
|
4466
|
-
// next continuation chunk can recover it instead of re-executing the
|
|
4467
|
-
// side effect.
|
|
4468
|
-
if (opts.threadId && !actionEntry.readOnly) {
|
|
4469
|
-
const ledgerThreadId = opts.threadId;
|
|
4470
|
-
const ledgerToolKey = toolCallCacheKey(toolCall.name, toolCall.input);
|
|
4471
|
-
actionPromise
|
|
4472
|
-
.then((zombieRaw) => {
|
|
4473
|
-
const zombieMcp = isMcpActionResult(zombieRaw) ? zombieRaw : null;
|
|
4474
|
-
if (zombieMcp &&
|
|
4475
|
-
zombieMcp.raw &&
|
|
4476
|
-
typeof zombieMcp.raw === "object" &&
|
|
4477
|
-
zombieMcp.raw.isError === true) {
|
|
4478
|
-
return;
|
|
4479
|
-
}
|
|
4480
|
-
const zombieText = zombieMcp ? zombieMcp.text : zombieRaw;
|
|
4481
|
-
const zombieStr = typeof zombieText === "string"
|
|
4482
|
-
? zombieText
|
|
4483
|
-
: JSON.stringify(zombieText, null, 2);
|
|
4484
|
-
void writeLedgerEntry(ledgerThreadId, ledgerToolKey, zombieStr);
|
|
4485
|
-
})
|
|
4486
|
-
.catch(() => {
|
|
4487
|
-
// Action errored in the zombie — no result to ledger.
|
|
4672
|
+
finally {
|
|
4673
|
+
if (!toolDoneEmitted) {
|
|
4674
|
+
const result = `Error running ${toolCall.name}: tool execution ended before returning a result.`;
|
|
4675
|
+
emitToolDone({
|
|
4676
|
+
type: "tool_done",
|
|
4677
|
+
id: toolCall.id,
|
|
4678
|
+
tool: toolCall.name,
|
|
4679
|
+
input: toolCall.input,
|
|
4680
|
+
result,
|
|
4681
|
+
isError: true,
|
|
4682
|
+
completedSideEffect: false,
|
|
4488
4683
|
});
|
|
4489
|
-
|
|
4490
|
-
const raw = await Promise.race([
|
|
4491
|
-
actionPromise,
|
|
4492
|
-
new Promise((_, reject) => {
|
|
4493
|
-
timeoutSignal.addEventListener("abort", () => reject(new Error(`Tool call timed out after ${toolTimeoutMs / 1000} seconds`)));
|
|
4494
|
-
}),
|
|
4495
|
-
// Stop waiting on the tool when the run itself is aborted (e.g. the
|
|
4496
|
-
// run-manager soft timeout, or a user cancel). Without this leg the
|
|
4497
|
-
// loop blocks on an in-flight tool for up to TOOL_TIMEOUT_MS after
|
|
4498
|
-
// the run signal has already fired.
|
|
4499
|
-
new Promise((_, reject) => {
|
|
4500
|
-
if (signal.aborted) {
|
|
4501
|
-
reject(new Error("Run aborted"));
|
|
4502
|
-
return;
|
|
4503
|
-
}
|
|
4504
|
-
signal.addEventListener("abort", () => reject(new Error("Run aborted")), { once: true });
|
|
4505
|
-
}),
|
|
4506
|
-
]);
|
|
4507
|
-
const mcpResult = isMcpActionResult(raw) ? raw : null;
|
|
4508
|
-
const rawForAgent = mcpResult ? mcpResult.text : raw;
|
|
4509
|
-
if (mcpResult &&
|
|
4510
|
-
mcpResult.raw &&
|
|
4511
|
-
typeof mcpResult.raw === "object" &&
|
|
4512
|
-
mcpResult.raw.isError === true) {
|
|
4513
|
-
isError = true;
|
|
4514
|
-
}
|
|
4515
|
-
mcpApp = mcpResult?.mcpApp;
|
|
4516
|
-
// Demo mode is browser-local presentation state. The agent and MCP
|
|
4517
|
-
// layers always receive the real, access-scoped tool result.
|
|
4518
|
-
let resultForAgent = rawForAgent;
|
|
4519
|
-
// Vision images for the model: MCP tools return standard `image`
|
|
4520
|
-
// content parts; first-party actions opt in via the well-known
|
|
4521
|
-
// `_agentImages` result field (stripped from the JSON the model
|
|
4522
|
-
// reads). The images array
|
|
4523
|
-
// never touches the ledger — only the compact text notes appended
|
|
4524
|
-
// below are persisted.
|
|
4525
|
-
let imageNotes = [];
|
|
4526
|
-
if (mcpResult) {
|
|
4527
|
-
const mcpImages = extractMcpToolResultImages(mcpResult.raw);
|
|
4528
|
-
if (mcpImages.length > 0)
|
|
4529
|
-
toolResultImages = mcpImages;
|
|
4530
|
-
}
|
|
4531
|
-
else {
|
|
4532
|
-
const extracted = extractAgentImagesFromActionResult(resultForAgent);
|
|
4533
|
-
resultForAgent = extracted.value;
|
|
4534
|
-
imageNotes = extracted.notes;
|
|
4535
|
-
if (extracted.images.length > 0) {
|
|
4536
|
-
toolResultImages = extracted.images;
|
|
4537
|
-
}
|
|
4538
|
-
}
|
|
4539
|
-
if (toolResultImages) {
|
|
4540
|
-
imageNotes = [
|
|
4541
|
-
...describeToolResultImages(toolResultImages),
|
|
4542
|
-
...imageNotes,
|
|
4543
|
-
];
|
|
4544
|
-
}
|
|
4545
|
-
let resultStr = typeof resultForAgent === "string"
|
|
4546
|
-
? resultForAgent
|
|
4547
|
-
: JSON.stringify(resultForAgent, null, 2);
|
|
4548
|
-
if (resultStr.length > toolMaxResultChars) {
|
|
4549
|
-
const truncated = resultStr.slice(0, toolMaxResultChars);
|
|
4550
|
-
resultStr = `${truncated}\n\n...[truncated — full result was ${resultStr.length.toLocaleString()} chars; only first ${toolMaxResultChars.toLocaleString()} shown]`;
|
|
4551
|
-
}
|
|
4552
|
-
// Image notes go after truncation so they always survive into the
|
|
4553
|
-
// persisted result string (the durable record that an image existed).
|
|
4554
|
-
if (imageNotes.length > 0) {
|
|
4555
|
-
resultStr = `${resultStr}\n\n${imageNotes.join("\n")}`;
|
|
4556
|
-
}
|
|
4557
|
-
result = resultStr;
|
|
4558
|
-
if (toolCall.name === TOOL_SEARCH_ACTION_NAME && !isError) {
|
|
4559
|
-
const added = expandActiveTools(extractToolSearchResultNames(rawForAgent));
|
|
4560
|
-
if (added.length > 0) {
|
|
4561
|
-
result += `\n\nLoaded matching tool schemas for next step: ${added.join(", ")}`;
|
|
4562
|
-
}
|
|
4563
|
-
}
|
|
4564
|
-
}
|
|
4565
|
-
catch (err) {
|
|
4566
|
-
if (isAgentActionStopError(err)) {
|
|
4567
|
-
const message = sanitizeToolErrorValue(err.message) ||
|
|
4568
|
-
`Stopped after ${toolCall.name} failed.`;
|
|
4569
|
-
result = sanitizeToolErrorValue(err.toolResult || message);
|
|
4570
|
-
requestedActionStop ??= {
|
|
4571
|
-
message,
|
|
4572
|
-
...(err.errorCode ? { errorCode: err.errorCode } : {}),
|
|
4573
|
-
};
|
|
4574
|
-
}
|
|
4575
|
-
else {
|
|
4576
|
-
const message = sanitizeToolErrorValue(err);
|
|
4577
|
-
result = `Error running ${toolCall.name}: ${message}${rateLimitRecoveryHint(message)}`;
|
|
4578
|
-
}
|
|
4579
|
-
isError = true;
|
|
4580
|
-
}
|
|
4581
|
-
if (isError) {
|
|
4582
|
-
result = finalizeToolErrorResult(result);
|
|
4583
|
-
}
|
|
4584
|
-
// Side-channel warnings raised anywhere inside the action's call stack
|
|
4585
|
-
// (see `action-warnings.ts`). Drained here rather than in the success
|
|
4586
|
-
// branch so an action that warns and then throws still surfaces it, and
|
|
4587
|
-
// so nothing stays pending to bleed into a later tool's result.
|
|
4588
|
-
const agentWarnings = drainAgentWarnings();
|
|
4589
|
-
if (agentWarnings.length > 0) {
|
|
4590
|
-
result = `${result}\n\n${formatAgentWarningsForToolResult(agentWarnings)}`;
|
|
4591
|
-
}
|
|
4592
|
-
// Auto-refresh the UI after a successful mutating tool call. Any call
|
|
4593
|
-
// that isn't read-only — by its own per-call Plan-mode effect, else the
|
|
4594
|
-
// action's readOnly flag — is assumed to mutate. The client's useDbSync
|
|
4595
|
-
// listener sees a change event with source:"action" and invalidates
|
|
4596
|
-
// ["action"] queries so list-* / get-* refetch. This makes refresh after
|
|
4597
|
-
// agent writes reliable without the model needing to remember to call
|
|
4598
|
-
// `refresh-screen` itself.
|
|
4599
|
-
if (!isError) {
|
|
4600
|
-
try {
|
|
4601
|
-
const { actionCallIsReadOnly, notifyActionChangeInBackground } = await import("../server/action-change.js");
|
|
4602
|
-
if (!actionCallIsReadOnly(actionEntry, toolCall.input, false)) {
|
|
4603
|
-
const owner = opts.ownerEmail ?? getRequestUserEmail() ?? undefined;
|
|
4604
|
-
const orgId = opts.orgId ?? getRequestOrgId() ?? undefined;
|
|
4605
|
-
notifyActionChangeInBackground({
|
|
4606
|
-
actionName: toolCall.name,
|
|
4607
|
-
...(owner ? { owner } : {}),
|
|
4608
|
-
...(orgId ? { orgId } : {}),
|
|
4609
|
-
});
|
|
4610
|
-
}
|
|
4611
|
-
}
|
|
4612
|
-
catch {
|
|
4613
|
-
// poll module may be unavailable in non-server contexts — ignore
|
|
4614
|
-
}
|
|
4615
|
-
}
|
|
4616
|
-
send({
|
|
4617
|
-
type: "tool_done",
|
|
4618
|
-
id: toolCall.id,
|
|
4619
|
-
tool: toolCall.name,
|
|
4620
|
-
input: toolCall.input,
|
|
4621
|
-
result,
|
|
4622
|
-
...(isError ? { isError: true } : {}),
|
|
4623
|
-
...(isError
|
|
4624
|
-
? { completedSideEffect: false }
|
|
4625
|
-
: actionEntry.readOnly !== true
|
|
4626
|
-
? { completedSideEffect: true }
|
|
4627
|
-
: {}),
|
|
4628
|
-
...(mcpApp ? { mcpApp } : {}),
|
|
4629
|
-
...(actionEntry.chatUI ? { chatUI: actionEntry.chatUI } : {}),
|
|
4630
|
-
});
|
|
4631
|
-
recordToolResult(result, isError);
|
|
4632
|
-
if (!isError) {
|
|
4633
|
-
if (cacheKey) {
|
|
4634
|
-
readOnlyToolResultCache.set(cacheKey, result);
|
|
4635
|
-
}
|
|
4636
|
-
else if (actionEntry.readOnly !== true) {
|
|
4637
|
-
// A genuine write invalidates all cached reads. A dedupe:false
|
|
4638
|
-
// read-only tool also has a null cacheKey (see above) but must NOT
|
|
4639
|
-
// clear the cache — it isn't a write and other tools' cached reads
|
|
4640
|
-
// are still valid.
|
|
4641
|
-
readOnlyToolResultCache.clear();
|
|
4642
|
-
duplicateReadOnlyToolCalls.clear();
|
|
4684
|
+
recordToolResult(result, true);
|
|
4643
4685
|
}
|
|
4644
4686
|
}
|
|
4645
|
-
return {
|
|
4646
|
-
type: "tool-result",
|
|
4647
|
-
toolCallId: toolCall.id,
|
|
4648
|
-
toolName: toolCall.name,
|
|
4649
|
-
toolInput: wireToolInput,
|
|
4650
|
-
content: result,
|
|
4651
|
-
...(isError ? { isError } : {}),
|
|
4652
|
-
...(!isError && toolResultImages && toolResultImages.length > 0
|
|
4653
|
-
? { images: toolResultImages }
|
|
4654
|
-
: {}),
|
|
4655
|
-
};
|
|
4656
4687
|
};
|
|
4657
4688
|
const getParallelBatchKind = (toolCall) => {
|
|
4658
4689
|
const entry = actions[toolCall.name];
|