@vellumai/assistant 0.8.7 → 0.8.8
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/Dockerfile +20 -4
- package/docker-entrypoint.sh +4 -2
- package/docker-init-apt-root.sh +3 -1
- package/docker-kata-apt-env.sh +3 -1
- package/docker-kata-runtime-family.sh +12 -0
- package/docs/architecture/memory.md +1 -1
- package/docs/plugins.md +75 -79
- package/examples/plugins/echo/README.md +6 -12
- package/examples/plugins/echo/register.ts +0 -41
- package/node_modules/@vellumai/skill-host-contracts/src/server-message.ts +3 -3
- package/openapi.yaml +3381 -348
- package/package.json +1 -1
- package/scripts/generate-openapi.ts +68 -41
- package/src/__tests__/agent-loop-exit-reason.test.ts +34 -39
- package/src/__tests__/agent-loop-provider-error-recording.test.ts +1 -1
- package/src/__tests__/agent-loop.test.ts +37 -87
- package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +2 -0
- package/src/__tests__/annotate-activity-metadata.test.ts +262 -0
- package/src/__tests__/annotate-risk-options.test.ts +2 -3
- package/src/__tests__/anthropic-provider.test.ts +95 -2
- package/src/__tests__/assistant-event-hub.test.ts +25 -0
- package/src/__tests__/assistant-events-sse-shed.test.ts +8 -0
- package/src/__tests__/{conversation-stream-state.test.ts → assistant-stream-state.test.ts} +252 -91
- package/src/__tests__/auth-fallback-events-store.test.ts +116 -0
- package/src/__tests__/background-workers-disk-pressure.test.ts +6 -0
- package/src/__tests__/btw-routes.test.ts +62 -3
- package/src/__tests__/build-persisted-content.test.ts +184 -0
- package/src/__tests__/catalog-files.test.ts +1 -1
- package/src/__tests__/clawhub-files.test.ts +1 -1
- package/src/__tests__/compaction-pipeline.test.ts +1 -1
- package/src/__tests__/compaction.benchmark.test.ts +0 -30
- package/src/__tests__/config-watcher.test.ts +1 -1
- package/src/__tests__/conversation-abort-tool-results.test.ts +57 -19
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +6 -2
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +10 -4
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +313 -1136
- package/src/__tests__/conversation-agent-loop.test.ts +596 -1616
- package/src/__tests__/conversation-analysis-routes.test.ts +6 -0
- package/src/__tests__/conversation-history-web-search.test.ts +11 -1
- package/src/__tests__/conversation-pairing.test.ts +4 -31
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +6 -0
- package/src/__tests__/conversation-provider-retry-repair.test.ts +26 -5
- package/src/__tests__/conversation-queue.test.ts +2 -0
- package/src/__tests__/conversation-routes-disk-view.test.ts +3 -0
- package/src/__tests__/conversation-routes-slash-commands.test.ts +6 -5
- package/src/__tests__/conversation-runtime-assembly.test.ts +170 -229
- package/src/__tests__/conversation-runtime-workspace.test.ts +3 -24
- package/src/__tests__/conversation-slash-commands.test.ts +8 -42
- package/src/__tests__/conversation-slash-queue.test.ts +6 -1
- package/src/__tests__/conversation-surfaces-action-delivery.test.ts +84 -0
- package/src/__tests__/conversation-sync-tags.test.ts +27 -15
- package/src/__tests__/conversation-title-service.test.ts +135 -2
- package/src/__tests__/conversation-workspace-injection.test.ts +6 -1
- package/src/__tests__/cross-provider-web-search.test.ts +214 -1
- package/src/__tests__/db-schedule-syntax-migration.test.ts +5 -0
- package/src/__tests__/dm-persistence.test.ts +5 -1
- package/src/__tests__/empty-response-hook.test.ts +304 -0
- package/src/__tests__/feature-flag-test-helpers.ts +2 -2
- package/src/__tests__/gemini-image-service.test.ts +13 -0
- package/src/__tests__/helpers/mock-provider.ts +110 -0
- package/src/__tests__/helpers/native-web-search-harness.ts +129 -0
- package/src/__tests__/history-repair-hook.test.ts +1 -0
- package/src/__tests__/identity-intro-cache.test.ts +12 -100
- package/src/__tests__/identity-routes.test.ts +248 -7
- package/src/__tests__/inbound-slack-persistence.test.ts +5 -1
- package/src/__tests__/injector-background-turn.test.ts +2 -8
- package/src/__tests__/injector-chain.test.ts +106 -270
- package/src/__tests__/injector-disk-pressure.test.ts +3 -12
- package/src/__tests__/injector-document-comments.test.ts +2 -2
- package/src/__tests__/injector-pkb-v2-silenced.test.ts +30 -22
- package/src/__tests__/injector-v3-suppression.test.ts +31 -37
- package/src/__tests__/internal-telemetry-routes.test.ts +109 -0
- package/src/__tests__/list-messages-page-latest.test.ts +60 -0
- package/src/__tests__/list-messages-tool-merge.test.ts +20 -0
- package/src/__tests__/llm-usage-store.test.ts +223 -1
- package/src/__tests__/memory-retrieval-hook.test.ts +297 -0
- package/src/__tests__/memory-v2-static-injector.test.ts +103 -35
- package/src/__tests__/native-web-search.test.ts +191 -0
- package/src/__tests__/onboarding-template-contract.test.ts +2 -0
- package/src/__tests__/openai-image-service.test.ts +17 -0
- package/src/__tests__/openai-provider.test.ts +31 -1
- package/src/__tests__/persist-unsendable-image.test.ts +215 -0
- package/src/__tests__/persistence-secret-redaction.test.ts +1 -0
- package/src/__tests__/pipeline-runner.test.ts +29 -39
- package/src/__tests__/pkb-autoinject.test.ts +2 -5
- package/src/__tests__/plugin-bootstrap.test.ts +13 -28
- package/src/__tests__/plugin-registry.test.ts +0 -27
- package/src/__tests__/plugin-types.test.ts +2 -125
- package/src/__tests__/process-message-display-content.test.ts +6 -2
- package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +5 -1
- package/src/__tests__/resolve-trust-class.test.ts +4 -4
- package/src/__tests__/runtime-events-sse-reconnect.test.ts +60 -23
- package/src/__tests__/schedule-routes.test.ts +603 -2
- package/src/__tests__/schedule-store.test.ts +41 -0
- package/src/__tests__/schedule-tools.test.ts +35 -0
- package/src/__tests__/server-history-render.test.ts +314 -1
- package/src/__tests__/skillssh-files.test.ts +1 -1
- package/src/__tests__/system-prompt.test.ts +20 -0
- package/src/__tests__/task-scheduler.test.ts +162 -1
- package/src/__tests__/terminal-tools.test.ts +6 -1
- package/src/__tests__/title-generate-hook.test.ts +319 -0
- package/src/__tests__/tool-error-hook.test.ts +278 -0
- package/src/__tests__/tool-preview-lifecycle.test.ts +468 -5
- package/src/__tests__/tool-result-metadata-plumbing.test.ts +1 -0
- package/src/__tests__/tool-result-truncate-hook.test.ts +127 -0
- package/src/__tests__/tool-result-truncation.test.ts +0 -2
- package/src/__tests__/ui-choice-copy-surfaces.test.ts +254 -0
- package/src/__tests__/ui-work-result-surface.test.ts +159 -0
- package/src/__tests__/usage-routes.test.ts +285 -1
- package/src/__tests__/user-plugin-loader.test.ts +2 -2
- package/src/__tests__/voice-session-bridge.test.ts +6 -3
- package/src/__tests__/web-search-backend-failure.test.ts +166 -0
- package/src/agent/loop.ts +346 -442
- package/src/api/events/assistant-thinking-delta.ts +33 -0
- package/src/api/events/tool-output-chunk.ts +45 -0
- package/src/api/events/tool-use-preview-start.ts +32 -0
- package/src/api/events/trace-event.ts +69 -0
- package/src/api/index.ts +48 -13
- package/src/api/responses/conversation-message.ts +368 -0
- package/src/avatar/__tests__/avatar-store.test.ts +34 -29
- package/src/cli/commands/__tests__/notifications.test.ts +58 -14
- package/src/cli/commands/notifications.ts +112 -60
- package/src/config/assistant-feature-flags.ts +22 -11
- package/src/config/bundled-skills/app-builder/SKILL.md +3 -20
- package/src/config/bundled-skills/app-builder/references/examples/README.md +17 -0
- package/src/config/bundled-skills/app-builder/references/examples/expense-tracker.md +515 -0
- package/src/config/bundled-skills/app-builder/references/examples/focus-timer.md +342 -0
- package/src/config/bundled-skills/app-builder/references/examples/habit-tracker.md +490 -0
- package/src/config/bundled-skills/document-editor/SKILL.md +1 -1
- package/src/config/bundled-skills/messaging/SKILL.md +0 -7
- package/src/config/feature-flag-cache.ts +3 -3
- package/src/config/feature-flag-registry.json +35 -3
- package/src/config/schemas/__tests__/memory-v2.test.ts +1 -0
- package/src/config/schemas/__tests__/memory-v3.test.ts +25 -0
- package/src/config/schemas/llm.ts +1 -0
- package/src/config/schemas/memory-v2.ts +8 -0
- package/src/config/schemas/memory-v3.ts +8 -0
- package/src/config/schemas/platform.ts +8 -0
- package/src/config/seed-inference-profiles.ts +2 -2
- package/src/config/skills.ts +13 -0
- package/src/context/compactor.ts +1 -1
- package/src/context/strip-injections.ts +122 -0
- package/src/context/token-estimator.ts +23 -0
- package/src/context/tool-result-truncation.ts +0 -23
- package/src/context/window-manager.ts +3 -6
- package/src/credential-execution/executable-discovery.ts +16 -0
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +6 -0
- package/src/daemon/__tests__/inference-profile-notification.test.ts +153 -0
- package/src/daemon/__tests__/native-web-search-metadata.test.ts +10 -8
- package/src/daemon/assistant-attachments.ts +1 -1
- package/src/daemon/config-watcher.ts +2 -2
- package/src/daemon/context-overflow-reducer.ts +0 -1
- package/src/daemon/conversation-agent-loop-handlers.ts +605 -153
- package/src/daemon/conversation-agent-loop.ts +281 -760
- package/src/daemon/conversation-history.ts +5 -4
- package/src/daemon/conversation-lifecycle.ts +3 -4
- package/src/daemon/conversation-messaging.ts +7 -6
- package/src/daemon/conversation-process.ts +11 -16
- package/src/daemon/conversation-runtime-assembly.ts +130 -347
- package/src/daemon/conversation-slash.ts +6 -25
- package/src/daemon/conversation-surfaces.ts +222 -4
- package/src/daemon/conversation-tool-setup.ts +2 -29
- package/src/daemon/conversation.ts +32 -14
- package/src/daemon/external-plugins-bootstrap.ts +9 -10
- package/src/daemon/handlers/config-a2a.ts +51 -36
- package/src/daemon/handlers/config-slack-channel.ts +20 -14
- package/src/daemon/handlers/config-telegram.ts +16 -2
- package/src/daemon/handlers/shared.ts +156 -84
- package/src/daemon/handlers/skills.ts +39 -10
- package/src/daemon/lifecycle.ts +4 -0
- package/src/daemon/message-types/apps.ts +1 -29
- package/src/daemon/message-types/messages.ts +9 -57
- package/src/daemon/message-types/skills.ts +2 -0
- package/src/daemon/message-types/surfaces.ts +136 -3
- package/src/daemon/now-scratchpad.ts +21 -0
- package/src/daemon/orphan-reaper.test.ts +210 -0
- package/src/daemon/orphan-reaper.ts +240 -0
- package/src/daemon/persist-unsendable-image.ts +117 -0
- package/src/daemon/process-message.ts +1 -3
- package/src/daemon/trace-emitter.ts +6 -4
- package/src/daemon/trust-context.ts +19 -0
- package/src/daemon/wake-target-adapter.ts +3 -1
- package/src/home/home-greeting-cache.ts +24 -1
- package/src/ipc/gateway-client.test.ts +2 -2
- package/src/ipc/gateway-client.ts +3 -3
- package/src/media/gemini-image-service.ts +15 -0
- package/src/media/openai-image-service.ts +14 -0
- package/src/media/types.ts +34 -0
- package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +56 -0
- package/src/memory/auth-fallback-events-store.ts +94 -0
- package/src/memory/conversation-title-service.ts +65 -41
- package/src/memory/db-init.ts +4 -0
- package/src/memory/graph/__tests__/conversation-graph-memory-registry.test.ts +119 -0
- package/src/memory/graph/conversation-graph-memory.ts +65 -0
- package/src/memory/jobs-store.ts +33 -0
- package/src/memory/jobs-worker.ts +31 -4
- package/src/memory/llm-usage-store.ts +224 -50
- package/src/memory/migrations/222-strip-placeholder-sentinels-from-messages.ts +6 -5
- package/src/memory/migrations/270-schedule-source-conversation.ts +13 -0
- package/src/memory/migrations/271-create-auth-fallback-events.ts +21 -0
- package/src/memory/migrations/index.ts +2 -0
- package/src/memory/pkb/autoinject.ts +61 -0
- package/src/memory/pkb/context.ts +50 -0
- package/src/memory/pkb/types.ts +14 -0
- package/src/memory/schedule-attribution-sql.ts +104 -0
- package/src/memory/schema/infrastructure.ts +16 -0
- package/src/memory/usage-grouped-buckets.ts +6 -1
- package/src/memory/v2/__tests__/consolidation-job.test.ts +1 -1
- package/src/memory/v2/consolidation-job.ts +1 -1
- package/src/memory/v3/__tests__/health.test.ts +16 -0
- package/src/memory/v3/__tests__/orchestrate.test.ts +45 -9
- package/src/memory/v3/__tests__/provider-blocks.test.ts +13 -0
- package/src/memory/v3/__tests__/router.test.ts +101 -29
- package/src/memory/v3/__tests__/selector.test.ts +93 -27
- package/src/memory/v3/__tests__/shadow-plugin.test.ts +23 -5
- package/src/memory/v3/health.ts +0 -0
- package/src/memory/v3/llm-retry.ts +32 -0
- package/src/memory/v3/orchestrate.ts +26 -14
- package/src/memory/v3/provider-blocks.ts +15 -5
- package/src/memory/v3/router.ts +48 -42
- package/src/memory/v3/selector.ts +57 -42
- package/src/memory/v3/shadow-plugin.ts +47 -15
- package/src/memory/v3/types.ts +8 -0
- package/src/notifications/conversation-pairing.ts +8 -15
- package/src/notifications/decision-engine.ts +6 -3
- package/src/notifications/home-feed-side-effect.ts +12 -1
- package/src/permissions/prompter.ts +4 -0
- package/src/plugin-api/constants.ts +4 -0
- package/src/plugin-api/index.ts +8 -1
- package/src/plugin-api/types.ts +151 -1
- package/src/plugins/defaults/empty-response/hooks/stop.ts +126 -0
- package/src/plugins/defaults/empty-response/register.ts +8 -13
- package/src/plugins/defaults/index.ts +1 -15
- package/src/plugins/defaults/injectors/register.ts +243 -74
- package/src/plugins/defaults/memory-retrieval/hooks/post-compact.ts +91 -0
- package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit-temp.ts +216 -0
- package/src/plugins/defaults/memory-retrieval/injector-chain.ts +35 -0
- package/src/plugins/defaults/title-generate/hooks/stop.ts +75 -0
- package/src/plugins/defaults/title-generate/hooks/user-prompt-submit.ts +35 -0
- package/src/plugins/defaults/title-generate/package.json +1 -1
- package/src/plugins/defaults/title-generate/register.ts +18 -18
- package/src/plugins/defaults/tool-error/hooks/post-tool-use.ts +118 -0
- package/src/plugins/defaults/tool-error/package.json +1 -1
- package/src/plugins/defaults/tool-error/register.ts +9 -21
- package/src/plugins/defaults/tool-result-truncate/hooks/post-tool-use.ts +32 -0
- package/src/plugins/defaults/tool-result-truncate/register.ts +10 -21
- package/src/plugins/defaults/tool-result-truncate/terminal.ts +37 -18
- package/src/plugins/pipeline.ts +6 -18
- package/src/plugins/registry.ts +8 -25
- package/src/plugins/types.ts +43 -474
- package/src/proactive-artifact/aux-message-injector.ts +3 -3
- package/src/proactive-artifact/job.test.ts +7 -12
- package/src/prompts/__tests__/system-prompt.test.ts +36 -0
- package/src/prompts/templates/BOOTSTRAP-ACTIVATION-RAIL.md +62 -0
- package/src/prompts/templates/BOOTSTRAP.md +2 -2
- package/src/prompts/templates/system-sections.ts +15 -0
- package/src/providers/anthropic/client.ts +37 -29
- package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +112 -0
- package/src/providers/openai/chat-completions-provider.ts +44 -0
- package/src/providers/openrouter/client.ts +1 -0
- package/src/providers/placeholder-sentinels.ts +35 -0
- package/src/runtime/__tests__/agent-wake.test.ts +5 -1
- package/src/runtime/agent-wake.ts +2 -2
- package/src/runtime/assistant-event-hub.ts +36 -6
- package/src/runtime/{conversation-stream-state.ts → assistant-stream-state.ts} +132 -58
- package/src/runtime/http-router.ts +16 -21
- package/src/runtime/http-types.ts +16 -70
- package/src/runtime/pending-interactions.ts +1 -0
- package/src/runtime/routes/__tests__/consolidation-routes.test.ts +265 -2
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +31 -1
- package/src/runtime/routes/__tests__/memory-v2-routes.test.ts +6 -2
- package/src/runtime/routes/__tests__/tts-routes.test.ts +6 -2
- package/src/runtime/routes/app-management-routes.ts +6 -117
- package/src/runtime/routes/app-routes.ts +13 -15
- package/src/runtime/routes/attachment-routes.ts +26 -15
- package/src/runtime/routes/avatar-routes.ts +26 -0
- package/src/runtime/routes/btw-routes.ts +29 -23
- package/src/runtime/routes/consolidation-routes.ts +120 -20
- package/src/runtime/routes/conversation-query-routes.ts +2 -0
- package/src/runtime/routes/conversation-routes.ts +358 -184
- package/src/runtime/routes/documents-routes.ts +4 -0
- package/src/runtime/routes/domain-routes.ts +51 -37
- package/src/runtime/routes/epoch-millis-range.ts +34 -0
- package/src/runtime/routes/events-routes.ts +28 -34
- package/src/runtime/routes/gateway-log-routes.ts +26 -4
- package/src/runtime/routes/heartbeat-routes.ts +32 -12
- package/src/runtime/routes/identity-intro-cache.ts +11 -34
- package/src/runtime/routes/identity-routes.ts +208 -17
- package/src/runtime/routes/image-generation-routes.ts +40 -2
- package/src/runtime/routes/index.ts +2 -0
- package/src/runtime/routes/integrations/a2a.ts +12 -10
- package/src/runtime/routes/integrations/slack/__tests__/channel.test.ts +16 -0
- package/src/runtime/routes/integrations/slack/channel.ts +4 -0
- package/src/runtime/routes/integrations/slack/share.ts +27 -6
- package/src/runtime/routes/integrations/telegram.ts +6 -0
- package/src/runtime/routes/integrations/twilio.ts +42 -0
- package/src/runtime/routes/internal-telemetry-routes.ts +88 -0
- package/src/runtime/routes/log-export-routes.ts +8 -0
- package/src/runtime/routes/memory-v2-routes.ts +15 -8
- package/src/runtime/routes/memory-v3-routes.ts +50 -28
- package/src/runtime/routes/oauth-apps.ts +66 -12
- package/src/runtime/routes/oauth-providers.ts +44 -5
- package/src/runtime/routes/platform-routes.ts +81 -5
- package/src/runtime/routes/playground/__tests__/force-compact.test.ts +6 -4
- package/src/runtime/routes/playground/force-compact.ts +1 -1
- package/src/runtime/routes/rename-conversation-routes.ts +5 -0
- package/src/runtime/routes/schedule-routes.ts +152 -42
- package/src/runtime/routes/secret-routes.ts +14 -2
- package/src/runtime/routes/skills-routes.ts +43 -14
- package/src/runtime/routes/tool-call-confirmation-enrichment.test.ts +161 -0
- package/src/runtime/routes/tool-call-confirmation-enrichment.ts +107 -0
- package/src/runtime/routes/trust-rules-routes.ts +26 -2
- package/src/runtime/routes/tts-routes.ts +35 -0
- package/src/runtime/routes/types.ts +66 -8
- package/src/runtime/routes/usage-routes.ts +47 -39
- package/src/runtime/routes/webhook-routes.ts +41 -2
- package/src/runtime/routes/workspace-routes.ts +4 -0
- package/src/runtime/services/__tests__/analyze-conversation.test.ts +6 -0
- package/src/runtime/services/analyze-conversation.ts +2 -2
- package/src/schedule/schedule-store.ts +20 -1
- package/src/schedule/schedule-usage-store.ts +83 -0
- package/src/schedule/scheduler.ts +12 -5
- package/src/skills/catalog-files.ts +2 -2
- package/src/skills/catalog-install.ts +3 -0
- package/src/skills/categories-cache.ts +118 -0
- package/src/skills/clawhub-files.ts +1 -2
- package/src/skills/skillssh-files.ts +1 -2
- package/src/telemetry/types.ts +29 -1
- package/src/telemetry/usage-telemetry-reporter.test.ts +112 -3
- package/src/telemetry/usage-telemetry-reporter.ts +57 -2
- package/src/tools/executor.ts +1 -53
- package/src/tools/network/__tests__/web-search-metadata.test.ts +7 -1
- package/src/tools/network/__tests__/web-search.test.ts +11 -3
- package/src/tools/network/web-search-error.test.ts +248 -0
- package/src/tools/network/web-search-error.ts +267 -0
- package/src/tools/network/web-search.ts +207 -48
- package/src/tools/schedule/create.ts +2 -0
- package/src/tools/terminal/safe-env.ts +10 -1
- package/src/tools/ui-surface/definitions.ts +9 -1
- package/src/tts/__tests__/provider-catalog-consistency.test.ts +85 -1
- package/src/tts/provider-catalog.ts +76 -1
- package/src/util/mutex.ts +47 -0
- package/src/workspace/git-service.ts +1 -42
- package/src/workspace/migrations/095-bump-heartbeat-interval-30m-to-60m.ts +51 -0
- package/src/workspace/migrations/096-reduce-quality-profile-effort.ts +72 -0
- package/src/workspace/migrations/097-enable-adaptive-thinking-managed-profiles.ts +93 -0
- package/src/workspace/migrations/registry.ts +6 -0
- package/src/__tests__/bootstrap-turn-cleanup.test.ts +0 -44
- package/src/__tests__/empty-response-pipeline.test.ts +0 -423
- package/src/__tests__/llm-call-pipeline.test.ts +0 -287
- package/src/__tests__/memory-retrieval-pipeline.test.ts +0 -418
- package/src/__tests__/persistence-pipeline.test.ts +0 -503
- package/src/__tests__/title-generate-pipeline.test.ts +0 -211
- package/src/__tests__/token-estimate-pipeline.test.ts +0 -479
- package/src/__tests__/tool-error-pipeline.test.ts +0 -241
- package/src/__tests__/tool-execute-pipeline.test.ts +0 -417
- package/src/__tests__/tool-result-truncate-pipeline.test.ts +0 -341
- package/src/daemon/bootstrap-turn-cleanup.ts +0 -45
- package/src/gallery/default-gallery.ts +0 -1359
- package/src/gallery/gallery-manifest.ts +0 -28
- package/src/home/feature-gate.ts +0 -22
- package/src/plugins/defaults/empty-response/middlewares/emptyResponse.ts +0 -22
- package/src/plugins/defaults/empty-response/terminal.ts +0 -106
- package/src/plugins/defaults/injectors/package.json +0 -15
- package/src/plugins/defaults/llm-call/middlewares/llmCall.ts +0 -17
- package/src/plugins/defaults/llm-call/package.json +0 -15
- package/src/plugins/defaults/llm-call/register.ts +0 -45
- package/src/plugins/defaults/memory-retrieval/middlewares/memoryRetrieval.ts +0 -17
- package/src/plugins/defaults/memory-retrieval/package.json +0 -15
- package/src/plugins/defaults/memory-retrieval/register.ts +0 -181
- package/src/plugins/defaults/persistence/middlewares/persistence.ts +0 -19
- package/src/plugins/defaults/persistence/package.json +0 -15
- package/src/plugins/defaults/persistence/register.ts +0 -38
- package/src/plugins/defaults/persistence/terminal.ts +0 -83
- package/src/plugins/defaults/title-generate/terminal.ts +0 -31
- package/src/plugins/defaults/token-estimate/middlewares/tokenEstimate.ts +0 -23
- package/src/plugins/defaults/token-estimate/package.json +0 -15
- package/src/plugins/defaults/token-estimate/register.ts +0 -34
- package/src/plugins/defaults/token-estimate/terminal.ts +0 -40
- package/src/plugins/defaults/tool-error/middlewares/toolError.ts +0 -21
- package/src/plugins/defaults/tool-error/terminal.ts +0 -47
- package/src/plugins/defaults/tool-execute/middlewares/toolExecute.ts +0 -23
- package/src/plugins/defaults/tool-execute/package.json +0 -15
- package/src/plugins/defaults/tool-execute/register.ts +0 -49
- package/src/plugins/defaults/tool-result-truncate/middlewares/toolResultTruncate.ts +0 -23
- package/src/plugins/defaults/tool-result-truncate/types.ts +0 -22
- package/src/skills/category-inference.ts +0 -111
|
@@ -36,6 +36,41 @@ import { ACTOR_PRINCIPALS } from "../../auth/route-policy.js";
|
|
|
36
36
|
import { BadRequestError, InternalError } from "../errors.js";
|
|
37
37
|
import type { RouteDefinition, RouteHandlerArgs } from "../types.js";
|
|
38
38
|
|
|
39
|
+
// ---------------------------------------------------------------------------
|
|
40
|
+
// Response schemas
|
|
41
|
+
// ---------------------------------------------------------------------------
|
|
42
|
+
|
|
43
|
+
const TwilioPhoneNumberSchema = z.object({
|
|
44
|
+
phoneNumber: z.string(),
|
|
45
|
+
friendlyName: z.string(),
|
|
46
|
+
capabilities: z.object({ voice: z.boolean() }),
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
const TwilioConfigResultSchema = z.object({
|
|
50
|
+
success: z.boolean(),
|
|
51
|
+
hasCredentials: z.boolean(),
|
|
52
|
+
accountSid: z.string().optional(),
|
|
53
|
+
phoneNumber: z.string().optional(),
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
const TwilioCredentialsResultSchema = z.object({
|
|
57
|
+
success: z.boolean(),
|
|
58
|
+
hasCredentials: z.boolean(),
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
const TwilioNumbersResultSchema = z.object({
|
|
62
|
+
success: z.boolean(),
|
|
63
|
+
hasCredentials: z.boolean(),
|
|
64
|
+
numbers: z.array(TwilioPhoneNumberSchema),
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
const TwilioNumberMutationResultSchema = z.object({
|
|
68
|
+
success: z.boolean(),
|
|
69
|
+
hasCredentials: z.boolean(),
|
|
70
|
+
phoneNumber: z.string().optional(),
|
|
71
|
+
warning: z.string().optional(),
|
|
72
|
+
});
|
|
73
|
+
|
|
39
74
|
// ---------------------------------------------------------------------------
|
|
40
75
|
// Shared helpers
|
|
41
76
|
// ---------------------------------------------------------------------------
|
|
@@ -362,6 +397,7 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
362
397
|
summary: "Get Twilio config",
|
|
363
398
|
description: "Return current Twilio configuration status.",
|
|
364
399
|
tags: ["integrations"],
|
|
400
|
+
responseBody: TwilioConfigResultSchema,
|
|
365
401
|
handler: () => handleGetTwilioConfig(),
|
|
366
402
|
},
|
|
367
403
|
{
|
|
@@ -380,6 +416,7 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
380
416
|
accountSid: z.string().describe("Twilio account SID"),
|
|
381
417
|
authToken: z.string().describe("Twilio auth token"),
|
|
382
418
|
}),
|
|
419
|
+
responseBody: TwilioCredentialsResultSchema,
|
|
383
420
|
},
|
|
384
421
|
{
|
|
385
422
|
operationId: "integrations_twilio_credentials_delete",
|
|
@@ -392,6 +429,7 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
392
429
|
summary: "Clear Twilio credentials",
|
|
393
430
|
description: "Remove stored Twilio credentials.",
|
|
394
431
|
tags: ["integrations"],
|
|
432
|
+
responseBody: TwilioCredentialsResultSchema,
|
|
395
433
|
handler: () => handleClearTwilioCredentials(),
|
|
396
434
|
},
|
|
397
435
|
{
|
|
@@ -405,6 +443,7 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
405
443
|
summary: "List Twilio numbers",
|
|
406
444
|
description: "List phone numbers on the Twilio account.",
|
|
407
445
|
tags: ["integrations"],
|
|
446
|
+
responseBody: TwilioNumbersResultSchema,
|
|
408
447
|
handler: () => handleListTwilioNumbers(),
|
|
409
448
|
},
|
|
410
449
|
{
|
|
@@ -418,6 +457,7 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
418
457
|
summary: "Provision Twilio number",
|
|
419
458
|
description: "Search for and provision a new phone number.",
|
|
420
459
|
tags: ["integrations"],
|
|
460
|
+
responseBody: TwilioNumberMutationResultSchema,
|
|
421
461
|
handler: handleProvisionTwilioNumber,
|
|
422
462
|
},
|
|
423
463
|
{
|
|
@@ -431,6 +471,7 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
431
471
|
summary: "Assign Twilio number",
|
|
432
472
|
description: "Assign an existing phone number to this assistant.",
|
|
433
473
|
tags: ["integrations"],
|
|
474
|
+
responseBody: TwilioNumberMutationResultSchema,
|
|
434
475
|
handler: handleAssignTwilioNumber,
|
|
435
476
|
},
|
|
436
477
|
{
|
|
@@ -444,6 +485,7 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
444
485
|
summary: "Release Twilio number",
|
|
445
486
|
description: "Release a phone number back to Twilio.",
|
|
446
487
|
tags: ["integrations"],
|
|
488
|
+
responseBody: TwilioNumberMutationResultSchema,
|
|
447
489
|
handler: handleReleaseTwilioNumber,
|
|
448
490
|
},
|
|
449
491
|
];
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Internal telemetry routes — receive operational signals forwarded from the
|
|
3
|
+
* gateway over the internal (service-token) transport.
|
|
4
|
+
*
|
|
5
|
+
* POST /v1/internal/telemetry/auth-fallback — record aggregated counts of
|
|
6
|
+
* requests served via the legacy loopback auth fallback. The gateway counts
|
|
7
|
+
* fallbacks in memory and flushes them here per window; the usage telemetry
|
|
8
|
+
* reporter ships the persisted rows to the platform.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { z } from "zod";
|
|
12
|
+
|
|
13
|
+
import {
|
|
14
|
+
type AuthFallbackCount,
|
|
15
|
+
recordAuthFallbackCounts,
|
|
16
|
+
} from "../../memory/auth-fallback-events-store.js";
|
|
17
|
+
import { getLogger } from "../../util/logger.js";
|
|
18
|
+
import { GATEWAY_PRINCIPALS } from "../auth/route-policy.js";
|
|
19
|
+
import { BadRequestError } from "./errors.js";
|
|
20
|
+
import type { RouteDefinition, RouteHandlerArgs } from "./types.js";
|
|
21
|
+
|
|
22
|
+
const log = getLogger("internal-telemetry-routes");
|
|
23
|
+
|
|
24
|
+
const authFallbackBody = z.object({
|
|
25
|
+
window_start: z.number().int().nonnegative(),
|
|
26
|
+
window_end: z.number().int().nonnegative(),
|
|
27
|
+
counts: z
|
|
28
|
+
.array(
|
|
29
|
+
z.object({
|
|
30
|
+
guard: z.string().min(1),
|
|
31
|
+
path: z.string().min(1),
|
|
32
|
+
failure_kind: z.string().min(1),
|
|
33
|
+
count: z.number().int().positive(),
|
|
34
|
+
}),
|
|
35
|
+
)
|
|
36
|
+
.min(1),
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
function handleRecordAuthFallback({ body }: RouteHandlerArgs) {
|
|
40
|
+
const parsed = authFallbackBody.safeParse(body);
|
|
41
|
+
if (!parsed.success) {
|
|
42
|
+
throw new BadRequestError(
|
|
43
|
+
`Invalid auth-fallback payload: ${parsed.error.message}`,
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
const { window_start, window_end, counts } = parsed.data;
|
|
47
|
+
const mapped: AuthFallbackCount[] = counts.map((c) => ({
|
|
48
|
+
guard: c.guard,
|
|
49
|
+
path: c.path,
|
|
50
|
+
failureKind: c.failure_kind,
|
|
51
|
+
count: c.count,
|
|
52
|
+
}));
|
|
53
|
+
|
|
54
|
+
const recorded = recordAuthFallbackCounts(window_start, window_end, mapped);
|
|
55
|
+
if (recorded === 0) {
|
|
56
|
+
// collectUsageData disabled — counts dropped to honor the opt-out.
|
|
57
|
+
return { skipped: true };
|
|
58
|
+
}
|
|
59
|
+
log.debug({ recorded }, "Recorded auth-fallback counts");
|
|
60
|
+
return { recorded };
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export const ROUTES: RouteDefinition[] = [
|
|
64
|
+
{
|
|
65
|
+
operationId: "internal_telemetry_auth_fallback",
|
|
66
|
+
endpoint: "internal/telemetry/auth-fallback",
|
|
67
|
+
method: "POST",
|
|
68
|
+
policy: {
|
|
69
|
+
requiredScopes: ["internal.write"],
|
|
70
|
+
allowedPrincipalTypes: GATEWAY_PRINCIPALS,
|
|
71
|
+
},
|
|
72
|
+
summary: "Record auth-fallback counts",
|
|
73
|
+
description:
|
|
74
|
+
"Receives aggregated legacy-loopback auth-fallback counts forwarded by " +
|
|
75
|
+
"the gateway and persists them for telemetry reporting.",
|
|
76
|
+
tags: ["internal", "telemetry"],
|
|
77
|
+
requestBody: authFallbackBody,
|
|
78
|
+
responseBody: z.union([
|
|
79
|
+
z.object({ recorded: z.number().int().nonnegative() }),
|
|
80
|
+
z.object({
|
|
81
|
+
skipped: z
|
|
82
|
+
.literal(true)
|
|
83
|
+
.describe("Counts dropped because usage data collection is disabled"),
|
|
84
|
+
}),
|
|
85
|
+
]),
|
|
86
|
+
handler: handleRecordAuthFallback,
|
|
87
|
+
},
|
|
88
|
+
];
|
|
@@ -508,6 +508,10 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
508
508
|
"Export audit records, assistant logs, and config as a tar.gz archive.",
|
|
509
509
|
tags: ["export"],
|
|
510
510
|
requestBody: exportRequestBody,
|
|
511
|
+
responseBody: {
|
|
512
|
+
contentType: "application/gzip",
|
|
513
|
+
schema: { type: "string", format: "binary" },
|
|
514
|
+
},
|
|
511
515
|
responseHeaders: {
|
|
512
516
|
"Content-Type": "application/gzip",
|
|
513
517
|
"Content-Disposition": 'attachment; filename="logs.tar.gz"',
|
|
@@ -532,6 +536,10 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
532
536
|
"Alias for /v1/export. Export audit records, assistant logs, and config as a tar.gz archive.",
|
|
533
537
|
tags: ["export"],
|
|
534
538
|
requestBody: exportRequestBody,
|
|
539
|
+
responseBody: {
|
|
540
|
+
contentType: "application/gzip",
|
|
541
|
+
schema: { type: "string", format: "binary" },
|
|
542
|
+
},
|
|
535
543
|
responseHeaders: {
|
|
536
544
|
"Content-Type": "application/gzip",
|
|
537
545
|
"Content-Disposition": 'attachment; filename="logs.tar.gz"',
|
|
@@ -210,14 +210,20 @@ async function handleGetConceptPage({
|
|
|
210
210
|
|
|
211
211
|
const MemoryV2ListConceptPagesParams = z.object({}).strict();
|
|
212
212
|
|
|
213
|
-
export
|
|
214
|
-
pages:
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
}
|
|
213
|
+
export const MemoryV2ListConceptPagesResultSchema = z.object({
|
|
214
|
+
pages: z.array(
|
|
215
|
+
z.object({
|
|
216
|
+
slug: z.string(),
|
|
217
|
+
bodyBytes: z.number(),
|
|
218
|
+
edgeCount: z.number(),
|
|
219
|
+
updatedAtMs: z.number(),
|
|
220
|
+
}),
|
|
221
|
+
),
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
export type MemoryV2ListConceptPagesResult = z.infer<
|
|
225
|
+
typeof MemoryV2ListConceptPagesResultSchema
|
|
226
|
+
>;
|
|
221
227
|
|
|
222
228
|
async function handleListConceptPages({
|
|
223
229
|
body = {},
|
|
@@ -732,6 +738,7 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
732
738
|
"Returns slugs, body sizes, edge counts, and last-modified timestamps for every concept page on disk. Read-only; used by the desktop About → Memories surface to render a browse-able list.",
|
|
733
739
|
tags: ["memory"],
|
|
734
740
|
requestBody: MemoryV2ListConceptPagesParams,
|
|
741
|
+
responseBody: MemoryV2ListConceptPagesResultSchema,
|
|
735
742
|
},
|
|
736
743
|
{
|
|
737
744
|
operationId: "memory_v2_reembed_skills",
|
|
@@ -18,6 +18,8 @@
|
|
|
18
18
|
import { writeFile } from "node:fs/promises";
|
|
19
19
|
import { join } from "node:path";
|
|
20
20
|
|
|
21
|
+
import { z } from "zod";
|
|
22
|
+
|
|
21
23
|
import { getPageIndex } from "../../memory/v2/page-index.js";
|
|
22
24
|
import { loadCore } from "../../memory/v3/core.js";
|
|
23
25
|
import { computeV3Health, renderV3Health } from "../../memory/v3/health.js";
|
|
@@ -88,18 +90,19 @@ async function loadTreeAndSlugs(deps?: MemoryV3Deps): Promise<{
|
|
|
88
90
|
// health
|
|
89
91
|
// ---------------------------------------------------------------------------
|
|
90
92
|
|
|
91
|
-
|
|
93
|
+
const MemoryV3HealthResultSchema = z.object({
|
|
92
94
|
/** Pre-rendered, human-readable report. Empty string when all-green. */
|
|
93
|
-
rendered: string
|
|
95
|
+
rendered: z.string(),
|
|
94
96
|
/** The structural counts, for `--json` consumers. */
|
|
95
|
-
counts: {
|
|
96
|
-
unassigned: number
|
|
97
|
-
danglingRefs: number
|
|
98
|
-
novelClusters: number
|
|
99
|
-
oversizedLeaves: number
|
|
100
|
-
tinyLeaves: number
|
|
101
|
-
}
|
|
102
|
-
}
|
|
97
|
+
counts: z.object({
|
|
98
|
+
unassigned: z.number(),
|
|
99
|
+
danglingRefs: z.number(),
|
|
100
|
+
novelClusters: z.number(),
|
|
101
|
+
oversizedLeaves: z.number(),
|
|
102
|
+
tinyLeaves: z.number(),
|
|
103
|
+
}),
|
|
104
|
+
});
|
|
105
|
+
export type MemoryV3HealthResult = z.infer<typeof MemoryV3HealthResultSchema>;
|
|
103
106
|
|
|
104
107
|
export async function handleMemoryV3Health(
|
|
105
108
|
deps?: MemoryV3Deps,
|
|
@@ -123,26 +126,28 @@ export async function handleMemoryV3Health(
|
|
|
123
126
|
// set-core
|
|
124
127
|
// ---------------------------------------------------------------------------
|
|
125
128
|
|
|
126
|
-
|
|
129
|
+
const MemoryV3SetCoreBodySchema = z.object({
|
|
127
130
|
/** Leaves to add to the always-on core set. */
|
|
128
|
-
add
|
|
131
|
+
add: z.array(z.string()).optional(),
|
|
129
132
|
/** Leaves to remove from the always-on core set. */
|
|
130
|
-
remove
|
|
133
|
+
remove: z.array(z.string()).optional(),
|
|
131
134
|
/**
|
|
132
135
|
* When true, persist the new core to `core.json` and invalidate the lanes.
|
|
133
136
|
* When false (default), compute the preview WITHOUT writing.
|
|
134
137
|
*/
|
|
135
|
-
write
|
|
136
|
-
}
|
|
138
|
+
write: z.boolean().optional(),
|
|
139
|
+
});
|
|
140
|
+
export type MemoryV3SetCoreBody = z.infer<typeof MemoryV3SetCoreBodySchema>;
|
|
137
141
|
|
|
138
|
-
|
|
142
|
+
const MemoryV3SetCoreResultSchema = z.object({
|
|
139
143
|
/** The core leaf set that would result (or did result, when `write`). */
|
|
140
|
-
nextCore:
|
|
144
|
+
nextCore: z.array(z.string()),
|
|
141
145
|
/** Number of unique page slugs the new core set pins always-on. */
|
|
142
|
-
alwaysOnPageCount: number
|
|
146
|
+
alwaysOnPageCount: z.number(),
|
|
143
147
|
/** Whether `core.json` was written. */
|
|
144
|
-
written: boolean
|
|
145
|
-
}
|
|
148
|
+
written: z.boolean(),
|
|
149
|
+
});
|
|
150
|
+
export type MemoryV3SetCoreResult = z.infer<typeof MemoryV3SetCoreResultSchema>;
|
|
146
151
|
|
|
147
152
|
/** Wire-format error code for a `set-core` add referencing an unknown leaf. */
|
|
148
153
|
export const MEMORY_V3_UNKNOWN_LEAF_CODE = "MEMORY_V3_UNKNOWN_LEAF";
|
|
@@ -206,11 +211,20 @@ export async function handleMemoryV3SetCore(
|
|
|
206
211
|
// reconcile
|
|
207
212
|
// ---------------------------------------------------------------------------
|
|
208
213
|
|
|
209
|
-
|
|
210
|
-
renames:
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
+
const MemoryV3ReconcileResultSchema = z.object({
|
|
215
|
+
renames: z.array(
|
|
216
|
+
z.object({
|
|
217
|
+
id: z.string().optional(),
|
|
218
|
+
oldPath: z.string(),
|
|
219
|
+
newPath: z.string(),
|
|
220
|
+
}),
|
|
221
|
+
),
|
|
222
|
+
deleted: z.array(z.string()),
|
|
223
|
+
prunedCore: z.array(z.string()),
|
|
224
|
+
});
|
|
225
|
+
export type MemoryV3ReconcileResult = z.infer<
|
|
226
|
+
typeof MemoryV3ReconcileResultSchema
|
|
227
|
+
>;
|
|
214
228
|
|
|
215
229
|
/**
|
|
216
230
|
* Reconcile page + core references against the live on-disk tree.
|
|
@@ -253,9 +267,12 @@ async function loadPrevLeaves(dataDir: string): Promise<LeafRef[]> {
|
|
|
253
267
|
// rebuild-index
|
|
254
268
|
// ---------------------------------------------------------------------------
|
|
255
269
|
|
|
256
|
-
|
|
257
|
-
ok: true
|
|
258
|
-
}
|
|
270
|
+
const MemoryV3RebuildIndexResultSchema = z.object({
|
|
271
|
+
ok: z.literal(true),
|
|
272
|
+
});
|
|
273
|
+
export type MemoryV3RebuildIndexResult = z.infer<
|
|
274
|
+
typeof MemoryV3RebuildIndexResultSchema
|
|
275
|
+
>;
|
|
259
276
|
|
|
260
277
|
/**
|
|
261
278
|
* Invalidate the v3 shadow lanes so the next turn rebuilds the tree/needle
|
|
@@ -299,6 +316,7 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
299
316
|
handler: () => handleMemoryV3Health(),
|
|
300
317
|
summary: "Print the v3 structural health report (read-only)",
|
|
301
318
|
tags: ["memory"],
|
|
319
|
+
responseBody: MemoryV3HealthResultSchema,
|
|
302
320
|
},
|
|
303
321
|
{
|
|
304
322
|
operationId: "memory_v3_set_core",
|
|
@@ -317,6 +335,8 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
317
335
|
},
|
|
318
336
|
summary: "Add/remove always-on core leaves (validates + previews cost)",
|
|
319
337
|
tags: ["memory"],
|
|
338
|
+
requestBody: MemoryV3SetCoreBodySchema,
|
|
339
|
+
responseBody: MemoryV3SetCoreResultSchema,
|
|
320
340
|
},
|
|
321
341
|
{
|
|
322
342
|
operationId: "memory_v3_reconcile",
|
|
@@ -327,6 +347,7 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
327
347
|
summary:
|
|
328
348
|
"v1 convergence/prune pass over page+core refs (no rename detection without a prior snapshot)",
|
|
329
349
|
tags: ["memory"],
|
|
350
|
+
responseBody: MemoryV3ReconcileResultSchema,
|
|
330
351
|
},
|
|
331
352
|
{
|
|
332
353
|
operationId: "memory_v3_rebuild_index",
|
|
@@ -336,5 +357,6 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
336
357
|
handler: () => handleMemoryV3RebuildIndex(),
|
|
337
358
|
summary: "Invalidate the v3 lanes so the next turn rebuilds",
|
|
338
359
|
tags: ["memory"],
|
|
360
|
+
responseBody: MemoryV3RebuildIndexResultSchema,
|
|
339
361
|
},
|
|
340
362
|
];
|
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
* bearer-token authenticated via the standard runtime auth middleware.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
+
import { z } from "zod";
|
|
10
|
+
|
|
9
11
|
import { orchestrateOAuthConnect } from "../../oauth/connect-orchestrator.js";
|
|
10
12
|
import {
|
|
11
13
|
deleteApp,
|
|
@@ -22,11 +24,8 @@ import {
|
|
|
22
24
|
} from "../../oauth/oauth-store.js";
|
|
23
25
|
import { serializeProviderSummary } from "../../oauth/provider-serializer.js";
|
|
24
26
|
import { ACTOR_PRINCIPALS } from "../auth/route-policy.js";
|
|
25
|
-
import {
|
|
26
|
-
|
|
27
|
-
InternalError,
|
|
28
|
-
NotFoundError,
|
|
29
|
-
} from "./errors.js";
|
|
27
|
+
import { BadRequestError, InternalError, NotFoundError } from "./errors.js";
|
|
28
|
+
import { oauthProviderSummarySchema } from "./oauth-providers.js";
|
|
30
29
|
import type { RouteDefinition, RouteHandlerArgs } from "./types.js";
|
|
31
30
|
|
|
32
31
|
function parseGrantedScopes(
|
|
@@ -131,17 +130,14 @@ async function handleUpsertApp({ body = {} }: RouteHandlerArgs) {
|
|
|
131
130
|
const clientId = b.client_id as string | undefined;
|
|
132
131
|
|
|
133
132
|
if (!providerKey || !clientId) {
|
|
134
|
-
throw new BadRequestError(
|
|
135
|
-
"provider_key and client_id are required",
|
|
136
|
-
);
|
|
133
|
+
throw new BadRequestError("provider_key and client_id are required");
|
|
137
134
|
}
|
|
138
135
|
|
|
139
136
|
const clientSecretOpts = b.client_secret
|
|
140
137
|
? { clientSecretValue: b.client_secret as string }
|
|
141
138
|
: b.client_secret_credential_path
|
|
142
139
|
? {
|
|
143
|
-
clientSecretCredentialPath:
|
|
144
|
-
b.client_secret_credential_path as string,
|
|
140
|
+
clientSecretCredentialPath: b.client_secret_credential_path as string,
|
|
145
141
|
}
|
|
146
142
|
: undefined;
|
|
147
143
|
|
|
@@ -297,6 +293,38 @@ async function handleConnectApp({ pathParams = {}, body }: RouteHandlerArgs) {
|
|
|
297
293
|
return { ok: true };
|
|
298
294
|
}
|
|
299
295
|
|
|
296
|
+
// ---------------------------------------------------------------------------
|
|
297
|
+
// Schemas
|
|
298
|
+
// ---------------------------------------------------------------------------
|
|
299
|
+
|
|
300
|
+
/** Custom OAuth app registration (snake_case wire shape from `formatAppRow`). */
|
|
301
|
+
const oauthAppSchema = z.object({
|
|
302
|
+
id: z.string(),
|
|
303
|
+
provider_key: z.string(),
|
|
304
|
+
client_id: z.string(),
|
|
305
|
+
created_at: z.number(),
|
|
306
|
+
updated_at: z.number(),
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
/** OAuth connection linked to a custom OAuth app. */
|
|
310
|
+
const oauthAppConnectionSchema = z.object({
|
|
311
|
+
id: z.string(),
|
|
312
|
+
provider_key: z.string(),
|
|
313
|
+
account_info: z.string().nullable(),
|
|
314
|
+
granted_scopes: z.array(z.string()),
|
|
315
|
+
status: z.string(),
|
|
316
|
+
has_refresh_token: z.boolean(),
|
|
317
|
+
expires_at: z.number().nullable(),
|
|
318
|
+
created_at: z.number(),
|
|
319
|
+
updated_at: z.number(),
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
const oauthAppCredentialsSchema = z.object({
|
|
323
|
+
provider_key: z.string(),
|
|
324
|
+
client_id: z.string(),
|
|
325
|
+
client_secret: z.string(),
|
|
326
|
+
});
|
|
327
|
+
|
|
300
328
|
// ---------------------------------------------------------------------------
|
|
301
329
|
// Route definitions
|
|
302
330
|
// ---------------------------------------------------------------------------
|
|
@@ -321,6 +349,10 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
321
349
|
description: "OAuth provider key to filter by",
|
|
322
350
|
},
|
|
323
351
|
],
|
|
352
|
+
responseBody: z.object({
|
|
353
|
+
provider: oauthProviderSummarySchema.nullable(),
|
|
354
|
+
apps: z.array(oauthAppSchema),
|
|
355
|
+
}),
|
|
324
356
|
handler: handleListApps,
|
|
325
357
|
},
|
|
326
358
|
{
|
|
@@ -352,6 +384,7 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
352
384
|
description: "OAuth client ID (requires provider)",
|
|
353
385
|
},
|
|
354
386
|
],
|
|
387
|
+
responseBody: z.object({ app: oauthAppSchema }),
|
|
355
388
|
handler: handleGetApp,
|
|
356
389
|
},
|
|
357
390
|
{
|
|
@@ -366,6 +399,13 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
366
399
|
description:
|
|
367
400
|
"Create or return an existing OAuth app registration. Updates client secret if provided.",
|
|
368
401
|
tags: ["oauth"],
|
|
402
|
+
requestBody: z.object({
|
|
403
|
+
provider_key: z.string(),
|
|
404
|
+
client_id: z.string(),
|
|
405
|
+
client_secret: z.string().optional(),
|
|
406
|
+
client_secret_credential_path: z.string().optional(),
|
|
407
|
+
}),
|
|
408
|
+
responseBody: z.object({ app: oauthAppSchema }),
|
|
369
409
|
handler: handleUpsertApp,
|
|
370
410
|
},
|
|
371
411
|
{
|
|
@@ -379,6 +419,8 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
379
419
|
summary: "Create OAuth app",
|
|
380
420
|
description: "Register a new OAuth app with client credentials.",
|
|
381
421
|
tags: ["oauth"],
|
|
422
|
+
requestBody: oauthAppCredentialsSchema,
|
|
423
|
+
responseBody: z.object({ app: oauthAppSchema }),
|
|
382
424
|
responseStatus: "201",
|
|
383
425
|
handler: handleCreateApp,
|
|
384
426
|
},
|
|
@@ -391,9 +433,9 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
391
433
|
allowedPrincipalTypes: ACTOR_PRINCIPALS,
|
|
392
434
|
},
|
|
393
435
|
summary: "Delete OAuth app",
|
|
394
|
-
description:
|
|
395
|
-
"Delete an OAuth app and disconnect all its connections.",
|
|
436
|
+
description: "Delete an OAuth app and disconnect all its connections.",
|
|
396
437
|
tags: ["oauth"],
|
|
438
|
+
responseBody: z.object({ ok: z.boolean() }),
|
|
397
439
|
handler: handleDeleteApp,
|
|
398
440
|
},
|
|
399
441
|
{
|
|
@@ -407,6 +449,9 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
407
449
|
summary: "List OAuth connections",
|
|
408
450
|
description: "List connections for an OAuth app.",
|
|
409
451
|
tags: ["oauth"],
|
|
452
|
+
responseBody: z.object({
|
|
453
|
+
connections: z.array(oauthAppConnectionSchema),
|
|
454
|
+
}),
|
|
410
455
|
handler: handleListConnections,
|
|
411
456
|
},
|
|
412
457
|
{
|
|
@@ -420,6 +465,7 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
420
465
|
summary: "Disconnect OAuth connection",
|
|
421
466
|
description: "Disconnect a single OAuth connection.",
|
|
422
467
|
tags: ["oauth"],
|
|
468
|
+
responseBody: z.object({ ok: z.boolean() }),
|
|
423
469
|
handler: handleDeleteConnection,
|
|
424
470
|
},
|
|
425
471
|
{
|
|
@@ -433,6 +479,14 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
433
479
|
summary: "Start OAuth connect",
|
|
434
480
|
description: "Start an OAuth connect flow for an app.",
|
|
435
481
|
tags: ["oauth"],
|
|
482
|
+
requestBody: z.object({
|
|
483
|
+
scopes: z.array(z.string()).optional(),
|
|
484
|
+
callback_transport: z.enum(["loopback", "gateway"]).optional(),
|
|
485
|
+
}),
|
|
486
|
+
responseBody: z.union([
|
|
487
|
+
z.object({ auth_url: z.string(), state: z.string() }),
|
|
488
|
+
z.object({ ok: z.literal(true) }),
|
|
489
|
+
]),
|
|
436
490
|
handler: handleConnectApp,
|
|
437
491
|
},
|
|
438
492
|
];
|
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
* the standard runtime auth middleware.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
+
import { z } from "zod";
|
|
10
|
+
|
|
9
11
|
import { loadConfig } from "../../config/loader.js";
|
|
10
12
|
import { getOAuthCallbackUrl } from "../../inbound/public-ingress-urls.js";
|
|
11
13
|
import {
|
|
@@ -220,7 +222,8 @@ function handleUpdateProvider({
|
|
|
220
222
|
if (b.default_scopes !== undefined) params.defaultScopes = b.default_scopes;
|
|
221
223
|
if (b.available_scopes !== undefined)
|
|
222
224
|
params.availableScopes = b.available_scopes;
|
|
223
|
-
if (b.scope_separator !== undefined)
|
|
225
|
+
if (b.scope_separator !== undefined)
|
|
226
|
+
params.scopeSeparator = b.scope_separator;
|
|
224
227
|
if (b.token_endpoint_auth_method !== undefined)
|
|
225
228
|
params.tokenEndpointAuthMethod = b.token_endpoint_auth_method;
|
|
226
229
|
if (b.token_exchange_body_format !== undefined)
|
|
@@ -245,13 +248,15 @@ function handleUpdateProvider({
|
|
|
245
248
|
params.injectionTemplates = b.injection_templates;
|
|
246
249
|
if (b.app_type !== undefined) params.appType = b.app_type;
|
|
247
250
|
if (b.identity_url !== undefined) params.identityUrl = b.identity_url;
|
|
248
|
-
if (b.identity_method !== undefined)
|
|
251
|
+
if (b.identity_method !== undefined)
|
|
252
|
+
params.identityMethod = b.identity_method;
|
|
249
253
|
if (b.identity_headers !== undefined)
|
|
250
254
|
params.identityHeaders = b.identity_headers;
|
|
251
255
|
if (b.identity_body !== undefined) params.identityBody = b.identity_body;
|
|
252
256
|
if (b.identity_response_paths !== undefined)
|
|
253
257
|
params.identityResponsePaths = b.identity_response_paths;
|
|
254
|
-
if (b.identity_format !== undefined)
|
|
258
|
+
if (b.identity_format !== undefined)
|
|
259
|
+
params.identityFormat = b.identity_format;
|
|
255
260
|
if (b.identity_ok_field !== undefined)
|
|
256
261
|
params.identityOkField = b.identity_ok_field;
|
|
257
262
|
if (b.setup_notes !== undefined) params.setupNotes = b.setup_notes;
|
|
@@ -321,6 +326,37 @@ async function handleDeleteProvider({
|
|
|
321
326
|
// Route definitions
|
|
322
327
|
// ---------------------------------------------------------------------------
|
|
323
328
|
|
|
329
|
+
/**
|
|
330
|
+
* Lightweight summary projection of an OAuth provider returned by the catalog
|
|
331
|
+
* list endpoint. Mirrors `SerializedProviderSummary` from the provider
|
|
332
|
+
* serializer (snake_case to match the HTTP API convention).
|
|
333
|
+
*/
|
|
334
|
+
export const oauthProviderSummarySchema = z.object({
|
|
335
|
+
provider_key: z.string(),
|
|
336
|
+
display_name: z.string().nullable(),
|
|
337
|
+
description: z.string().nullable(),
|
|
338
|
+
dashboard_url: z.string().nullable(),
|
|
339
|
+
client_id_placeholder: z.string().nullable(),
|
|
340
|
+
requires_client_secret: z.boolean(),
|
|
341
|
+
logo_url: z.string().nullable(),
|
|
342
|
+
supports_managed_mode: z.boolean(),
|
|
343
|
+
managed_service_is_paid: z.boolean(),
|
|
344
|
+
feature_flag: z.string().nullable(),
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* Response for the single-provider detail endpoint. The `provider` field is the
|
|
349
|
+
* full serialized provider configuration — an open-ended, admin-defined object
|
|
350
|
+
* whose keys depend on the stored row (parsed JSON blobs, identity templates,
|
|
351
|
+
* and forwarded columns), so it is intentionally typed as an open record rather
|
|
352
|
+
* than a closed schema. `oauth_callback_url` is the ingress callback URL the
|
|
353
|
+
* web UI consumes (null when ingress is not configured).
|
|
354
|
+
*/
|
|
355
|
+
export const oauthProviderDetailSchema = z.object({
|
|
356
|
+
provider: z.record(z.string(), z.unknown()),
|
|
357
|
+
oauth_callback_url: z.string().nullable(),
|
|
358
|
+
});
|
|
359
|
+
|
|
324
360
|
export const ROUTES: RouteDefinition[] = [
|
|
325
361
|
{
|
|
326
362
|
operationId: "oauth_providers_get",
|
|
@@ -331,8 +367,7 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
331
367
|
allowedPrincipalTypes: ACTOR_PRINCIPALS,
|
|
332
368
|
},
|
|
333
369
|
summary: "List OAuth providers",
|
|
334
|
-
description:
|
|
335
|
-
"List all registered OAuth providers with optional filtering.",
|
|
370
|
+
description: "List all registered OAuth providers with optional filtering.",
|
|
336
371
|
tags: ["oauth"],
|
|
337
372
|
handler: handleListProviders,
|
|
338
373
|
queryParams: [
|
|
@@ -342,6 +377,9 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
342
377
|
description: "Filter by managed mode support (true/false)",
|
|
343
378
|
},
|
|
344
379
|
],
|
|
380
|
+
responseBody: z.object({
|
|
381
|
+
providers: z.array(oauthProviderSummarySchema),
|
|
382
|
+
}),
|
|
345
383
|
},
|
|
346
384
|
{
|
|
347
385
|
operationId: "oauth_providers_by_providerKey_get",
|
|
@@ -355,6 +393,7 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
355
393
|
description: "Get a single OAuth provider by key.",
|
|
356
394
|
tags: ["oauth"],
|
|
357
395
|
handler: handleGetProvider,
|
|
396
|
+
responseBody: oauthProviderDetailSchema,
|
|
358
397
|
},
|
|
359
398
|
{
|
|
360
399
|
operationId: "oauth_providers_post",
|