@vellumai/assistant 0.5.1 → 0.5.2
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/ARCHITECTURE.md +54 -54
- package/docs/architecture/integrations.md +62 -67
- package/docs/credential-execution-service.md +3 -3
- package/package.json +1 -1
- package/src/__tests__/agent-loop.test.ts +111 -0
- package/src/__tests__/always-loaded-tools-guard.test.ts +3 -4
- package/src/__tests__/app-builder-tool-scripts.test.ts +13 -151
- package/src/__tests__/app-dir-path-guard.test.ts +78 -0
- package/src/__tests__/app-executors.test.ts +1 -291
- package/src/__tests__/app-git-history.test.ts +4 -4
- package/src/__tests__/app-routes-csp.test.ts +1 -0
- package/src/__tests__/app-store-dir-names.test.ts +426 -0
- package/src/__tests__/attachments-store.test.ts +169 -21
- package/src/__tests__/attachments.test.ts +115 -1
- package/src/__tests__/btw-routes.test.ts +1 -0
- package/src/__tests__/canonical-guardian-store.test.ts +38 -0
- package/src/__tests__/channel-reply-delivery.test.ts +55 -0
- package/src/__tests__/checker.test.ts +54 -0
- package/src/__tests__/claude-code-skill-regression.test.ts +2 -0
- package/src/__tests__/claude-code-tool-profiles.test.ts +2 -0
- package/src/__tests__/compaction.benchmark.test.ts +2 -1
- package/src/__tests__/config-schema-cmd.test.ts +68 -21
- package/src/__tests__/config-schema.test.ts +1 -1
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +149 -5
- package/src/__tests__/conversation-agent-loop.test.ts +290 -2
- package/src/__tests__/conversation-attachments.test.ts +17 -19
- package/src/__tests__/conversation-disk-view-integration.test.ts +277 -0
- package/src/__tests__/conversation-disk-view.test.ts +810 -0
- package/src/__tests__/conversation-error.test.ts +1 -1
- package/src/__tests__/conversation-fork-crud.test.ts +551 -0
- package/src/__tests__/conversation-fork-route.test.ts +386 -0
- package/src/__tests__/conversation-history-web-search.test.ts +1 -1
- package/src/__tests__/conversation-key-store-disk-view.test.ts +130 -0
- package/src/__tests__/conversation-media-retry.test.ts +8 -2
- package/src/__tests__/conversation-queue.test.ts +36 -1
- package/src/__tests__/conversation-routes-disk-view.test.ts +439 -0
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +2 -2
- package/src/__tests__/conversation-routes-slash-commands.test.ts +2 -7
- package/src/__tests__/conversation-runtime-assembly.test.ts +17 -2
- package/src/__tests__/conversation-skill-tools.test.ts +4 -9
- package/src/__tests__/conversation-slash-commands.test.ts +149 -0
- package/src/__tests__/conversation-store.test.ts +24 -21
- package/src/__tests__/conversation-surfaces-state-update.test.ts +246 -0
- package/src/__tests__/conversation-surfaces-task-progress.test.ts +1 -0
- package/src/__tests__/conversation-title-service.test.ts +137 -0
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +25 -315
- package/src/__tests__/conversation-tool-setup-memory-scope.test.ts +1 -0
- package/src/__tests__/conversation-tool-setup-side-effect-flag.test.ts +1 -0
- package/src/__tests__/conversation-workspace-cache-state.test.ts +44 -2
- package/src/__tests__/conversation-workspace-injection.test.ts +11 -0
- package/src/__tests__/credential-security-invariants.test.ts +3 -0
- package/src/__tests__/credential-vault-unit.test.ts +5 -10
- package/src/__tests__/cu-unified-flow.test.ts +1 -0
- package/src/__tests__/db-conversation-fork-lineage-migration.test.ts +241 -0
- package/src/__tests__/db-llm-request-log-provider-migration.test.ts +214 -0
- package/src/__tests__/diagnostics-export.test.ts +70 -1
- package/src/__tests__/first-greeting.test.ts +80 -0
- package/src/__tests__/gateway-only-guard.test.ts +1 -0
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +3 -7
- package/src/__tests__/history-repair.test.ts +32 -10
- package/src/__tests__/http-conversation-lineage.test.ts +251 -0
- package/src/__tests__/image-source-path-reinject.test.ts +136 -0
- package/src/__tests__/llm-context-normalization.test.ts +1116 -0
- package/src/__tests__/llm-context-route-provider.test.ts +217 -0
- package/src/__tests__/llm-request-log-turn-query.test.ts +270 -0
- package/src/__tests__/media-generate-image.test.ts +47 -94
- package/src/__tests__/memory-lifecycle-e2e.test.ts +3 -1
- package/src/__tests__/memory-recall-quality.test.ts +5 -5
- package/src/__tests__/migration-cross-version-compatibility.test.ts +4 -1
- package/src/__tests__/migration-export-http.test.ts +3 -1
- package/src/__tests__/migration-import-commit-http.test.ts +18 -4
- package/src/__tests__/migration-import-preflight-http.test.ts +1 -3
- package/src/__tests__/mime-builder.test.ts +3 -2
- package/src/__tests__/non-member-access-request.test.ts +12 -1
- package/src/__tests__/notification-decision-identity.test.ts +52 -0
- package/src/__tests__/oauth-apps-routes.test.ts +103 -0
- package/src/__tests__/oauth-store.test.ts +115 -0
- package/src/__tests__/provider-error-scenarios.test.ts +1 -3
- package/src/__tests__/provider-failover-actual-provider.test.ts +66 -0
- package/src/__tests__/recording-handler.test.ts +17 -0
- package/src/__tests__/registry.test.ts +3 -8
- package/src/__tests__/relay-server.test.ts +1 -1
- package/src/__tests__/runtime-attachment-metadata.test.ts +7 -3
- package/src/__tests__/schema-transforms.test.ts +165 -5
- package/src/__tests__/server-history-render.test.ts +2 -2
- package/src/__tests__/slack-app-setup-skill-regression.test.ts +3 -1
- package/src/__tests__/slack-inbound-verification.test.ts +2 -2
- package/src/__tests__/starter-task-flow.test.ts +1 -0
- package/src/__tests__/suggestion-routes.test.ts +443 -0
- package/src/__tests__/swarm-conversation-integration.test.ts +1 -0
- package/src/__tests__/swarm-recursion.test.ts +1 -0
- package/src/__tests__/swarm-tool.test.ts +1 -0
- package/src/__tests__/tool-execution-abort-cleanup.test.ts +1 -0
- package/src/__tests__/tool-preview-lifecycle.test.ts +32 -5
- package/src/__tests__/top-level-renderer.test.ts +22 -0
- package/src/__tests__/turn-boundary-resolution.test.ts +243 -0
- package/src/__tests__/web-fetch.test.ts +6 -2
- package/src/__tests__/workspace-migration-006-services-config.test.ts +335 -0
- package/src/__tests__/workspace-migration-007-web-search-provider-rename.test.ts +312 -0
- package/src/__tests__/workspace-migration-009-backfill-conversation-disk-view.test.ts +278 -0
- package/src/__tests__/workspace-migration-010-app-dir-rename.test.ts +275 -0
- package/src/__tests__/workspace-migration-012-rename-conversation-disk-view-dirs.test.ts +77 -0
- package/src/__tests__/workspace-migration-013-repair-conversation-disk-view.test.ts +401 -0
- package/src/__tests__/workspace-migration-backfill-installation-id.test.ts +328 -0
- package/src/__tests__/workspace-migration-seed-device-id.test.ts +6 -10
- package/src/agent/attachments.ts +27 -1
- package/src/agent/loop.ts +29 -1
- package/src/avatar/traits-png-sync.ts +80 -25
- package/src/bundler/app-bundler.ts +4 -4
- package/src/calls/call-domain.ts +1 -0
- package/src/calls/voice-session-bridge.ts +1 -0
- package/src/cli/commands/auth.ts +92 -0
- package/src/cli/commands/avatar.ts +7 -6
- package/src/cli/commands/config.ts +2 -0
- package/src/cli/commands/oauth/providers.ts +29 -0
- package/src/cli/program.ts +12 -0
- package/src/cli.ts +15 -48
- package/src/config/bundled-skills/app-builder/SKILL.md +103 -28
- package/src/config/bundled-skills/app-builder/TOOLS.json +5 -199
- package/src/config/bundled-skills/app-builder/tools/{app-query.ts → app-refresh.ts} +2 -2
- package/src/config/bundled-skills/contacts/tools/google-contacts.ts +2 -3
- package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +6 -9
- package/src/config/bundled-skills/gmail/tools/gmail-attachments.ts +4 -6
- package/src/config/bundled-skills/gmail/tools/gmail-draft.ts +2 -3
- package/src/config/bundled-skills/gmail/tools/gmail-filters.ts +2 -3
- package/src/config/bundled-skills/gmail/tools/gmail-follow-up.ts +2 -3
- package/src/config/bundled-skills/gmail/tools/gmail-forward.ts +2 -3
- package/src/config/bundled-skills/gmail/tools/gmail-label.ts +4 -6
- package/src/config/bundled-skills/gmail/tools/gmail-outreach-scan.ts +2 -3
- package/src/config/bundled-skills/gmail/tools/gmail-send-draft.ts +2 -3
- package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +2 -3
- package/src/config/bundled-skills/gmail/tools/gmail-trash.ts +2 -3
- package/src/config/bundled-skills/gmail/tools/gmail-unsubscribe.ts +2 -3
- package/src/config/bundled-skills/gmail/tools/gmail-vacation.ts +2 -3
- package/src/config/bundled-skills/google-calendar/tools/shared.ts +1 -1
- package/src/config/bundled-skills/image-studio/SKILL.md +2 -2
- package/src/config/bundled-skills/image-studio/TOOLS.json +2 -2
- package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +45 -72
- package/src/config/bundled-skills/media-processing/tools/extract-keyframes.ts +2 -2
- package/src/config/bundled-skills/messaging/tools/shared.ts +1 -1
- package/src/config/bundled-skills/settings/tools/voice-config-update.ts +19 -3
- package/src/config/bundled-skills/skill-management/TOOLS.json +2 -2
- package/src/config/bundled-skills/slack/tools/shared.ts +19 -4
- package/src/config/bundled-skills/slack/tools/slack-scan-digest.ts +2 -3
- package/src/config/bundled-skills/transcribe/SKILL.md +1 -1
- package/src/config/bundled-skills/transcribe/TOOLS.json +2 -6
- package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +19 -83
- package/src/config/bundled-tool-registry.ts +2 -14
- package/src/config/feature-flag-registry.json +8 -0
- package/src/config/loader.ts +64 -0
- package/src/config/raw-config-utils.ts +30 -0
- package/src/config/schema-utils.ts +28 -7
- package/src/config/schema.ts +8 -0
- package/src/config/schemas/elevenlabs.ts +18 -0
- package/src/config/schemas/memory-lifecycle.ts +4 -2
- package/src/config/schemas/memory-storage.ts +1 -1
- package/src/config/schemas/services.ts +8 -6
- package/src/contacts/contact-store.ts +13 -6
- package/src/contacts/contacts-write.ts +0 -1
- package/src/context/window-manager.ts +13 -2
- package/src/daemon/conversation-agent-loop-handlers.ts +48 -7
- package/src/daemon/conversation-agent-loop.ts +56 -19
- package/src/daemon/conversation-attachments.ts +18 -36
- package/src/daemon/conversation-error.ts +2 -1
- package/src/daemon/conversation-history.ts +18 -4
- package/src/daemon/conversation-lifecycle.ts +39 -15
- package/src/daemon/conversation-messaging.ts +70 -26
- package/src/daemon/conversation-process.ts +58 -34
- package/src/daemon/conversation-runtime-assembly.ts +21 -38
- package/src/daemon/conversation-slash.ts +121 -256
- package/src/daemon/conversation-surfaces.ts +143 -20
- package/src/daemon/conversation-tool-setup.ts +0 -6
- package/src/daemon/conversation-workspace.ts +21 -1
- package/src/daemon/conversation.ts +51 -29
- package/src/daemon/first-greeting.ts +35 -0
- package/src/daemon/handlers/config-embeddings.ts +148 -0
- package/src/daemon/handlers/config-model.ts +71 -26
- package/src/daemon/handlers/conversations.ts +0 -23
- package/src/daemon/handlers/recording.ts +26 -21
- package/src/daemon/host-cu-proxy.ts +2 -2
- package/src/daemon/lifecycle.ts +106 -64
- package/src/daemon/message-protocol.ts +3 -0
- package/src/daemon/message-types/conversations.ts +19 -0
- package/src/daemon/message-types/messages.ts +1 -0
- package/src/daemon/message-types/shared.ts +2 -0
- package/src/daemon/message-types/surfaces.ts +2 -0
- package/src/daemon/message-types/upgrades.ts +23 -0
- package/src/daemon/server.ts +83 -12
- package/src/daemon/shutdown-handlers.ts +8 -5
- package/src/daemon/startup-error.ts +9 -0
- package/src/daemon/tool-side-effects.ts +11 -28
- package/src/events/tool-permission-telemetry-listener.ts +1 -3
- package/src/instrument.ts +0 -4
- package/src/media/app-icon-generator.ts +2 -2
- package/src/memory/app-git-service.ts +28 -16
- package/src/memory/app-store.ts +230 -41
- package/src/memory/attachments-store.ts +558 -130
- package/src/memory/conversation-attention-store.ts +70 -0
- package/src/memory/conversation-crud.ts +442 -3
- package/src/memory/conversation-directories.ts +125 -0
- package/src/memory/conversation-disk-view.ts +390 -0
- package/src/memory/conversation-key-store.ts +17 -5
- package/src/memory/conversation-queries.ts +5 -1
- package/src/memory/conversation-title-service.ts +21 -49
- package/src/memory/db-init.ts +28 -0
- package/src/memory/embedding-backend.ts +42 -53
- package/src/memory/embedding-gemini.test.ts +4 -4
- package/src/memory/embedding-local.ts +1 -3
- package/src/memory/embedding-ollama.ts +1 -3
- package/src/memory/embedding-openai.ts +1 -3
- package/src/memory/indexer.ts +9 -7
- package/src/memory/items-extractor.ts +42 -13
- package/src/memory/job-handlers/conversation-starters.ts +6 -1
- package/src/memory/job-handlers/embedding.test.ts +1 -4
- package/src/memory/llm-request-log-store.ts +100 -1
- package/src/memory/migrations/102-alter-table-columns.ts +5 -0
- package/src/memory/migrations/146-schedule-oneshot-routing.ts +3 -3
- package/src/memory/migrations/147-migrate-reminders-to-schedules.ts +66 -70
- package/src/memory/migrations/148-drop-reminders-table.ts +5 -9
- package/src/memory/migrations/160-drop-loopback-port-column.ts +1 -3
- package/src/memory/migrations/174-rename-thread-starters-table.ts +0 -7
- package/src/memory/migrations/178-oauth-providers-managed-service-config-key.ts +15 -0
- package/src/memory/migrations/179-llm-request-log-message-id.ts +16 -0
- package/src/memory/migrations/180-backfill-inline-attachments-to-disk.ts +66 -0
- package/src/memory/migrations/181-rename-thread-starters-checkpoints.ts +46 -0
- package/src/memory/migrations/182-oauth-providers-display-metadata.ts +20 -0
- package/src/memory/migrations/183-add-conversation-fork-lineage.ts +22 -0
- package/src/memory/migrations/184-llm-request-log-provider.ts +12 -0
- package/src/memory/migrations/index.ts +7 -0
- package/src/memory/migrations/registry.ts +13 -0
- package/src/memory/retriever.test.ts +601 -2
- package/src/memory/retriever.ts +85 -9
- package/src/memory/schema/conversations.ts +6 -0
- package/src/memory/schema/infrastructure.ts +13 -7
- package/src/memory/schema/oauth.ts +6 -0
- package/src/messaging/providers/gmail/mime-builder.ts +3 -1
- package/src/notifications/copy-composer.ts +26 -0
- package/src/notifications/decision-engine.ts +14 -1
- package/src/notifications/emit-signal.ts +1 -1
- package/src/notifications/signal.ts +36 -0
- package/src/oauth/byo-connection.test.ts +1 -45
- package/src/oauth/byo-connection.ts +2 -8
- package/src/oauth/connect-orchestrator.ts +15 -11
- package/src/oauth/connection-resolver.test.ts +191 -0
- package/src/oauth/connection-resolver.ts +66 -38
- package/src/oauth/connection.ts +0 -1
- package/src/oauth/oauth-store.ts +97 -47
- package/src/oauth/platform-connection.test.ts +0 -1
- package/src/oauth/platform-connection.ts +11 -3
- package/src/oauth/seed-providers.ts +78 -3
- package/src/oauth/token-persistence.ts +16 -10
- package/src/permissions/checker.ts +71 -8
- package/src/prompts/templates/BOOTSTRAP.md +2 -0
- package/src/providers/anthropic/client.ts +8 -1
- package/src/providers/failover.ts +4 -1
- package/src/providers/gemini/client.ts +50 -0
- package/src/providers/model-catalog.ts +92 -0
- package/src/providers/model-intents.ts +29 -20
- package/src/providers/openai/client.ts +49 -0
- package/src/providers/types.ts +2 -0
- package/src/runtime/access-request-helper.ts +16 -7
- package/src/runtime/auth/credential-service.ts +3 -1
- package/src/runtime/auth/route-policy.ts +14 -1
- package/src/runtime/btw-sidechain.ts +101 -0
- package/src/runtime/channel-reply-delivery.ts +17 -1
- package/src/runtime/http-router.ts +3 -1
- package/src/runtime/http-server.ts +196 -141
- package/src/runtime/http-types.ts +1 -0
- package/src/runtime/migrations/vbundle-builder.ts +5 -1
- package/src/runtime/routes/access-request-decision.ts +41 -0
- package/src/runtime/routes/app-management-routes.ts +6 -3
- package/src/runtime/routes/app-routes.ts +7 -3
- package/src/runtime/routes/approval-routes.ts +1 -0
- package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +34 -2
- package/src/runtime/routes/attachment-routes.ts +45 -15
- package/src/runtime/routes/btw-routes.ts +21 -61
- package/src/runtime/routes/conversation-management-routes.ts +68 -0
- package/src/runtime/routes/conversation-query-routes.ts +180 -10
- package/src/runtime/routes/conversation-routes.ts +222 -28
- package/src/runtime/routes/conversation-starter-routes.ts +9 -11
- package/src/runtime/routes/diagnostics-routes.ts +1 -0
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +2 -2
- package/src/runtime/routes/llm-context-normalization.ts +1199 -0
- package/src/runtime/routes/log-export-routes.ts +3 -0
- package/src/runtime/routes/memory-item-routes.test.ts +34 -0
- package/src/runtime/routes/memory-item-routes.ts +4 -0
- package/src/runtime/routes/migration-routes.ts +4 -1
- package/src/runtime/routes/oauth-apps.ts +291 -0
- package/src/runtime/routes/secret-routes.ts +28 -1
- package/src/runtime/routes/settings-routes.ts +14 -0
- package/src/runtime/routes/trace-event-routes.ts +4 -1
- package/src/schedule/schedule-store.ts +9 -21
- package/src/security/secure-keys.ts +21 -0
- package/src/signals/bash.ts +1 -1
- package/src/swarm/backend-claude-code.ts +3 -6
- package/src/telemetry/usage-telemetry-reporter.test.ts +3 -2
- package/src/telemetry/usage-telemetry-reporter.ts +3 -1
- package/src/tools/AGENTS.md +6 -10
- package/src/tools/apps/executors.ts +17 -232
- package/src/tools/claude-code/claude-code.ts +2 -3
- package/src/tools/credentials/vault.ts +7 -12
- package/src/tools/host-filesystem/read.ts +13 -10
- package/src/tools/network/__tests__/web-search.test.ts +4 -2
- package/src/tools/schedule/list.ts +2 -7
- package/src/tools/schema-transforms.ts +5 -0
- package/src/tools/shared/filesystem/format-diff.ts +2 -7
- package/src/tools/skills/execute.ts +1 -1
- package/src/tools/tool-manifest.ts +0 -6
- package/src/tools/ui-surface/definitions.ts +2 -2
- package/src/util/device-id.ts +28 -5
- package/src/util/platform.ts +6 -0
- package/src/util/pricing.ts +1 -0
- package/src/util/retry.ts +1 -3
- package/src/workspace/migrations/002-backfill-installation-id.ts +23 -12
- package/src/workspace/migrations/003-seed-device-id.ts +3 -4
- package/src/workspace/migrations/006-services-config.ts +5 -0
- package/src/workspace/migrations/008-voice-timeout-and-max-steps.ts +12 -0
- package/src/workspace/migrations/009-backfill-conversation-disk-view.ts +10 -0
- package/src/workspace/migrations/010-app-dir-rename.ts +223 -0
- package/src/workspace/migrations/012-rename-conversation-disk-view-dirs.ts +64 -0
- package/src/workspace/migrations/013-repair-conversation-disk-view.ts +11 -0
- package/src/workspace/migrations/rebuild-conversation-disk-view.ts +186 -0
- package/src/workspace/migrations/registry.ts +10 -0
- package/src/workspace/top-level-renderer.ts +12 -0
- package/src/__tests__/asset-materialize-tool.test.ts +0 -523
- package/src/__tests__/asset-search-tool.test.ts +0 -536
- package/src/__tests__/fixtures/media-reuse-fixtures.ts +0 -56
- package/src/__tests__/media-reuse-story.e2e.test.ts +0 -762
- package/src/__tests__/media-visibility-policy.test.ts +0 -190
- package/src/config/bundled-skills/app-builder/tools/app-file-edit.ts +0 -14
- package/src/config/bundled-skills/app-builder/tools/app-file-list.ts +0 -13
- package/src/config/bundled-skills/app-builder/tools/app-file-read.ts +0 -21
- package/src/config/bundled-skills/app-builder/tools/app-file-write.ts +0 -14
- package/src/config/bundled-skills/app-builder/tools/app-list.ts +0 -13
- package/src/config/bundled-skills/app-builder/tools/app-update.ts +0 -23
- package/src/daemon/media-visibility-policy.ts +0 -59
- package/src/tools/assets/materialize.ts +0 -248
- package/src/tools/assets/search.ts +0 -400
|
@@ -2,6 +2,7 @@ import OpenAI from "openai";
|
|
|
2
2
|
|
|
3
3
|
import { SYSTEM_PROMPT_CACHE_BOUNDARY } from "../../prompts/cache-boundary.js";
|
|
4
4
|
import { ProviderError } from "../../util/errors.js";
|
|
5
|
+
import { getLogger } from "../../util/logger.js";
|
|
5
6
|
import { extractRetryAfterMs } from "../../util/retry.js";
|
|
6
7
|
import { escapeXmlAttr } from "../../util/xml.js";
|
|
7
8
|
import { createStreamTimeout } from "../stream-timeout.js";
|
|
@@ -14,6 +15,54 @@ import type {
|
|
|
14
15
|
ToolDefinition,
|
|
15
16
|
} from "../types.js";
|
|
16
17
|
|
|
18
|
+
const log = getLogger("openai-client");
|
|
19
|
+
|
|
20
|
+
/** Validation-specific timeout (10s) so a stalled network doesn't block key submission. */
|
|
21
|
+
const VALIDATION_TIMEOUT_MS = 10_000;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Validate an OpenAI API key by making a lightweight GET /v1/models call.
|
|
25
|
+
* Returns `{ valid: true }` on success or `{ valid: false, reason: string }` on failure.
|
|
26
|
+
*/
|
|
27
|
+
export async function validateOpenAIApiKey(
|
|
28
|
+
apiKey: string,
|
|
29
|
+
): Promise<{ valid: true } | { valid: false; reason: string }> {
|
|
30
|
+
try {
|
|
31
|
+
const client = new OpenAI({
|
|
32
|
+
apiKey,
|
|
33
|
+
timeout: VALIDATION_TIMEOUT_MS,
|
|
34
|
+
maxRetries: 0,
|
|
35
|
+
});
|
|
36
|
+
await client.models.list();
|
|
37
|
+
return { valid: true };
|
|
38
|
+
} catch (error) {
|
|
39
|
+
if (error instanceof OpenAI.APIError) {
|
|
40
|
+
if (error.status === 401) {
|
|
41
|
+
return { valid: false, reason: "API key is invalid or expired." };
|
|
42
|
+
}
|
|
43
|
+
if (error.status === 403) {
|
|
44
|
+
return {
|
|
45
|
+
valid: false,
|
|
46
|
+
reason: `OpenAI API error (${error.status}): ${error.message}`,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
// Transient errors (429, 5xx, etc.) — validation is inconclusive,
|
|
50
|
+
// allow the key to be stored rather than blocking the user.
|
|
51
|
+
log.warn(
|
|
52
|
+
{ status: error.status },
|
|
53
|
+
"OpenAI API returned a transient error during key validation — allowing key storage",
|
|
54
|
+
);
|
|
55
|
+
return { valid: true };
|
|
56
|
+
}
|
|
57
|
+
// Network errors — validation is inconclusive, allow key storage.
|
|
58
|
+
log.warn(
|
|
59
|
+
{ error: error instanceof Error ? error.message : String(error) },
|
|
60
|
+
"Network error during OpenAI key validation — allowing key storage",
|
|
61
|
+
);
|
|
62
|
+
return { valid: true };
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
17
66
|
export interface OpenAICompatibleProviderOptions {
|
|
18
67
|
baseURL?: string;
|
|
19
68
|
providerName?: string;
|
package/src/providers/types.ts
CHANGED
|
@@ -93,6 +93,8 @@ export type ModelIntent =
|
|
|
93
93
|
export interface ProviderResponse {
|
|
94
94
|
content: ContentBlock[];
|
|
95
95
|
model: string;
|
|
96
|
+
/** Provider that actually produced this response, which may differ from a wrapper provider name. */
|
|
97
|
+
actualProvider?: string;
|
|
96
98
|
usage: {
|
|
97
99
|
/** Total input tokens (input_tokens + cache_creation + cache_read). */
|
|
98
100
|
inputTokens: number;
|
|
@@ -21,7 +21,10 @@ import {
|
|
|
21
21
|
updateCanonicalGuardianDelivery,
|
|
22
22
|
} from "../memory/canonical-guardian-store.js";
|
|
23
23
|
import { emitNotificationSignal } from "../notifications/emit-signal.js";
|
|
24
|
-
import type {
|
|
24
|
+
import type {
|
|
25
|
+
GuardianResolutionSource,
|
|
26
|
+
NotificationSourceChannel,
|
|
27
|
+
} from "../notifications/signal.js";
|
|
25
28
|
import type { NotificationDeliveryResult } from "../notifications/types.js";
|
|
26
29
|
import { getLogger } from "../util/logger.js";
|
|
27
30
|
import { ensureVellumGuardianBinding } from "./guardian-vellum-migration.js";
|
|
@@ -100,10 +103,7 @@ export function notifyGuardianOfAccessRequest(
|
|
|
100
103
|
let guardianExternalUserId: string | null = null;
|
|
101
104
|
let guardianPrincipalId: string | null = null;
|
|
102
105
|
let guardianBindingChannel: string | null = null;
|
|
103
|
-
let guardianResolutionSource:
|
|
104
|
-
| "source-channel-contact"
|
|
105
|
-
| "vellum-anchor"
|
|
106
|
-
| "none" = "none";
|
|
106
|
+
let guardianResolutionSource: GuardianResolutionSource = "none";
|
|
107
107
|
|
|
108
108
|
const assistantGuardianPrincipalId =
|
|
109
109
|
ensureVellumGuardianBinding(canonicalAssistantId);
|
|
@@ -207,11 +207,19 @@ export function notifyGuardianOfAccessRequest(
|
|
|
207
207
|
// because the desktop path lacks the channel delivery context needed
|
|
208
208
|
// to deliver the verification code. Phone is excluded because it is
|
|
209
209
|
// not a deliverable notification channel.
|
|
210
|
+
// When the guardian was resolved via a verified same-channel contact,
|
|
211
|
+
// route only to that channel — delivering on desktop as well is noisy
|
|
212
|
+
// and the desktop path lacks the channel delivery context for approval.
|
|
213
|
+
// When the guardian was NOT verified on the source channel (e.g. resolved
|
|
214
|
+
// via vellum anchor), route to all channels so the guardian can see
|
|
215
|
+
// the request on desktop/other channels where they ARE verified.
|
|
210
216
|
const TEXT_CHANNELS_WITH_DELIVERY: ReadonlySet<string> = new Set([
|
|
211
217
|
"slack",
|
|
212
218
|
"telegram",
|
|
213
219
|
]);
|
|
214
|
-
const sameChannelOnly =
|
|
220
|
+
const sameChannelOnly =
|
|
221
|
+
TEXT_CHANNELS_WITH_DELIVERY.has(sourceChannel) &&
|
|
222
|
+
guardianResolutionSource === "source-channel-contact";
|
|
215
223
|
|
|
216
224
|
void emitNotificationSignal({
|
|
217
225
|
sourceEventName: "ingress.access_request",
|
|
@@ -226,7 +234,7 @@ export function notifyGuardianOfAccessRequest(
|
|
|
226
234
|
},
|
|
227
235
|
contextPayload: {
|
|
228
236
|
requestId,
|
|
229
|
-
requestCode: canonicalRequest.requestCode,
|
|
237
|
+
requestCode: canonicalRequest.requestCode ?? "",
|
|
230
238
|
sourceChannel,
|
|
231
239
|
conversationExternalId,
|
|
232
240
|
actorExternalId,
|
|
@@ -234,6 +242,7 @@ export function notifyGuardianOfAccessRequest(
|
|
|
234
242
|
actorUsername: actorUsername ?? null,
|
|
235
243
|
senderIdentifier,
|
|
236
244
|
guardianBindingChannel,
|
|
245
|
+
guardianResolutionSource,
|
|
237
246
|
previousMemberStatus: previousMemberStatus ?? null,
|
|
238
247
|
},
|
|
239
248
|
dedupeKey: `access-request:${canonicalRequest.id}`,
|
|
@@ -31,6 +31,7 @@ import {
|
|
|
31
31
|
createActorTokenRecord,
|
|
32
32
|
revokeByDeviceBinding as revokeActorTokensByDevice,
|
|
33
33
|
} from "../actor-token-store.js";
|
|
34
|
+
import { DAEMON_INTERNAL_ASSISTANT_ID } from "../assistant-scope.js";
|
|
34
35
|
import { getExternalAssistantId } from "./external-assistant-id.js";
|
|
35
36
|
import { CURRENT_POLICY_EPOCH } from "./policy.js";
|
|
36
37
|
import { hashToken, mintToken } from "./token-service.js";
|
|
@@ -107,7 +108,8 @@ function mintAccessToken(guardianPrincipalId: string): {
|
|
|
107
108
|
expiresAt: number;
|
|
108
109
|
issuedAt: number;
|
|
109
110
|
} {
|
|
110
|
-
const externalAssistantId =
|
|
111
|
+
const externalAssistantId =
|
|
112
|
+
getExternalAssistantId() ?? DAEMON_INTERNAL_ASSISTANT_ID;
|
|
111
113
|
const sub = `actor:${externalAssistantId}:${guardianPrincipalId}`;
|
|
112
114
|
|
|
113
115
|
const token = mintToken({
|
|
@@ -129,6 +129,7 @@ const ACTOR_ENDPOINTS: Array<{ endpoint: string; scopes: Scope[] }> = [
|
|
|
129
129
|
{ endpoint: "btw", scopes: ["chat.write"] },
|
|
130
130
|
{ endpoint: "conversations", scopes: ["chat.read"] },
|
|
131
131
|
{ endpoint: "conversations:DELETE", scopes: ["chat.write"] },
|
|
132
|
+
{ endpoint: "conversations/fork", scopes: ["chat.write"] },
|
|
132
133
|
{ endpoint: "conversations/switch", scopes: ["chat.write"] },
|
|
133
134
|
{ endpoint: "conversations/name", scopes: ["chat.write"] },
|
|
134
135
|
{ endpoint: "conversations/cancel", scopes: ["chat.write"] },
|
|
@@ -342,6 +343,10 @@ const ACTOR_ENDPOINTS: Array<{ endpoint: string; scopes: Scope[] }> = [
|
|
|
342
343
|
{ endpoint: "model:PUT", scopes: ["settings.write"] },
|
|
343
344
|
{ endpoint: "model/image-gen", scopes: ["settings.write"] },
|
|
344
345
|
|
|
346
|
+
// Embedding config
|
|
347
|
+
{ endpoint: "config/embeddings:GET", scopes: ["settings.read"] },
|
|
348
|
+
{ endpoint: "config/embeddings:PUT", scopes: ["settings.write"] },
|
|
349
|
+
|
|
345
350
|
// Conversation management
|
|
346
351
|
{ endpoint: "conversations/wipe", scopes: ["chat.write"] },
|
|
347
352
|
{ endpoint: "conversations/reorder", scopes: ["chat.write"] },
|
|
@@ -351,6 +356,7 @@ const ACTOR_ENDPOINTS: Array<{ endpoint: string; scopes: Scope[] }> = [
|
|
|
351
356
|
|
|
352
357
|
// Message content
|
|
353
358
|
{ endpoint: "messages/content", scopes: ["chat.read"] },
|
|
359
|
+
{ endpoint: "messages/llm-context", scopes: ["chat.read"] },
|
|
354
360
|
|
|
355
361
|
// Queued message deletion
|
|
356
362
|
{ endpoint: "messages/queued", scopes: ["chat.write"] },
|
|
@@ -435,7 +441,14 @@ const ACTOR_ENDPOINTS: Array<{ endpoint: string; scopes: Scope[] }> = [
|
|
|
435
441
|
{ endpoint: "dictation", scopes: ["chat.write"] },
|
|
436
442
|
|
|
437
443
|
// OAuth / integrations
|
|
438
|
-
{ endpoint: "
|
|
444
|
+
{ endpoint: "oauth/start", scopes: ["settings.write"] },
|
|
445
|
+
{ endpoint: "integrations/oauth/start", scopes: ["settings.write"] }, // legacy alias
|
|
446
|
+
{ endpoint: "oauth/apps", scopes: ["settings.read"] },
|
|
447
|
+
{ endpoint: "oauth/apps.create", scopes: ["settings.write"] },
|
|
448
|
+
{ endpoint: "oauth/apps.delete", scopes: ["settings.write"] },
|
|
449
|
+
{ endpoint: "oauth/apps/connections", scopes: ["settings.read"] },
|
|
450
|
+
{ endpoint: "oauth/apps/connect", scopes: ["settings.write"] },
|
|
451
|
+
{ endpoint: "oauth/connections", scopes: ["settings.write"] },
|
|
439
452
|
|
|
440
453
|
// Ingress config
|
|
441
454
|
{ endpoint: "integrations/ingress/config:GET", scopes: ["settings.read"] },
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { buildToolDefinitions } from "../daemon/conversation-tool-setup.js";
|
|
2
|
+
import { buildSystemPrompt } from "../prompts/system-prompt.js";
|
|
3
|
+
import {
|
|
4
|
+
createTimeout,
|
|
5
|
+
extractAllText,
|
|
6
|
+
userMessage,
|
|
7
|
+
} from "../providers/provider-send-message.js";
|
|
8
|
+
import type {
|
|
9
|
+
Message,
|
|
10
|
+
ModelIntent,
|
|
11
|
+
Provider,
|
|
12
|
+
ProviderEvent,
|
|
13
|
+
ProviderResponse,
|
|
14
|
+
ToolDefinition,
|
|
15
|
+
} from "../providers/types.js";
|
|
16
|
+
|
|
17
|
+
export interface BtwSidechainConversationLike {
|
|
18
|
+
provider: Provider;
|
|
19
|
+
systemPrompt: string;
|
|
20
|
+
hasSystemPromptOverride?: boolean;
|
|
21
|
+
getMessages(): Message[];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface RunBtwSidechainParams {
|
|
25
|
+
content: string;
|
|
26
|
+
conversation?: BtwSidechainConversationLike;
|
|
27
|
+
provider?: Provider;
|
|
28
|
+
messages?: Message[];
|
|
29
|
+
systemPrompt?: string;
|
|
30
|
+
tools?: ToolDefinition[];
|
|
31
|
+
maxTokens?: number;
|
|
32
|
+
modelIntent?: ModelIntent;
|
|
33
|
+
signal?: AbortSignal;
|
|
34
|
+
timeoutMs?: number;
|
|
35
|
+
onEvent?: (event: ProviderEvent) => void;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface RunBtwSidechainResult {
|
|
39
|
+
text: string;
|
|
40
|
+
hadTextDeltas: boolean;
|
|
41
|
+
response: ProviderResponse;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Run an ephemeral BTW-style side-chain LLM call.
|
|
46
|
+
*
|
|
47
|
+
* This mirrors the /v1/btw route behavior: no message persistence, tool_choice
|
|
48
|
+
* forced to none, latency-optimized by default, and the standard system prompt
|
|
49
|
+
* with BOOTSTRAP.md excluded unless an explicit system prompt override exists.
|
|
50
|
+
*/
|
|
51
|
+
export async function runBtwSidechain(
|
|
52
|
+
params: RunBtwSidechainParams,
|
|
53
|
+
): Promise<RunBtwSidechainResult> {
|
|
54
|
+
const trimmedContent = params.content.trim();
|
|
55
|
+
const provider = params.provider ?? params.conversation?.provider;
|
|
56
|
+
if (!provider) {
|
|
57
|
+
throw new Error("BTW side-chain requires a provider");
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const tools = params.tools ?? buildToolDefinitions();
|
|
61
|
+
const history = params.messages ?? params.conversation?.getMessages() ?? [];
|
|
62
|
+
const messages = [...history, userMessage(trimmedContent)];
|
|
63
|
+
const systemPrompt =
|
|
64
|
+
params.systemPrompt ??
|
|
65
|
+
(params.conversation?.hasSystemPromptOverride
|
|
66
|
+
? params.conversation.systemPrompt
|
|
67
|
+
: buildSystemPrompt({ excludeBootstrap: true }));
|
|
68
|
+
|
|
69
|
+
const { signal: timeoutSignal, cleanup } = createTimeout(
|
|
70
|
+
params.timeoutMs ?? 30_000,
|
|
71
|
+
);
|
|
72
|
+
const combinedSignal = params.signal
|
|
73
|
+
? AbortSignal.any([params.signal, timeoutSignal])
|
|
74
|
+
: timeoutSignal;
|
|
75
|
+
|
|
76
|
+
let collectedText = "";
|
|
77
|
+
let hadTextDeltas = false;
|
|
78
|
+
|
|
79
|
+
try {
|
|
80
|
+
const response = await provider.sendMessage(messages, tools, systemPrompt, {
|
|
81
|
+
config: {
|
|
82
|
+
max_tokens: params.maxTokens ?? 1024,
|
|
83
|
+
tool_choice: { type: "none" },
|
|
84
|
+
modelIntent: params.modelIntent ?? "latency-optimized",
|
|
85
|
+
},
|
|
86
|
+
onEvent: (event) => {
|
|
87
|
+
if (event.type === "text_delta") {
|
|
88
|
+
hadTextDeltas = true;
|
|
89
|
+
collectedText += event.text;
|
|
90
|
+
}
|
|
91
|
+
params.onEvent?.(event);
|
|
92
|
+
},
|
|
93
|
+
signal: combinedSignal,
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
const text = collectedText.trim() || extractAllText(response).trim();
|
|
97
|
+
return { text, hadTextDeltas, response };
|
|
98
|
+
} finally {
|
|
99
|
+
cleanup();
|
|
100
|
+
}
|
|
101
|
+
}
|
|
@@ -45,14 +45,24 @@ function sleep(ms: number): Promise<void> {
|
|
|
45
45
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
+
const NO_RESPONSE_RE = /^\s*<no_response\s*\/?>\s*$/;
|
|
49
|
+
|
|
50
|
+
/** Returns true when any segment is a `<no_response/>` sentinel. */
|
|
51
|
+
function hasNoResponseMarker(textSegments: string[]): boolean {
|
|
52
|
+
return textSegments.some((s) => NO_RESPONSE_RE.test(s));
|
|
53
|
+
}
|
|
54
|
+
|
|
48
55
|
function toDeliverableTextSegments(
|
|
49
56
|
textSegments: string[],
|
|
50
57
|
fallbackText?: string,
|
|
51
58
|
): string[] {
|
|
52
59
|
const nonEmptySegments = textSegments.filter(
|
|
53
|
-
(segment) => segment.trim().length > 0,
|
|
60
|
+
(segment) => segment.trim().length > 0 && !NO_RESPONSE_RE.test(segment),
|
|
54
61
|
);
|
|
55
62
|
if (nonEmptySegments.length > 0) return nonEmptySegments;
|
|
63
|
+
// If the only text was <no_response/>, treat as intentional silence —
|
|
64
|
+
// do not fall back to fallbackText.
|
|
65
|
+
if (hasNoResponseMarker(textSegments)) return [];
|
|
56
66
|
if (typeof fallbackText === "string" && fallbackText.trim().length > 0) {
|
|
57
67
|
return [fallbackText];
|
|
58
68
|
}
|
|
@@ -86,6 +96,12 @@ export async function deliverRenderedReplyViaCallback(
|
|
|
86
96
|
const replyAttachments =
|
|
87
97
|
attachments && attachments.length > 0 ? attachments : undefined;
|
|
88
98
|
|
|
99
|
+
// If the model output <no_response/> and no other deliverable text remains,
|
|
100
|
+
// suppress all delivery — including attachments — so nothing is posted.
|
|
101
|
+
if (deliverableSegments.length === 0 && hasNoResponseMarker(textSegments)) {
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
|
|
89
105
|
if (deliverableSegments.length === 0) {
|
|
90
106
|
if (replyAttachments) {
|
|
91
107
|
const result: ChannelDeliveryResult = await deliverChannelReply(
|
|
@@ -88,7 +88,9 @@ export class HttpRouter {
|
|
|
88
88
|
): Promise<Response | null> {
|
|
89
89
|
// Normalize trailing slashes so "/integrations/twilio/config/" matches
|
|
90
90
|
// a route defined as "integrations/twilio/config".
|
|
91
|
-
const normalized = endpoint.endsWith("/")
|
|
91
|
+
const normalized = endpoint.endsWith("/")
|
|
92
|
+
? endpoint.slice(0, -1)
|
|
93
|
+
: endpoint;
|
|
92
94
|
|
|
93
95
|
for (const compiled of this.compiledRoutes) {
|
|
94
96
|
if (compiled.def.method !== req.method) continue;
|