@agent-native/core 0.112.0 → 0.113.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 +4 -2
- package/corpus/core/CHANGELOG.md +22 -0
- package/corpus/core/docs/AGENTS.md +7 -0
- package/corpus/core/docs/content/integrations.mdx +63 -2
- package/corpus/core/docs/design/provider-integration-authority.md +117 -0
- package/corpus/core/package.json +6 -1
- package/corpus/core/scripts/materialize-source-corpus.mjs +9 -2
- package/corpus/core/src/cli/atomic-json-file.ts +324 -0
- package/corpus/core/src/cli/claude-code-participant.ts +515 -0
- package/corpus/core/src/cli/code-agent-executor.ts +18 -10
- package/corpus/core/src/cli/code-agent-runs.concurrent-worker.ts +33 -0
- package/corpus/core/src/cli/code-agent-runs.ts +55 -62
- package/corpus/core/src/cli/codex-cli-participant.ts +496 -0
- package/corpus/core/src/cli/multi-frontier-runs.ts +1246 -135
- package/corpus/core/src/client/chat/ChatHistoryList.tsx +7 -404
- package/corpus/core/src/integrations/index.ts +10 -0
- package/corpus/core/src/integrations/slack-oauth.ts +1 -0
- package/corpus/core/src/integrations/webhook-delivery.ts +55 -0
- package/corpus/core/src/notifications/channels.ts +4 -10
- package/corpus/core/src/provider-api/actions/custom-provider-registration.ts +197 -0
- package/corpus/core/src/provider-api/actions/delete-staged-dataset.ts +3 -42
- package/corpus/core/src/provider-api/actions/list-staged-datasets.ts +3 -45
- package/corpus/core/src/provider-api/actions/provider-api-audit.ts +88 -0
- package/corpus/core/src/provider-api/actions/provider-api.ts +460 -0
- package/corpus/core/src/provider-api/actions/query-staged-dataset.ts +3 -140
- package/corpus/core/src/provider-api/actions/staged-datasets.ts +359 -0
- package/corpus/core/src/provider-api/gong.ts +108 -0
- package/corpus/core/src/scripts/docs/source-search.ts +2 -1
- package/corpus/core/src/server/google-oauth-credentials.ts +80 -3
- package/corpus/core/src/server/index.ts +6 -0
- package/corpus/core/src/styles/chat-history-list.css +1 -313
- package/corpus/core/src/templates/default/.agents/skills/actions/SKILL.md +32 -12
- package/corpus/core/src/templates/default/.agents/skills/agent-native-docs/SKILL.md +10 -0
- package/corpus/core/src/templates/default/.agents/skills/customizing-agent-native/SKILL.md +102 -0
- package/corpus/core/src/templates/default/.agents/skills/integration-webhooks/SKILL.md +323 -0
- package/corpus/core/src/templates/default/.agents/skills/onboarding/SKILL.md +56 -0
- package/corpus/core/src/templates/default/.agents/skills/secrets/SKILL.md +273 -0
- package/corpus/core/src/templates/default/.agents/skills/self-modifying-code/SKILL.md +11 -2
- package/corpus/core/src/templates/default/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
- package/corpus/core/src/templates/default/AGENTS.md +25 -18
- package/corpus/core/src/templates/headless/.agents/skills/actions/SKILL.md +512 -0
- package/corpus/core/src/templates/headless/.agents/skills/agent-native-docs/SKILL.md +10 -0
- package/corpus/core/src/templates/headless/.agents/skills/customizing-agent-native/SKILL.md +102 -0
- package/corpus/core/src/templates/headless/.agents/skills/integration-webhooks/SKILL.md +323 -0
- package/corpus/core/src/templates/headless/.agents/skills/secrets/SKILL.md +273 -0
- package/corpus/core/src/templates/headless/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
- package/corpus/core/src/templates/headless/AGENTS.md +7 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/actions/SKILL.md +32 -12
- package/corpus/core/src/templates/workspace-core/.agents/skills/agent-native-docs/SKILL.md +10 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/customizing-agent-native/SKILL.md +102 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/self-modifying-code/SKILL.md +11 -2
- package/corpus/core/src/templates/workspace-core/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
- package/corpus/core/src/templates/workspace-core/AGENTS.md +4 -0
- package/corpus/core/src/templates/workspace-root/AGENTS.md +4 -0
- package/corpus/templates/analytics/.agents/skills/actions/SKILL.md +32 -12
- package/corpus/templates/analytics/.agents/skills/customizing-agent-native/SKILL.md +102 -0
- package/corpus/templates/analytics/.agents/skills/self-modifying-code/SKILL.md +11 -2
- package/corpus/templates/analytics/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
- package/corpus/templates/analytics/actions/delete-staged-dataset.ts +3 -23
- package/corpus/templates/analytics/actions/list-staged-datasets.ts +3 -27
- package/corpus/templates/analytics/actions/provider-api-catalog.ts +16 -19
- package/corpus/templates/analytics/actions/provider-api-docs.ts +3 -5
- package/corpus/templates/analytics/actions/provider-api-request.ts +162 -185
- package/corpus/templates/analytics/actions/query-staged-dataset.ts +3 -47
- package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +52 -161
- package/corpus/templates/assets/.agents/skills/actions/SKILL.md +32 -12
- package/corpus/templates/assets/.agents/skills/customizing-agent-native/SKILL.md +102 -0
- package/corpus/templates/assets/.agents/skills/self-modifying-code/SKILL.md +11 -2
- package/corpus/templates/assets/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
- package/corpus/templates/assets/app/components/layout/Sidebar.tsx +63 -160
- package/corpus/templates/brain/.agents/skills/actions/SKILL.md +32 -12
- package/corpus/templates/brain/.agents/skills/customizing-agent-native/SKILL.md +102 -0
- package/corpus/templates/brain/.agents/skills/self-modifying-code/SKILL.md +11 -2
- package/corpus/templates/brain/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
- package/corpus/templates/brain/actions/_schemas.ts +13 -7
- package/corpus/templates/brain/actions/delete-staged-dataset.ts +3 -24
- package/corpus/templates/brain/actions/list-staged-datasets.ts +3 -28
- package/corpus/templates/brain/actions/provider-api-catalog.ts +5 -11
- package/corpus/templates/brain/actions/provider-api-docs.ts +3 -5
- package/corpus/templates/brain/actions/provider-api-request.ts +3 -37
- package/corpus/templates/brain/actions/query-staged-dataset.ts +3 -48
- package/corpus/templates/brain/actions/update-source.ts +5 -1
- package/corpus/templates/brain/app/components/layout/Sidebar.tsx +48 -154
- package/corpus/templates/brain/app/lib/brain.ts +55 -0
- package/corpus/templates/brain/app/lib/ingest-handoff.ts +35 -0
- package/corpus/templates/brain/changelog/2026-07-19-slack-backfills-can-now-join-configured-public-channels-befo.md +6 -0
- package/corpus/templates/brain/changelog/2026-07-19-slack-backfills-now-continue-across-the-configured-number-of.md +6 -0
- package/corpus/templates/brain/changelog/2026-07-19-slack-backfills-now-start-with-a-safe-four-week-window-and-r.md +6 -0
- package/corpus/templates/brain/server/lib/connectors.ts +53 -2
- package/corpus/templates/brain/server/lib/slack-channel-membership.ts +44 -0
- package/corpus/templates/brain/shared/slack-source-config.ts +60 -0
- package/corpus/templates/calendar/.agents/skills/actions/SKILL.md +32 -12
- package/corpus/templates/calendar/.agents/skills/customizing-agent-native/SKILL.md +102 -0
- package/corpus/templates/calendar/.agents/skills/self-modifying-code/SKILL.md +11 -2
- package/corpus/templates/calendar/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
- package/corpus/templates/calendar/actions/delete-staged-dataset.ts +3 -24
- package/corpus/templates/calendar/actions/list-staged-datasets.ts +3 -28
- package/corpus/templates/calendar/actions/provider-api-catalog.ts +5 -11
- package/corpus/templates/calendar/actions/provider-api-docs.ts +3 -5
- package/corpus/templates/calendar/actions/provider-api-request.ts +3 -37
- package/corpus/templates/calendar/actions/query-staged-dataset.ts +3 -48
- package/corpus/templates/calendar/server/handlers/gong.ts +6 -61
- package/corpus/templates/calendar/server/handlers/google-auth.ts +10 -8
- package/corpus/templates/calendar/server/lib/google-calendar.ts +7 -45
- package/corpus/templates/chat/.agents/skills/actions/SKILL.md +32 -12
- package/corpus/templates/chat/.agents/skills/agent-native-docs/SKILL.md +10 -0
- package/corpus/templates/chat/.agents/skills/customizing-agent-native/SKILL.md +102 -0
- package/corpus/templates/chat/.agents/skills/self-modifying-code/SKILL.md +11 -2
- package/corpus/templates/chat/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
- package/corpus/templates/chat/AGENTS.md +5 -2
- package/corpus/templates/chat/app/components/layout/Sidebar.tsx +51 -157
- package/corpus/templates/clips/.agents/skills/actions/SKILL.md +32 -12
- package/corpus/templates/clips/.agents/skills/customizing-agent-native/SKILL.md +102 -0
- package/corpus/templates/clips/.agents/skills/self-modifying-code/SKILL.md +11 -2
- package/corpus/templates/clips/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
- package/corpus/templates/clips/AGENTS.md +11 -0
- package/corpus/templates/clips/actions/export-to-brain.ts +505 -171
- package/corpus/templates/clips/changelog/2026-07-19-ready-clips-transcripts-can-be-backfilled-to-brain-for-a-bou.md +6 -0
- package/corpus/templates/clips/server/lib/calendar-event-meetings.ts +1 -1
- package/corpus/templates/clips/server/lib/google-calendar-client.ts +12 -22
- package/corpus/templates/clips/server/lib/google-calendar-oauth.ts +9 -6
- package/corpus/templates/clips/server/lib/slack-oauth.ts +12 -47
- package/corpus/templates/clips/server/routes/_agent-native/google/auth-url.get.ts +2 -6
- package/corpus/templates/clips/server/routes/api/auth/google-calendar.get.ts +4 -4
- package/corpus/templates/content/.agents/skills/actions/SKILL.md +32 -12
- package/corpus/templates/content/.agents/skills/customizing-agent-native/SKILL.md +102 -0
- package/corpus/templates/content/.agents/skills/self-modifying-code/SKILL.md +11 -2
- package/corpus/templates/content/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
- package/corpus/templates/content/actions/delete-staged-dataset.ts +3 -24
- package/corpus/templates/content/actions/list-staged-datasets.ts +3 -28
- package/corpus/templates/content/actions/provider-api-catalog.ts +5 -11
- package/corpus/templates/content/actions/provider-api-docs.ts +3 -5
- package/corpus/templates/content/actions/provider-api-request.ts +3 -37
- package/corpus/templates/content/actions/query-staged-dataset.ts +3 -48
- package/corpus/templates/design/.agents/skills/actions/SKILL.md +32 -12
- package/corpus/templates/design/.agents/skills/customizing-agent-native/SKILL.md +102 -0
- package/corpus/templates/design/.agents/skills/self-modifying-code/SKILL.md +11 -2
- package/corpus/templates/design/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
- package/corpus/templates/design/actions/delete-staged-dataset.ts +4 -23
- package/corpus/templates/design/actions/list-staged-datasets.ts +4 -27
- package/corpus/templates/design/actions/provider-api-catalog.ts +15 -18
- package/corpus/templates/design/actions/provider-api-docs.ts +57 -48
- package/corpus/templates/design/actions/provider-api-request.ts +140 -164
- package/corpus/templates/design/actions/query-staged-dataset.ts +4 -47
- package/corpus/templates/dispatch/.agents/skills/actions/SKILL.md +32 -12
- package/corpus/templates/dispatch/.agents/skills/customizing-agent-native/SKILL.md +102 -0
- package/corpus/templates/dispatch/.agents/skills/self-modifying-code/SKILL.md +11 -2
- package/corpus/templates/dispatch/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
- package/corpus/templates/dispatch/actions/delete-staged-dataset.ts +4 -23
- package/corpus/templates/dispatch/actions/list-staged-datasets.ts +4 -30
- package/corpus/templates/dispatch/actions/provider-api-catalog.ts +15 -18
- package/corpus/templates/dispatch/actions/provider-api-docs.ts +57 -48
- package/corpus/templates/dispatch/actions/provider-api-request.ts +138 -163
- package/corpus/templates/dispatch/actions/query-staged-dataset.ts +4 -47
- package/corpus/templates/forms/.agents/skills/actions/SKILL.md +32 -12
- package/corpus/templates/forms/.agents/skills/customizing-agent-native/SKILL.md +102 -0
- package/corpus/templates/forms/.agents/skills/self-modifying-code/SKILL.md +11 -2
- package/corpus/templates/forms/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
- package/corpus/templates/forms/server/lib/integrations.ts +23 -22
- package/corpus/templates/macros/.agents/skills/customizing-agent-native/SKILL.md +102 -0
- package/corpus/templates/macros/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
- package/corpus/templates/mail/.agents/skills/actions/SKILL.md +32 -12
- package/corpus/templates/mail/.agents/skills/customizing-agent-native/SKILL.md +102 -0
- package/corpus/templates/mail/.agents/skills/self-modifying-code/SKILL.md +11 -2
- package/corpus/templates/mail/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
- package/corpus/templates/mail/actions/delete-staged-dataset.ts +4 -23
- package/corpus/templates/mail/actions/list-staged-datasets.ts +4 -27
- package/corpus/templates/mail/actions/provider-api-catalog.ts +15 -18
- package/corpus/templates/mail/actions/provider-api-docs.ts +57 -48
- package/corpus/templates/mail/actions/provider-api-request.ts +146 -173
- package/corpus/templates/mail/actions/query-staged-dataset.ts +4 -47
- package/corpus/templates/mail/server/handlers/gong.ts +6 -61
- package/corpus/templates/mail/server/lib/google-auth.ts +10 -13
- package/corpus/templates/plan/.agents/skills/actions/SKILL.md +32 -12
- package/corpus/templates/plan/.agents/skills/customizing-agent-native/SKILL.md +102 -0
- package/corpus/templates/plan/.agents/skills/self-modifying-code/SKILL.md +11 -2
- package/corpus/templates/plan/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
- package/corpus/templates/plan/app/components/layout/Sidebar.tsx +47 -156
- package/corpus/templates/slides/.agents/skills/actions/SKILL.md +32 -12
- package/corpus/templates/slides/.agents/skills/customizing-agent-native/SKILL.md +102 -0
- package/corpus/templates/slides/.agents/skills/self-modifying-code/SKILL.md +11 -2
- package/corpus/templates/slides/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
- package/corpus/templates/slides/actions/delete-staged-dataset.ts +4 -23
- package/corpus/templates/slides/actions/list-staged-datasets.ts +4 -27
- package/corpus/templates/slides/actions/provider-api-catalog.ts +15 -18
- package/corpus/templates/slides/actions/provider-api-docs.ts +57 -48
- package/corpus/templates/slides/actions/provider-api-request.ts +145 -172
- package/corpus/templates/slides/actions/query-staged-dataset.ts +4 -47
- package/corpus/templates/slides/server/lib/google-docs-oauth.ts +11 -36
- package/corpus/templates/tasks/.agents/skills/actions/SKILL.md +32 -12
- package/corpus/templates/tasks/.agents/skills/agent-native-docs/SKILL.md +10 -0
- package/corpus/templates/tasks/.agents/skills/customizing-agent-native/SKILL.md +102 -0
- package/corpus/templates/tasks/.agents/skills/self-modifying-code/SKILL.md +11 -2
- package/corpus/templates/tasks/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
- package/corpus/toolkit/CHANGELOG.md +125 -0
- package/corpus/toolkit/README.md +60 -0
- package/corpus/toolkit/export-snapshot.json +35 -0
- package/corpus/toolkit/migration-manifest.json +4 -0
- package/corpus/toolkit/package.json +281 -0
- package/corpus/toolkit/scripts/finalize-build.mjs +55 -0
- package/corpus/toolkit/src/app-shell/header-actions.tsx +84 -0
- package/corpus/toolkit/src/app-shell/index.ts +1 -0
- package/corpus/toolkit/src/chat-history/ChatHistoryList.tsx +469 -0
- package/corpus/toolkit/src/chat-history/index.ts +7 -0
- package/corpus/toolkit/src/chat-history.css +314 -0
- package/corpus/toolkit/src/collab-ui/AgentPresenceChip.tsx +69 -0
- package/corpus/toolkit/src/collab-ui/LiveCursorOverlay.tsx +241 -0
- package/corpus/toolkit/src/collab-ui/PresenceBar.tsx +346 -0
- package/corpus/toolkit/src/collab-ui/RecentEditHighlights.tsx +225 -0
- package/corpus/toolkit/src/collab-ui/RemoteSelectionRings.tsx +227 -0
- package/corpus/toolkit/src/collab-ui/agent-identity.ts +16 -0
- package/corpus/toolkit/src/collab-ui/index.ts +39 -0
- package/corpus/toolkit/src/collab-ui/lead-client.ts +32 -0
- package/corpus/toolkit/src/collab-ui/types.ts +96 -0
- package/corpus/toolkit/src/composer/AgentComposerFrame.tsx +59 -0
- package/corpus/toolkit/src/composer/ComposerPlusMenu.tsx +983 -0
- package/corpus/toolkit/src/composer/MentionPopover.tsx +412 -0
- package/corpus/toolkit/src/composer/PastedTextChip.tsx +150 -0
- package/corpus/toolkit/src/composer/PromptComposer.tsx +718 -0
- package/corpus/toolkit/src/composer/RealtimeVoiceMode.tsx +856 -0
- package/corpus/toolkit/src/composer/TiptapComposer.tsx +2936 -0
- package/corpus/toolkit/src/composer/VoiceButton.tsx +255 -0
- package/corpus/toolkit/src/composer/asset-picker-url.ts +80 -0
- package/corpus/toolkit/src/composer/attachment-accept.ts +71 -0
- package/corpus/toolkit/src/composer/draft-key.ts +7 -0
- package/corpus/toolkit/src/composer/extensions/FileReference.tsx +55 -0
- package/corpus/toolkit/src/composer/extensions/MentionReference.tsx +93 -0
- package/corpus/toolkit/src/composer/extensions/SkillReference.tsx +56 -0
- package/corpus/toolkit/src/composer/index.ts +79 -0
- package/corpus/toolkit/src/composer/pasted-text.ts +160 -0
- package/corpus/toolkit/src/composer/prompt-attachments.ts +93 -0
- package/corpus/toolkit/src/composer/realtime-voice-audio-level.ts +64 -0
- package/corpus/toolkit/src/composer/realtime-voice-transcript.ts +134 -0
- package/corpus/toolkit/src/composer/runtime-adapters.tsx +343 -0
- package/corpus/toolkit/src/composer/types.ts +66 -0
- package/corpus/toolkit/src/composer/use-file-search.ts +64 -0
- package/corpus/toolkit/src/composer/use-mention-search.ts +90 -0
- package/corpus/toolkit/src/composer/use-skills.ts +45 -0
- package/corpus/toolkit/src/composer/useRealtimeVoiceMode.tsx +2117 -0
- package/corpus/toolkit/src/composer/useVoiceDictation.ts +1191 -0
- package/corpus/toolkit/src/context-ui/ContextMeter.tsx +101 -0
- package/corpus/toolkit/src/context-ui/ContextSegmentRow.tsx +184 -0
- package/corpus/toolkit/src/context-ui/ContextTreemap.tsx +125 -0
- package/corpus/toolkit/src/context-ui/ContextXRayPanel.tsx +377 -0
- package/corpus/toolkit/src/context-ui/format.ts +42 -0
- package/corpus/toolkit/src/context-ui/index.ts +15 -0
- package/corpus/toolkit/src/context-ui/types.ts +43 -0
- package/corpus/toolkit/src/design-tweaks/index.ts +1 -0
- package/corpus/toolkit/src/design-tweaks/visual-style-controls.tsx +1084 -0
- package/corpus/toolkit/src/editor/BubbleToolbar.tsx +253 -0
- package/corpus/toolkit/src/editor/CodeBlockNode.tsx +254 -0
- package/corpus/toolkit/src/editor/DragHandle.ts +1437 -0
- package/corpus/toolkit/src/editor/ImageExtension.ts +306 -0
- package/corpus/toolkit/src/editor/RegistryBlockContext.tsx +107 -0
- package/corpus/toolkit/src/editor/RegistryBlockNode.tsx +652 -0
- package/corpus/toolkit/src/editor/RichMarkdownEditor.tsx +81 -0
- package/corpus/toolkit/src/editor/RunId.ts +61 -0
- package/corpus/toolkit/src/editor/SharedRichEditor.tsx +321 -0
- package/corpus/toolkit/src/editor/SlashCommandMenu.tsx +310 -0
- package/corpus/toolkit/src/editor/extensions.ts +402 -0
- package/corpus/toolkit/src/editor/gfmDoc.ts +92 -0
- package/corpus/toolkit/src/editor/index.ts +93 -0
- package/corpus/toolkit/src/editor/registrySlashCommands.ts +131 -0
- package/corpus/toolkit/src/editor/surgical-apply.ts +192 -0
- package/corpus/toolkit/src/editor/useCollabReconcile.ts +589 -0
- package/corpus/toolkit/src/editor.css +510 -0
- package/corpus/toolkit/src/hooks/index.ts +2 -0
- package/corpus/toolkit/src/hooks/use-mobile.tsx +21 -0
- package/corpus/toolkit/src/hooks/use-toast.ts +188 -0
- package/corpus/toolkit/src/index.ts +8 -0
- package/corpus/toolkit/src/onboarding/index.ts +1 -0
- package/corpus/toolkit/src/provider.tsx +47 -0
- package/corpus/toolkit/src/sharing/VisibilityBadge.tsx +37 -0
- package/corpus/toolkit/src/sharing/index.ts +4 -0
- package/corpus/toolkit/src/styles.css +21 -0
- package/corpus/toolkit/src/ui/accordion.tsx +56 -0
- package/corpus/toolkit/src/ui/alert-dialog.tsx +141 -0
- package/corpus/toolkit/src/ui/alert.tsx +59 -0
- package/corpus/toolkit/src/ui/aspect-ratio.tsx +5 -0
- package/corpus/toolkit/src/ui/avatar.tsx +48 -0
- package/corpus/toolkit/src/ui/badge.tsx +37 -0
- package/corpus/toolkit/src/ui/breadcrumb.tsx +115 -0
- package/corpus/toolkit/src/ui/button.tsx +78 -0
- package/corpus/toolkit/src/ui/calendar.tsx +214 -0
- package/corpus/toolkit/src/ui/card.tsx +86 -0
- package/corpus/toolkit/src/ui/carousel.tsx +260 -0
- package/corpus/toolkit/src/ui/chart.tsx +375 -0
- package/corpus/toolkit/src/ui/checkbox.tsx +28 -0
- package/corpus/toolkit/src/ui/collapsible.tsx +9 -0
- package/corpus/toolkit/src/ui/command.tsx +174 -0
- package/corpus/toolkit/src/ui/context-menu.tsx +202 -0
- package/corpus/toolkit/src/ui/date-picker.tsx +64 -0
- package/corpus/toolkit/src/ui/dialog.tsx +146 -0
- package/corpus/toolkit/src/ui/drawer.tsx +126 -0
- package/corpus/toolkit/src/ui/dropdown-menu.tsx +218 -0
- package/corpus/toolkit/src/ui/form.tsx +177 -0
- package/corpus/toolkit/src/ui/hover-card.tsx +27 -0
- package/corpus/toolkit/src/ui/index.ts +52 -0
- package/corpus/toolkit/src/ui/input-otp.tsx +69 -0
- package/corpus/toolkit/src/ui/input.tsx +22 -0
- package/corpus/toolkit/src/ui/label.tsx +24 -0
- package/corpus/toolkit/src/ui/logo.tsx +36 -0
- package/corpus/toolkit/src/ui/menubar.tsx +235 -0
- package/corpus/toolkit/src/ui/navigation-menu.tsx +128 -0
- package/corpus/toolkit/src/ui/pagination.tsx +121 -0
- package/corpus/toolkit/src/ui/popover.tsx +44 -0
- package/corpus/toolkit/src/ui/progress.tsx +26 -0
- package/corpus/toolkit/src/ui/radio-group.tsx +42 -0
- package/corpus/toolkit/src/ui/resizable.tsx +43 -0
- package/corpus/toolkit/src/ui/scroll-area.tsx +46 -0
- package/corpus/toolkit/src/ui/select.tsx +158 -0
- package/corpus/toolkit/src/ui/separator.tsx +29 -0
- package/corpus/toolkit/src/ui/sheet.tsx +160 -0
- package/corpus/toolkit/src/ui/sidebar.tsx +777 -0
- package/corpus/toolkit/src/ui/skeleton.tsx +18 -0
- package/corpus/toolkit/src/ui/slider.tsx +26 -0
- package/corpus/toolkit/src/ui/sonner.tsx +58 -0
- package/corpus/toolkit/src/ui/spinner.tsx +17 -0
- package/corpus/toolkit/src/ui/switch.tsx +27 -0
- package/corpus/toolkit/src/ui/table.tsx +117 -0
- package/corpus/toolkit/src/ui/tabs.tsx +53 -0
- package/corpus/toolkit/src/ui/textarea.tsx +23 -0
- package/corpus/toolkit/src/ui/toast.tsx +127 -0
- package/corpus/toolkit/src/ui/toaster.tsx +33 -0
- package/corpus/toolkit/src/ui/toggle-group.tsx +59 -0
- package/corpus/toolkit/src/ui/toggle.tsx +43 -0
- package/corpus/toolkit/src/ui/tooltip.tsx +53 -0
- package/corpus/toolkit/src/ui/use-toast.ts +3 -0
- package/corpus/toolkit/src/utils.ts +8 -0
- package/corpus/toolkit/tsconfig.json +23 -0
- package/dist/cli/atomic-json-file.d.ts +30 -0
- package/dist/cli/atomic-json-file.d.ts.map +1 -0
- package/dist/cli/atomic-json-file.js +240 -0
- package/dist/cli/atomic-json-file.js.map +1 -0
- package/dist/cli/claude-code-participant.d.ts +77 -0
- package/dist/cli/claude-code-participant.d.ts.map +1 -0
- package/dist/cli/claude-code-participant.js +355 -0
- package/dist/cli/claude-code-participant.js.map +1 -0
- package/dist/cli/code-agent-executor.d.ts.map +1 -1
- package/dist/cli/code-agent-executor.js +18 -10
- package/dist/cli/code-agent-executor.js.map +1 -1
- package/dist/cli/code-agent-runs.concurrent-worker.d.ts +2 -0
- package/dist/cli/code-agent-runs.concurrent-worker.d.ts.map +1 -0
- package/dist/cli/code-agent-runs.concurrent-worker.js +32 -0
- package/dist/cli/code-agent-runs.concurrent-worker.js.map +1 -0
- package/dist/cli/code-agent-runs.d.ts.map +1 -1
- package/dist/cli/code-agent-runs.js +43 -56
- package/dist/cli/code-agent-runs.js.map +1 -1
- package/dist/cli/codex-cli-participant.d.ts +77 -0
- package/dist/cli/codex-cli-participant.d.ts.map +1 -0
- package/dist/cli/codex-cli-participant.js +354 -0
- package/dist/cli/codex-cli-participant.js.map +1 -0
- package/dist/cli/multi-frontier-runs.d.ts +115 -0
- package/dist/cli/multi-frontier-runs.d.ts.map +1 -1
- package/dist/cli/multi-frontier-runs.js +831 -113
- package/dist/cli/multi-frontier-runs.js.map +1 -1
- package/dist/client/chat/ChatHistoryList.d.ts +1 -87
- package/dist/client/chat/ChatHistoryList.d.ts.map +1 -1
- package/dist/client/chat/ChatHistoryList.js +1 -82
- package/dist/client/chat/ChatHistoryList.js.map +1 -1
- package/dist/integrations/index.d.ts +2 -1
- package/dist/integrations/index.d.ts.map +1 -1
- package/dist/integrations/index.js +2 -1
- package/dist/integrations/index.js.map +1 -1
- package/dist/integrations/slack-manifest.d.ts +1 -1
- package/dist/integrations/slack-oauth.d.ts +1 -1
- package/dist/integrations/slack-oauth.d.ts.map +1 -1
- package/dist/integrations/slack-oauth.js +1 -0
- package/dist/integrations/slack-oauth.js.map +1 -1
- package/dist/integrations/webhook-delivery.d.ts +23 -0
- package/dist/integrations/webhook-delivery.d.ts.map +1 -0
- package/dist/integrations/webhook-delivery.js +32 -0
- package/dist/integrations/webhook-delivery.js.map +1 -0
- package/dist/notifications/channels.d.ts.map +1 -1
- package/dist/notifications/channels.js +4 -9
- package/dist/notifications/channels.js.map +1 -1
- package/dist/notifications/routes.d.ts +3 -3
- package/dist/provider-api/actions/custom-provider-registration.d.ts +136 -0
- package/dist/provider-api/actions/custom-provider-registration.d.ts.map +1 -0
- package/dist/provider-api/actions/custom-provider-registration.js +154 -0
- package/dist/provider-api/actions/custom-provider-registration.js.map +1 -0
- package/dist/provider-api/actions/delete-staged-dataset.d.ts +1 -1
- package/dist/provider-api/actions/delete-staged-dataset.d.ts.map +1 -1
- package/dist/provider-api/actions/delete-staged-dataset.js +3 -34
- package/dist/provider-api/actions/delete-staged-dataset.js.map +1 -1
- package/dist/provider-api/actions/list-staged-datasets.d.ts +2 -3
- package/dist/provider-api/actions/list-staged-datasets.d.ts.map +1 -1
- package/dist/provider-api/actions/list-staged-datasets.js +3 -40
- package/dist/provider-api/actions/list-staged-datasets.js.map +1 -1
- package/dist/provider-api/actions/provider-api-audit.d.ts +7 -0
- package/dist/provider-api/actions/provider-api-audit.d.ts.map +1 -0
- package/dist/provider-api/actions/provider-api-audit.js +74 -0
- package/dist/provider-api/actions/provider-api-audit.js.map +1 -0
- package/dist/provider-api/actions/provider-api.d.ts +370 -0
- package/dist/provider-api/actions/provider-api.d.ts.map +1 -0
- package/dist/provider-api/actions/provider-api.js +280 -0
- package/dist/provider-api/actions/provider-api.js.map +1 -0
- package/dist/provider-api/actions/query-staged-dataset.d.ts +1 -1
- package/dist/provider-api/actions/query-staged-dataset.d.ts.map +1 -1
- package/dist/provider-api/actions/query-staged-dataset.js +3 -116
- package/dist/provider-api/actions/query-staged-dataset.js.map +1 -1
- package/dist/provider-api/actions/staged-datasets.d.ts +190 -0
- package/dist/provider-api/actions/staged-datasets.d.ts.map +1 -0
- package/dist/provider-api/actions/staged-datasets.js +210 -0
- package/dist/provider-api/actions/staged-datasets.js.map +1 -0
- package/dist/provider-api/gong.d.ts +44 -0
- package/dist/provider-api/gong.d.ts.map +1 -0
- package/dist/provider-api/gong.js +56 -0
- package/dist/provider-api/gong.js.map +1 -0
- package/dist/scripts/docs/source-search.d.ts +2 -1
- package/dist/scripts/docs/source-search.d.ts.map +1 -1
- package/dist/scripts/docs/source-search.js +2 -1
- package/dist/scripts/docs/source-search.js.map +1 -1
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/google-oauth-credentials.d.ts +35 -0
- package/dist/server/google-oauth-credentials.d.ts.map +1 -1
- package/dist/server/google-oauth-credentials.js +48 -2
- package/dist/server/google-oauth-credentials.js.map +1 -1
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +1 -1
- package/dist/server/index.js.map +1 -1
- package/dist/styles/chat-history-list.css +1 -313
- package/dist/templates/chat/.agents/skills/actions/SKILL.md +32 -12
- package/dist/templates/chat/.agents/skills/agent-native-docs/SKILL.md +10 -0
- package/dist/templates/chat/.agents/skills/customizing-agent-native/SKILL.md +102 -0
- package/dist/templates/chat/.agents/skills/self-modifying-code/SKILL.md +11 -2
- package/dist/templates/chat/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
- package/dist/templates/chat/AGENTS.md +5 -2
- package/dist/templates/chat/app/components/layout/Sidebar.tsx +51 -157
- package/dist/templates/default/.agents/skills/actions/SKILL.md +32 -12
- package/dist/templates/default/.agents/skills/agent-native-docs/SKILL.md +10 -0
- package/dist/templates/default/.agents/skills/customizing-agent-native/SKILL.md +102 -0
- package/dist/templates/default/.agents/skills/integration-webhooks/SKILL.md +323 -0
- package/dist/templates/default/.agents/skills/onboarding/SKILL.md +56 -0
- package/dist/templates/default/.agents/skills/secrets/SKILL.md +273 -0
- package/dist/templates/default/.agents/skills/self-modifying-code/SKILL.md +11 -2
- package/dist/templates/default/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
- package/dist/templates/default/AGENTS.md +25 -18
- package/dist/templates/headless/.agents/skills/actions/SKILL.md +512 -0
- package/dist/templates/headless/.agents/skills/agent-native-docs/SKILL.md +10 -0
- package/dist/templates/headless/.agents/skills/customizing-agent-native/SKILL.md +102 -0
- package/dist/templates/headless/.agents/skills/integration-webhooks/SKILL.md +323 -0
- package/dist/templates/headless/.agents/skills/secrets/SKILL.md +273 -0
- package/dist/templates/headless/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
- package/dist/templates/headless/AGENTS.md +7 -0
- package/dist/templates/workspace-core/.agents/skills/actions/SKILL.md +32 -12
- package/dist/templates/workspace-core/.agents/skills/agent-native-docs/SKILL.md +10 -0
- package/dist/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
- package/dist/templates/workspace-core/.agents/skills/customizing-agent-native/SKILL.md +102 -0
- package/dist/templates/workspace-core/.agents/skills/self-modifying-code/SKILL.md +11 -2
- package/dist/templates/workspace-core/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
- package/dist/templates/workspace-core/AGENTS.md +4 -0
- package/dist/templates/workspace-root/AGENTS.md +4 -0
- package/docs/AGENTS.md +7 -0
- package/docs/content/integrations.mdx +63 -2
- package/docs/design/provider-integration-authority.md +117 -0
- package/package.json +7 -2
- package/src/templates/chat/.agents/skills/actions/SKILL.md +32 -12
- package/src/templates/chat/.agents/skills/agent-native-docs/SKILL.md +10 -0
- package/src/templates/chat/.agents/skills/customizing-agent-native/SKILL.md +102 -0
- package/src/templates/chat/.agents/skills/self-modifying-code/SKILL.md +11 -2
- package/src/templates/chat/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
- package/src/templates/chat/AGENTS.md +5 -2
- package/src/templates/chat/app/components/layout/Sidebar.tsx +51 -157
- package/src/templates/default/.agents/skills/actions/SKILL.md +32 -12
- package/src/templates/default/.agents/skills/agent-native-docs/SKILL.md +10 -0
- package/src/templates/default/.agents/skills/customizing-agent-native/SKILL.md +102 -0
- package/src/templates/default/.agents/skills/integration-webhooks/SKILL.md +323 -0
- package/src/templates/default/.agents/skills/onboarding/SKILL.md +56 -0
- package/src/templates/default/.agents/skills/secrets/SKILL.md +273 -0
- package/src/templates/default/.agents/skills/self-modifying-code/SKILL.md +11 -2
- package/src/templates/default/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
- package/src/templates/default/AGENTS.md +25 -18
- package/src/templates/headless/.agents/skills/actions/SKILL.md +512 -0
- package/src/templates/headless/.agents/skills/agent-native-docs/SKILL.md +10 -0
- package/src/templates/headless/.agents/skills/customizing-agent-native/SKILL.md +102 -0
- package/src/templates/headless/.agents/skills/integration-webhooks/SKILL.md +323 -0
- package/src/templates/headless/.agents/skills/secrets/SKILL.md +273 -0
- package/src/templates/headless/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
- package/src/templates/headless/AGENTS.md +7 -0
- package/src/templates/workspace-core/.agents/skills/actions/SKILL.md +32 -12
- package/src/templates/workspace-core/.agents/skills/agent-native-docs/SKILL.md +10 -0
- package/src/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
- package/src/templates/workspace-core/.agents/skills/customizing-agent-native/SKILL.md +102 -0
- package/src/templates/workspace-core/.agents/skills/self-modifying-code/SKILL.md +11 -2
- package/src/templates/workspace-core/.agents/skills/upgrade-agent-native/SKILL.md +6 -0
- package/src/templates/workspace-core/AGENTS.md +4 -0
- package/src/templates/workspace-root/AGENTS.md +4 -0
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: integration-webhooks
|
|
3
|
+
description: >-
|
|
4
|
+
Cross-platform pattern for handling messaging integration webhooks (Slack,
|
|
5
|
+
Telegram, WhatsApp, email, etc.) on serverless hosts. Use when adding a new
|
|
6
|
+
integration adapter, debugging dropped messages, or wiring long-running agent
|
|
7
|
+
work into a webhook handler.
|
|
8
|
+
scope: dev
|
|
9
|
+
metadata:
|
|
10
|
+
internal: true
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# Integration Webhooks
|
|
14
|
+
|
|
15
|
+
## Rule
|
|
16
|
+
|
|
17
|
+
Integration webhooks (Slack, Telegram, WhatsApp, email, Google Docs, etc.) must
|
|
18
|
+
**enqueue work to SQL and return 200 immediately**, then process the work in a
|
|
19
|
+
**separate fresh function execution** kicked off by a self-fired HTTP POST. A
|
|
20
|
+
recurring retry job sweeps anything that gets stuck. This pattern works on every
|
|
21
|
+
serverless host (Netlify, Vercel, Cloudflare Workers, Fly, Render, Node) without
|
|
22
|
+
relying on platform-specific background-execution features.
|
|
23
|
+
|
|
24
|
+
Do not run agent loops inside the webhook handler itself. Do not rely on
|
|
25
|
+
fire-and-forget `Promise`s after `return`ing from a serverless handler — they get
|
|
26
|
+
killed when the function freezes.
|
|
27
|
+
|
|
28
|
+
## Why
|
|
29
|
+
|
|
30
|
+
Messaging platforms expect a 200 response within a tight window — Slack will
|
|
31
|
+
retry after 3 seconds, and a retried event triggers duplicate agent runs. At the
|
|
32
|
+
same time, an agent loop replying to the message can take 30–60+ seconds because
|
|
33
|
+
it may make multiple LLM calls and tool calls.
|
|
34
|
+
|
|
35
|
+
Past attempts that don't work cross-host:
|
|
36
|
+
|
|
37
|
+
- **Fire-and-forget `Promise.then(...)` after returning** — Lambda/Vercel/CF
|
|
38
|
+
freeze the execution context the moment the response goes out. The promise
|
|
39
|
+
is silently killed, the user gets no reply, and there's no error in the
|
|
40
|
+
logs.
|
|
41
|
+
- **Netlify Background Functions** — Netlify-only, requires a `-background`
|
|
42
|
+
filename suffix, breaks on every other host.
|
|
43
|
+
- **Cloudflare `event.waitUntil()`** — CF Workers only, not portable.
|
|
44
|
+
- **Vercel Fluid / `after()`** — Vercel-only, gated behind specific runtimes.
|
|
45
|
+
- **A long-lived in-process queue** — fine on a single Node box, but on
|
|
46
|
+
serverless every cold start gets a fresh queue and any pending work is
|
|
47
|
+
lost.
|
|
48
|
+
|
|
49
|
+
The only universal answer: **persist the work, then trigger a brand new
|
|
50
|
+
function execution to do it.** SQL is the queue, a self-webhook is the trigger,
|
|
51
|
+
and a recurring job is the safety net.
|
|
52
|
+
|
|
53
|
+
## The Flow
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
┌──────────┐ 1. POST /integrations/:platform/webhook
|
|
57
|
+
│ Platform │────────────────────────────────────────────►┌──────────────────┐
|
|
58
|
+
└──────────┘ │ Webhook handler │
|
|
59
|
+
│ (function exec 1)│
|
|
60
|
+
└──────────────────┘
|
|
61
|
+
│
|
|
62
|
+
2. INSERT INTO integration_pending_tasks
|
|
63
|
+
(status='pending', payload=...)
|
|
64
|
+
│
|
|
65
|
+
3. fetch(POST /integrations/_process-task)
|
|
66
|
+
— fire-and-forget, NO await on body
|
|
67
|
+
│
|
|
68
|
+
4. return 200 to platform ◄───────────┘
|
|
69
|
+
|
|
70
|
+
┌──────────────────┐
|
|
71
|
+
5. POST arrives at processor │ Processor │
|
|
72
|
+
(separate fresh function) │ (function exec 2)│
|
|
73
|
+
└──────────────────┘
|
|
74
|
+
│
|
|
75
|
+
6. claimPendingTask(id) → status='processing'
|
|
76
|
+
7. runAgentLoop(...) — full timeout budget here
|
|
77
|
+
8. adapter.sendResponse(...) back to platform
|
|
78
|
+
9. markTaskCompleted(id)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
┌──────────────────────────────────────────────┐
|
|
82
|
+
│ Recurring job (every 60s) — safety net │
|
|
83
|
+
│ Re-fires processor for tasks stuck in │
|
|
84
|
+
│ 'pending' or 'processing' beyond timeout. │
|
|
85
|
+
│ Caps retries at 3 then marks 'failed'. │
|
|
86
|
+
└──────────────────────────────────────────────┘
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
The webhook handler does as little as possible. The fresh function execution
|
|
90
|
+
that handles `_process-task` gets its own full timeout budget for the agent
|
|
91
|
+
loop.
|
|
92
|
+
|
|
93
|
+
## Key Files
|
|
94
|
+
|
|
95
|
+
| File | Purpose |
|
|
96
|
+
| ----------------------------------------------------------------------- | ---------------------------------------------------------------------- |
|
|
97
|
+
| `packages/core/src/integrations/plugin.ts` | Mounts `/_agent-native/integrations/*` routes |
|
|
98
|
+
| `packages/core/src/integrations/webhook-handler.ts` | Verifies signature, parses, enqueues task, fires processor |
|
|
99
|
+
| `packages/core/src/integrations/pending-tasks-store.ts` | SQL queue: `insertPendingTask`, `claimPendingTask`, `markTaskCompleted`, `markTaskFailed` |
|
|
100
|
+
| `packages/core/src/integrations/pending-tasks-retry-job.ts` | Recurring retry sweep (`startPendingTasksRetryJob`, `retryStuckPendingTasks`) |
|
|
101
|
+
| `packages/core/src/integrations/types.ts` | `PlatformAdapter`, `IncomingMessage`, `OutgoingMessage` |
|
|
102
|
+
| `packages/core/src/integrations/adapters/{slack,telegram,whatsapp,email,google-docs}.ts` | One adapter per platform |
|
|
103
|
+
|
|
104
|
+
## Routes
|
|
105
|
+
|
|
106
|
+
All under `/_agent-native/integrations/`:
|
|
107
|
+
|
|
108
|
+
| Method | Path | Purpose |
|
|
109
|
+
| ------ | -------------------------- | ------------------------------------------------------------- |
|
|
110
|
+
| POST | `/:platform/webhook` | Platform pings this. Verifies, enqueues, returns 200 quickly. |
|
|
111
|
+
| POST | `/_process-task` | Self-webhook target. Claims a task and runs the agent loop. |
|
|
112
|
+
| GET | `/status` | All integrations status (settings UI). |
|
|
113
|
+
| GET | `/:platform/status` | One platform's status. |
|
|
114
|
+
| POST | `/:platform/enable` | Enable an integration. |
|
|
115
|
+
| POST | `/:platform/disable` | Disable an integration. |
|
|
116
|
+
| POST | `/:platform/setup` | Platform-specific setup (e.g. Telegram webhook registration). |
|
|
117
|
+
|
|
118
|
+
## SQL Schema
|
|
119
|
+
|
|
120
|
+
The pending-task queue lives in `integration_pending_tasks`:
|
|
121
|
+
|
|
122
|
+
```sql
|
|
123
|
+
CREATE TABLE IF NOT EXISTS integration_pending_tasks (
|
|
124
|
+
id TEXT PRIMARY KEY,
|
|
125
|
+
platform TEXT NOT NULL,
|
|
126
|
+
external_thread_id TEXT NOT NULL,
|
|
127
|
+
payload TEXT NOT NULL, -- JSON-serialized IncomingMessage
|
|
128
|
+
owner_email TEXT NOT NULL,
|
|
129
|
+
org_id TEXT,
|
|
130
|
+
status TEXT NOT NULL, -- pending | processing | completed | failed
|
|
131
|
+
attempts INTEGER NOT NULL DEFAULT 0,
|
|
132
|
+
error_message TEXT,
|
|
133
|
+
created_at INTEGER NOT NULL,
|
|
134
|
+
updated_at INTEGER NOT NULL,
|
|
135
|
+
completed_at INTEGER
|
|
136
|
+
);
|
|
137
|
+
CREATE INDEX IF NOT EXISTS idx_pending_tasks_status_created
|
|
138
|
+
ON integration_pending_tasks(status, created_at);
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
The store layer creates this lazily on first use via `ensureTable()` and uses
|
|
142
|
+
`intType()` from `db/client.ts` so it works on both SQLite and Postgres.
|
|
143
|
+
|
|
144
|
+
`claimPendingTask` is the critical concurrency primitive: it atomically flips
|
|
145
|
+
`pending` → `processing` and increments `attempts`, returning `null` if another
|
|
146
|
+
worker beat us to it. Both the initial fire-and-forget call and the retry job
|
|
147
|
+
funnel through the same processor endpoint, and `claimPendingTask` is what
|
|
148
|
+
prevents the same task from being processed twice.
|
|
149
|
+
|
|
150
|
+
## Adding a New Platform Adapter
|
|
151
|
+
|
|
152
|
+
1. **Implement `PlatformAdapter`** in `packages/core/src/integrations/adapters/<platform>.ts`:
|
|
153
|
+
|
|
154
|
+
```ts
|
|
155
|
+
export function myPlatformAdapter(): PlatformAdapter {
|
|
156
|
+
return {
|
|
157
|
+
platform: "myplatform",
|
|
158
|
+
label: "MyPlatform",
|
|
159
|
+
getRequiredEnvKeys: () => [
|
|
160
|
+
{ name: "MYPLATFORM_TOKEN", label: "MyPlatform Bot Token", scope: "global" },
|
|
161
|
+
{ name: "MYPLATFORM_SIGNING_SECRET", label: "MyPlatform Signing Secret", scope: "global" },
|
|
162
|
+
],
|
|
163
|
+
async handleVerification(event) {
|
|
164
|
+
// Platform-specific challenge response, if any
|
|
165
|
+
return { handled: false };
|
|
166
|
+
},
|
|
167
|
+
async verifyWebhook(event) {
|
|
168
|
+
// Verify HMAC/signature with a server-side secret and constant-time comparison.
|
|
169
|
+
// Never leave this as a permissive stub in production.
|
|
170
|
+
return verifyMyPlatformSignature(event);
|
|
171
|
+
},
|
|
172
|
+
async parseIncomingMessage(event) {
|
|
173
|
+
// Map raw payload → IncomingMessage, or null to ignore
|
|
174
|
+
return null;
|
|
175
|
+
},
|
|
176
|
+
async sendResponse(message, context) {
|
|
177
|
+
// POST back to the platform's API
|
|
178
|
+
},
|
|
179
|
+
formatAgentResponse(text) {
|
|
180
|
+
return { text, platformContext: {} };
|
|
181
|
+
},
|
|
182
|
+
async getStatus(baseUrl) {
|
|
183
|
+
return { platform: "myplatform", label: "MyPlatform", enabled: false, configured: false };
|
|
184
|
+
},
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
2. **Register it** in `getDefaultAdapters()` inside `plugin.ts`. The webhook,
|
|
190
|
+
queue, processor, and retry job are shared infrastructure — you do not
|
|
191
|
+
write any of that per-adapter.
|
|
192
|
+
|
|
193
|
+
3. **Declare required env keys** so the secrets/onboarding UI surfaces them.
|
|
194
|
+
See `secrets` and `onboarding` skills.
|
|
195
|
+
|
|
196
|
+
4. **Update the platform's webhook URL** to point at
|
|
197
|
+
`${baseUrl}/_agent-native/integrations/<platform>/webhook`. For platforms
|
|
198
|
+
with a registration API (Telegram), implement `POST /:platform/setup`.
|
|
199
|
+
|
|
200
|
+
Never hardcode bot tokens, signing secrets, verification tokens, webhook URLs,
|
|
201
|
+
channel/customer identifiers, or copied platform payloads with real private data
|
|
202
|
+
inside the adapter, tests, docs, prompts, or fixtures. `getRequiredEnvKeys()`
|
|
203
|
+
declares credential names only. Values come from deployment configuration,
|
|
204
|
+
registered secrets, OAuth, or scoped credential stores, and tests should use
|
|
205
|
+
obvious fake placeholders.
|
|
206
|
+
|
|
207
|
+
The adapter is **only** responsible for:
|
|
208
|
+
|
|
209
|
+
- platform-specific verification (signatures, challenges)
|
|
210
|
+
- payload → `IncomingMessage` mapping
|
|
211
|
+
- agent text → platform format
|
|
212
|
+
- delivering the response back to the platform
|
|
213
|
+
|
|
214
|
+
It does **not** know about the queue, the processor, retries, or the agent
|
|
215
|
+
loop. Those are handled by the shared webhook handler.
|
|
216
|
+
|
|
217
|
+
### Slack non-message events
|
|
218
|
+
|
|
219
|
+
Slack's Events API also sends events that are not agent messages, such as
|
|
220
|
+
`link_shared` for app unfurls. Do not map those into `IncomingMessage` unless
|
|
221
|
+
they should actually run the agent. Handle them as short, provider-specific
|
|
222
|
+
webhook work: verify the Slack signature, return `200 OK` quickly, and call the
|
|
223
|
+
provider API needed for the event (`chat.unfurl` for link previews). If a single
|
|
224
|
+
Slack app must handle both agent chat and app unfurls, put a dispatcher in front
|
|
225
|
+
of the one Slack Events Request URL and route message events to the integration
|
|
226
|
+
webhook flow while routing `link_shared` to the app-specific unfurl handler.
|
|
227
|
+
|
|
228
|
+
## Long-Running Agent Work
|
|
229
|
+
|
|
230
|
+
The processor endpoint runs in a fresh function execution with its own full
|
|
231
|
+
timeout (typically 30–60s on Netlify/Vercel, longer on background-friendly
|
|
232
|
+
hosts). That budget is dedicated entirely to the agent loop — there is no
|
|
233
|
+
platform-side timer racing it.
|
|
234
|
+
|
|
235
|
+
If a single agent run might exceed the function timeout (large multi-step
|
|
236
|
+
plans, deep delegation chains), the agent should:
|
|
237
|
+
|
|
238
|
+
1. Send an interim acknowledgement back to the platform so the user knows the
|
|
239
|
+
request landed (`adapter.sendResponse({ text: "Working on it..." })`).
|
|
240
|
+
2. Persist intermediate state in chat-thread data, application state, or a
|
|
241
|
+
recurring job so the next invocation can pick up where this one left off.
|
|
242
|
+
|
|
243
|
+
The retry job will only re-fire tasks stuck in `processing` for over 5 minutes,
|
|
244
|
+
so a normal long-running reply is safe.
|
|
245
|
+
|
|
246
|
+
## Cross-Platform Considerations
|
|
247
|
+
|
|
248
|
+
- **No platform-specific background APIs.** No `waitUntil`, no
|
|
249
|
+
`-background.ts` filenames, no Vercel `after()`. The pattern works
|
|
250
|
+
identically on every host because it only uses `fetch()` and SQL.
|
|
251
|
+
- **No assumed runtime.** The processor endpoint is a normal H3 handler under
|
|
252
|
+
`/_agent-native/`. It runs wherever the rest of the framework runs.
|
|
253
|
+
- **No persistent in-memory state.** The dedup map in the webhook handler is
|
|
254
|
+
best-effort only; the SQL queue is the source of truth. Any cold start
|
|
255
|
+
loses the dedup map but the queue stays consistent.
|
|
256
|
+
- **Postgres + SQLite both supported.** `claimPendingTask` uses `RETURNING` on
|
|
257
|
+
Postgres and a re-read on SQLite. No platform-specific SQL.
|
|
258
|
+
- **Self-webhook URL resolution.** The processor URL is built from
|
|
259
|
+
`WEBHOOK_BASE_URL`, `APP_URL`, or `URL` env vars (with `localhost:3000` as
|
|
260
|
+
the dev fallback). Templates that change their public URL must keep one of
|
|
261
|
+
these set.
|
|
262
|
+
|
|
263
|
+
## Why Fire-and-Forget on Serverless Is Unreliable
|
|
264
|
+
|
|
265
|
+
Even though the webhook handler does `fetch(processorUrl, ...)` without
|
|
266
|
+
awaiting the response body, that initial dispatch is **not** guaranteed to
|
|
267
|
+
complete before the function freezes. In practice it usually does — the TCP
|
|
268
|
+
connect + write happens quickly — but the recurring retry job is the safety
|
|
269
|
+
net for the cases where:
|
|
270
|
+
|
|
271
|
+
- The serverless platform froze the handler before the outbound `fetch`
|
|
272
|
+
flushed its bytes.
|
|
273
|
+
- The processor function 502'd or cold-started slow enough to time out.
|
|
274
|
+
- The processor itself was killed mid-agent-loop (function timeout, container
|
|
275
|
+
shutdown, deploy mid-run).
|
|
276
|
+
|
|
277
|
+
Tasks stuck in `pending` for >90s or `processing` for >5min get re-fired up to
|
|
278
|
+
3 times. After 3 attempts they're marked `failed` permanently so we stop
|
|
279
|
+
spamming the processor.
|
|
280
|
+
|
|
281
|
+
**Never assume the initial fire-and-forget succeeded.** Always rely on the
|
|
282
|
+
queue + retry job for at-least-once delivery.
|
|
283
|
+
|
|
284
|
+
## Debugging Checklist
|
|
285
|
+
|
|
286
|
+
1. **Platform sent the webhook?** Check the platform's delivery logs (Slack
|
|
287
|
+
admin, Telegram `getWebhookInfo`).
|
|
288
|
+
2. **Webhook handler returned 200?** If not, the platform retries — look for
|
|
289
|
+
duplicate task rows. Signature failures return 401.
|
|
290
|
+
3. **Task in the queue?** `SELECT * FROM integration_pending_tasks WHERE
|
|
291
|
+
external_thread_id = '...' ORDER BY created_at DESC LIMIT 5`.
|
|
292
|
+
4. **Status?** `pending` means the processor never picked it up — check that
|
|
293
|
+
`_process-task` is reachable from the box itself (the self-fetch must work
|
|
294
|
+
over the public URL). `processing` for over 5 minutes means the processor
|
|
295
|
+
died mid-run — the retry job will pick it up.
|
|
296
|
+
5. **Failed?** Check `error_message` and `attempts`. After 3 attempts the row
|
|
297
|
+
is parked at `failed` and won't be retried.
|
|
298
|
+
6. **Reply not delivered?** The processor likely succeeded but
|
|
299
|
+
`adapter.sendResponse` failed — check the adapter's outbound logs.
|
|
300
|
+
|
|
301
|
+
## Automation connectors
|
|
302
|
+
|
|
303
|
+
Workflow systems such as n8n and Zapier are not messaging channels. Do not add
|
|
304
|
+
them as `PlatformAdapter`s or route them through `provider-api`.
|
|
305
|
+
|
|
306
|
+
For n8n-style workflow invocation and callbacks, use
|
|
307
|
+
`@agent-native/core/automation` with static workflow IDs and allow-listed
|
|
308
|
+
origins. Agents provide structured input, never a target URL or credential.
|
|
309
|
+
Callbacks must verify a configured secret/signature, claim a durable event ID,
|
|
310
|
+
enqueue work through the established queue, and acknowledge quickly.
|
|
311
|
+
|
|
312
|
+
Zapier is blueprint-only unless the app implements Zapier's explicit REST Hook
|
|
313
|
+
subscribe/unsubscribe contract or configures a separate Zapier MCP connection.
|
|
314
|
+
Do not imply a generic Zapier workflow-execution API exists.
|
|
315
|
+
|
|
316
|
+
## Related Skills
|
|
317
|
+
|
|
318
|
+
- `server-plugins` — How `/_agent-native/` routes get mounted
|
|
319
|
+
- `recurring-jobs` — Pattern the retry job follows
|
|
320
|
+
- `actions` — When to use an action vs a webhook
|
|
321
|
+
- `secrets` — Registering platform tokens
|
|
322
|
+
- `onboarding` — Surfacing setup steps for each platform
|
|
323
|
+
- `delegate-to-agent` — How the processor invokes the agent loop
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: onboarding
|
|
3
|
+
description: >-
|
|
4
|
+
How to register user-facing setup steps (API keys, OAuth, connecting
|
|
5
|
+
third-party services) for the sidebar setup checklist. Use when adding a
|
|
6
|
+
feature that needs initial user configuration.
|
|
7
|
+
scope: dev
|
|
8
|
+
metadata:
|
|
9
|
+
internal: true
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Onboarding Steps
|
|
13
|
+
|
|
14
|
+
## Rule
|
|
15
|
+
|
|
16
|
+
If a feature requires user-facing setup (API keys, OAuth, connecting a third-party service), register an onboarding step so it appears in the agent sidebar's setup checklist.
|
|
17
|
+
|
|
18
|
+
Onboarding must point users to a secure credential path; it must never encode
|
|
19
|
+
the credential value in source, docs, fixtures, prompts, or generated content.
|
|
20
|
+
For API keys and service tokens, prefer `registerRequiredSecret()` from the
|
|
21
|
+
`secrets` skill so the settings UI, encrypted storage, validation, and
|
|
22
|
+
onboarding checklist stay in one place. For OAuth, check the scoped OAuth token
|
|
23
|
+
store. Use deployment env vars only for deploy-level configuration, not
|
|
24
|
+
per-user credentials.
|
|
25
|
+
|
|
26
|
+
## Registering a Step
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
import { registerOnboardingStep } from "@agent-native/core/onboarding";
|
|
30
|
+
import { hasOAuthTokens } from "@agent-native/core/oauth-tokens";
|
|
31
|
+
|
|
32
|
+
registerOnboardingStep({
|
|
33
|
+
id: "gmail",
|
|
34
|
+
order: 100,
|
|
35
|
+
title: "Connect Gmail",
|
|
36
|
+
description: "Grant read/send access.",
|
|
37
|
+
methods: [
|
|
38
|
+
{
|
|
39
|
+
id: "oauth",
|
|
40
|
+
kind: "link",
|
|
41
|
+
primary: true,
|
|
42
|
+
label: "Sign in with Google",
|
|
43
|
+
payload: { url: "/_agent-native/google/auth-url" },
|
|
44
|
+
},
|
|
45
|
+
],
|
|
46
|
+
isComplete: async (ctx) =>
|
|
47
|
+
ctx?.userEmail ? hasOAuthTokens("google", ctx.userEmail) : false,
|
|
48
|
+
});
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
See `packages/core/docs/content/onboarding.md` for method kinds and built-in steps.
|
|
52
|
+
|
|
53
|
+
## Related Skills
|
|
54
|
+
|
|
55
|
+
- `adding-a-feature` — The four-area checklist; onboarding is often part of a new integration
|
|
56
|
+
- `authentication` — Most onboarding steps involve OAuth or credentials
|
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: secrets
|
|
3
|
+
description: >-
|
|
4
|
+
Declaratively register API keys and service credentials a template needs so
|
|
5
|
+
they appear in the agent sidebar settings UI and the onboarding checklist.
|
|
6
|
+
Use for any third-party API key (OpenAI, Stripe, Twilio, etc.) and for
|
|
7
|
+
surfacing OAuth connections in the unified settings UI.
|
|
8
|
+
scope: dev
|
|
9
|
+
metadata:
|
|
10
|
+
internal: true
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# Secrets Registry
|
|
14
|
+
|
|
15
|
+
## Non-negotiable rule
|
|
16
|
+
|
|
17
|
+
Never hardcode credential values. Source, docs, tests, fixtures, prompts, seed
|
|
18
|
+
data, and generated extension/app content may mention credential **names** such
|
|
19
|
+
as `OPENAI_API_KEY`, but must not contain real API keys, tokens, webhook URLs,
|
|
20
|
+
signing secrets, OAuth refresh tokens, or private Builder/customer data.
|
|
21
|
+
|
|
22
|
+
Secret values are supplied at runtime through deployment configuration, the
|
|
23
|
+
encrypted `app_secrets` vault, `saveCredential` / `resolveCredential`, OAuth, or
|
|
24
|
+
`${keys.NAME}` substitution. Examples must use obvious placeholders such as
|
|
25
|
+
`<OPENAI_API_KEY>` or `${keys.SLACK_WEBHOOK}`, not real-looking copied values.
|
|
26
|
+
|
|
27
|
+
## When to use
|
|
28
|
+
|
|
29
|
+
Use this for any external credential your template needs: API keys, service
|
|
30
|
+
tokens, webhook secrets. It gives you:
|
|
31
|
+
|
|
32
|
+
- A sidebar UI entry for each credential (masked input, rotate, test, delete).
|
|
33
|
+
- Automatic onboarding-checklist items for `required: true` secrets.
|
|
34
|
+
- A stable server-side read API (`readAppSecret`) that decrypts values on
|
|
35
|
+
demand.
|
|
36
|
+
- Validator hooks for health-checking keys before save and from a Test button.
|
|
37
|
+
|
|
38
|
+
## When NOT to use
|
|
39
|
+
|
|
40
|
+
- OAuth flows that need to run the full authorization code exchange — use
|
|
41
|
+
`@agent-native/core/oauth-tokens` directly to save/refresh tokens. The
|
|
42
|
+
registry can still surface the OAuth connection in the sidebar by
|
|
43
|
+
registering a secret with `kind: "oauth"` — that just delegates status
|
|
44
|
+
lookup to oauth-tokens and renders a Connect button, no `app_secrets` row
|
|
45
|
+
is written.
|
|
46
|
+
- Purely process-level env vars that are never user-facing (e.g. `NODE_ENV`,
|
|
47
|
+
deployment flags). Those belong in the onboarding `form` method or the
|
|
48
|
+
`envKeys` list in `core-routes-plugin`.
|
|
49
|
+
|
|
50
|
+
## Registering a secret
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
// server/plugins/register-secrets.ts
|
|
54
|
+
import { defineNitroPlugin } from "@agent-native/core/server";
|
|
55
|
+
import { registerRequiredSecret } from "@agent-native/core/secrets";
|
|
56
|
+
|
|
57
|
+
export default defineNitroPlugin(() => {
|
|
58
|
+
registerRequiredSecret({
|
|
59
|
+
key: "OPENAI_API_KEY",
|
|
60
|
+
label: "OpenAI API Key",
|
|
61
|
+
description: "Used for Whisper transcription of your recordings.",
|
|
62
|
+
docsUrl: "https://platform.openai.com/api-keys",
|
|
63
|
+
scope: "user",
|
|
64
|
+
kind: "api-key",
|
|
65
|
+
required: true,
|
|
66
|
+
validator: async (value) => {
|
|
67
|
+
const res = await fetch("https://api.openai.com/v1/models", {
|
|
68
|
+
headers: { Authorization: `Bearer ${value}` },
|
|
69
|
+
});
|
|
70
|
+
return res.ok
|
|
71
|
+
? { ok: true }
|
|
72
|
+
: { ok: false, error: `OpenAI rejected the key (HTTP ${res.status})` };
|
|
73
|
+
},
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### OAuth in the unified UI
|
|
79
|
+
|
|
80
|
+
```ts
|
|
81
|
+
registerRequiredSecret({
|
|
82
|
+
key: "GOOGLE_CONNECTED",
|
|
83
|
+
label: "Google account",
|
|
84
|
+
description: "Grants access to Gmail / Calendar APIs.",
|
|
85
|
+
scope: "user",
|
|
86
|
+
kind: "oauth",
|
|
87
|
+
required: true,
|
|
88
|
+
oauthProvider: "google", // must match the provider id in oauth-tokens
|
|
89
|
+
oauthConnectUrl: "/_agent-native/google/auth-url",
|
|
90
|
+
});
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
The sidebar shows a Connect button instead of a text input; no `app_secrets`
|
|
94
|
+
row is written — status is derived from `hasOAuthTokens("google")`.
|
|
95
|
+
|
|
96
|
+
## Registered options
|
|
97
|
+
|
|
98
|
+
| Field | Type | Purpose |
|
|
99
|
+
| ------------------ | --------------------------------------- | ------------------------------------------------------------------------ |
|
|
100
|
+
| `key` | `string` | Env-var style name (`OPENAI_API_KEY`). Also the storage key. |
|
|
101
|
+
| `label` | `string` | Human-readable title in the sidebar. |
|
|
102
|
+
| `description` | `string?` | Subtitle under the label. |
|
|
103
|
+
| `docsUrl` | `string?` | "Get key" link rendered on the card. |
|
|
104
|
+
| `scope` | `"user" \| "workspace"` | Per-user or shared across the active org. |
|
|
105
|
+
| `kind` | `"api-key" \| "oauth"` | Drives UI and storage behavior. |
|
|
106
|
+
| `required` | `boolean?` | When true, an onboarding step is auto-injected. |
|
|
107
|
+
| `validator` | `(v) => Promise<boolean \| {ok,error}>` | Runs on save and from the Test button. Never log `v`. |
|
|
108
|
+
| `oauthProvider` | `string?` (oauth-kind only) | Provider id in `oauth-tokens` that backs this entry. |
|
|
109
|
+
| `oauthConnectUrl` | `string?` (oauth-kind only) | URL the Connect button points at. |
|
|
110
|
+
|
|
111
|
+
## Reading a secret from an action
|
|
112
|
+
|
|
113
|
+
```ts
|
|
114
|
+
import { z } from "zod";
|
|
115
|
+
import { defineAction } from "@agent-native/core/action";
|
|
116
|
+
import { readAppSecret } from "@agent-native/core/secrets";
|
|
117
|
+
import { getRequestUserEmail } from "@agent-native/core/server";
|
|
118
|
+
|
|
119
|
+
export default defineAction({
|
|
120
|
+
description: "Transcribe an audio file with Whisper",
|
|
121
|
+
schema: z.object({ fileUrl: z.string() }),
|
|
122
|
+
run: async ({ fileUrl }) => {
|
|
123
|
+
const email = await getRequestUserEmail();
|
|
124
|
+
if (!email) throw new Error("Not signed in");
|
|
125
|
+
|
|
126
|
+
const stored = await readAppSecret({
|
|
127
|
+
key: "OPENAI_API_KEY",
|
|
128
|
+
scope: "user",
|
|
129
|
+
scopeId: email,
|
|
130
|
+
});
|
|
131
|
+
const apiKey = stored?.value;
|
|
132
|
+
if (!apiKey) {
|
|
133
|
+
throw new Error(
|
|
134
|
+
"OPENAI_API_KEY is not set. Configure it in the sidebar settings.",
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// …call OpenAI. NEVER log the key or include it in error messages.
|
|
139
|
+
},
|
|
140
|
+
});
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Rules:
|
|
144
|
+
|
|
145
|
+
- **Never log the value.** The read layer enforces this server-side; your
|
|
146
|
+
code must do the same.
|
|
147
|
+
- **Use env vars only for deploy-level secrets.** If a credential is
|
|
148
|
+
user-scoped, org-scoped, or workspace-scoped, read the scoped vault/credential
|
|
149
|
+
store. Do not add a `process.env` fallback that makes every user inherit one
|
|
150
|
+
deployment's key.
|
|
151
|
+
- **Scope matches the registration.** `scope: "user"` → pass the user email.
|
|
152
|
+
`scope: "workspace"` → pass the active `orgId` from
|
|
153
|
+
`getOrgContext(event).orgId`.
|
|
154
|
+
|
|
155
|
+
## HTTP routes
|
|
156
|
+
|
|
157
|
+
Core routes plugin mounts these under `/_agent-native/secrets/` automatically:
|
|
158
|
+
|
|
159
|
+
- `GET /_agent-native/secrets` — list registered secrets with status (`set`
|
|
160
|
+
/ `unset` / `invalid`), metadata, and — for set api-keys — the last 4
|
|
161
|
+
characters. Values are never returned.
|
|
162
|
+
- `POST /_agent-native/secrets/:key` — body `{ value, scope?, scopeId? }`.
|
|
163
|
+
Runs the registered validator; returns 400 with the error on failure.
|
|
164
|
+
- `DELETE /_agent-native/secrets/:key` — remove the stored value.
|
|
165
|
+
- `POST /_agent-native/secrets/:key/test` — re-run the validator against the
|
|
166
|
+
currently stored value.
|
|
167
|
+
|
|
168
|
+
## Storage & encryption
|
|
169
|
+
|
|
170
|
+
- Values are stored in `app_secrets` (created on-demand; no migration
|
|
171
|
+
needed).
|
|
172
|
+
- Encrypted at rest with AES-256-GCM. Key material is derived from
|
|
173
|
+
`<APP_NAME>_SECRETS_ENCRYPTION_KEY` when set (for example,
|
|
174
|
+
`ANALYTICS_SECRETS_ENCRYPTION_KEY`), then `SECRETS_ENCRYPTION_KEY`, then
|
|
175
|
+
`BETTER_AUTH_SECRET`. App-scoped keys are useful when a local multi-app
|
|
176
|
+
workspace connects one app to its production database without replacing the
|
|
177
|
+
shared local authentication secret. If none is set, the framework uses a
|
|
178
|
+
machine-local fallback and logs a one-time warning — set stable key material
|
|
179
|
+
in production and in every runtime that reads the same encrypted data.
|
|
180
|
+
|
|
181
|
+
## Ad-hoc Keys
|
|
182
|
+
|
|
183
|
+
Ad-hoc keys are user-created secrets that are not declared by the template.
|
|
184
|
+
Users create them through the settings UI or the agent chat to use with
|
|
185
|
+
automations and the `web-request` tool. They support `${keys.NAME}`
|
|
186
|
+
substitution in outbound HTTP requests.
|
|
187
|
+
|
|
188
|
+
### Ad-hoc API
|
|
189
|
+
|
|
190
|
+
Core routes plugin mounts these under `/_agent-native/secrets/adhoc`:
|
|
191
|
+
|
|
192
|
+
- `GET /_agent-native/secrets/adhoc` — list all ad-hoc keys (name, last 4
|
|
193
|
+
chars, URL allowlist). Values are never returned.
|
|
194
|
+
- `POST /_agent-native/secrets/adhoc` — body `{ name, value, urlAllowlist? }`.
|
|
195
|
+
Creates or updates an ad-hoc key.
|
|
196
|
+
- `DELETE /_agent-native/secrets/adhoc/:name` — remove an ad-hoc key.
|
|
197
|
+
|
|
198
|
+
### URL Allowlists
|
|
199
|
+
|
|
200
|
+
Each ad-hoc key can have a URL allowlist — an array of origin URLs that
|
|
201
|
+
restrict where the key's value can be sent. The check is origin-level
|
|
202
|
+
(scheme + host + port). If no allowlist is configured, the key can be used
|
|
203
|
+
with any URL.
|
|
204
|
+
|
|
205
|
+
```ts
|
|
206
|
+
// Creating a key with an allowlist
|
|
207
|
+
POST /_agent-native/secrets/adhoc
|
|
208
|
+
{
|
|
209
|
+
"name": "SLACK_WEBHOOK",
|
|
210
|
+
"value": "<SLACK_WEBHOOK_URL_FROM_SETTINGS>",
|
|
211
|
+
"urlAllowlist": ["https://hooks.slack.com"]
|
|
212
|
+
}
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### `${keys.NAME}` Substitution
|
|
216
|
+
|
|
217
|
+
The `web-request` tool supports `${keys.NAME}` placeholders in the URL,
|
|
218
|
+
headers, and body. Substitution happens server-side after the agent emits
|
|
219
|
+
the tool call — the raw secret value never enters the agent's context.
|
|
220
|
+
|
|
221
|
+
```ts
|
|
222
|
+
import {
|
|
223
|
+
resolveKeyReferences,
|
|
224
|
+
validateUrlAllowlist,
|
|
225
|
+
} from "@agent-native/core/secrets/substitution";
|
|
226
|
+
|
|
227
|
+
// Resolve all ${keys.NAME} references in a string
|
|
228
|
+
const { resolved, usedKeys } = await resolveKeyReferences(
|
|
229
|
+
"Bearer ${keys.API_TOKEN}",
|
|
230
|
+
"user",
|
|
231
|
+
"user@example.com",
|
|
232
|
+
);
|
|
233
|
+
|
|
234
|
+
// Validate a URL against a key's allowlist
|
|
235
|
+
const allowed = validateUrlAllowlist(
|
|
236
|
+
"https://hooks.slack.com/services/<WORKSPACE>/<CHANNEL>/<SECRET>",
|
|
237
|
+
["https://hooks.slack.com"],
|
|
238
|
+
);
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
Key resolution falls back from user scope to workspace scope, so users can
|
|
242
|
+
override shared keys without breaking automations that reference workspace
|
|
243
|
+
defaults.
|
|
244
|
+
|
|
245
|
+
## Dispatch Vault Access
|
|
246
|
+
|
|
247
|
+
Dispatch workspaces have a vault access policy for workspace app credentials:
|
|
248
|
+
|
|
249
|
+
- `all-apps` is the default. Every saved Dispatch vault key is available to
|
|
250
|
+
every workspace app; `sync-vault-to-app` pushes all vault keys to the target
|
|
251
|
+
app.
|
|
252
|
+
- `manual` requires explicit per-app grants. Use
|
|
253
|
+
`create-vault-grant` / `grant-vault-secrets-to-app`, then
|
|
254
|
+
`sync-vault-to-app`.
|
|
255
|
+
|
|
256
|
+
Use `get-vault-access-settings` before deciding whether to create grants, and
|
|
257
|
+
use `set-vault-access-settings` only when the user asks to change the policy.
|
|
258
|
+
|
|
259
|
+
### Key Files (ad-hoc)
|
|
260
|
+
|
|
261
|
+
| File | Purpose |
|
|
262
|
+
| ---------------------------------------------- | ------------------------------------------- |
|
|
263
|
+
| `packages/core/src/secrets/substitution.ts` | `resolveKeyReferences()`, `validateUrlAllowlist()` |
|
|
264
|
+
| `packages/core/src/tools/fetch-tool.ts` | `web-request` tool consuming key references |
|
|
265
|
+
|
|
266
|
+
## Related skills
|
|
267
|
+
|
|
268
|
+
- `onboarding` — the setup checklist that required secrets show up in.
|
|
269
|
+
- `actions` — where you'll read secrets when calling third-party APIs.
|
|
270
|
+
- `authentication` — session scoping; `scope: "user"` uses the session
|
|
271
|
+
email.
|
|
272
|
+
- `security` — input validation and never logging secrets.
|
|
273
|
+
- `automations` — ad-hoc keys power `${keys.NAME}` in automation web requests.
|