@vellumai/assistant 0.5.0 → 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__/assistant-feature-flags-integration.test.ts +7 -9
- 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-execution-feature-gates.test.ts +3 -3
- 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__/filesystem-tools.test.ts +4 -2
- 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 +103 -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__/skill-feature-flags-integration.test.ts +18 -17
- package/src/__tests__/skill-feature-flags.test.ts +13 -13
- package/src/__tests__/skill-load-feature-flag.test.ts +4 -4
- 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__/system-prompt.test.ts +8 -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 +16 -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 +46 -42
- 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/history-repair.ts +28 -8
- 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 +62 -19
- package/src/prompts/system-prompt.ts +2 -0
- 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 +4 -21
- 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
|
@@ -70,21 +70,53 @@ describe("injectActivityField", () => {
|
|
|
70
70
|
expect("activity" in props0).toBe(false);
|
|
71
71
|
});
|
|
72
72
|
|
|
73
|
-
test("
|
|
73
|
+
test("returns unchanged when activity is in top-level properties but not required", () => {
|
|
74
74
|
const defs = [
|
|
75
75
|
makeDef("my_tool", {
|
|
76
76
|
type: "object",
|
|
77
77
|
properties: { activity: { type: "number" } },
|
|
78
|
-
required: [],
|
|
78
|
+
required: ["foo"],
|
|
79
79
|
}),
|
|
80
80
|
];
|
|
81
81
|
const result = injectActivityField(defs);
|
|
82
|
-
// Should be the exact same object reference (no
|
|
82
|
+
// Should be the exact same object reference (no modification)
|
|
83
83
|
expect(Object.is(result[0], defs[0])).toBe(true);
|
|
84
84
|
const schema = result[0].input_schema as Record<string, unknown>;
|
|
85
85
|
const props = schema.properties as Record<string, unknown>;
|
|
86
86
|
// Original activity type preserved
|
|
87
87
|
expect(props.activity).toEqual({ type: "number" });
|
|
88
|
+
// required NOT modified — don't promote server-defined optional activity
|
|
89
|
+
expect(schema.required).toEqual(["foo"]);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
test("returns unchanged when activity is in both top-level properties AND required", () => {
|
|
93
|
+
const defs = [
|
|
94
|
+
makeDef("my_tool", {
|
|
95
|
+
type: "object",
|
|
96
|
+
properties: { activity: { type: "string" } },
|
|
97
|
+
required: ["activity"],
|
|
98
|
+
}),
|
|
99
|
+
];
|
|
100
|
+
const result = injectActivityField(defs);
|
|
101
|
+
const schema = result[0].input_schema as Record<string, unknown>;
|
|
102
|
+
const props = schema.properties as Record<string, unknown>;
|
|
103
|
+
// Original activity type preserved
|
|
104
|
+
expect(props.activity).toEqual({ type: "string" });
|
|
105
|
+
// activity must be in required even though it was already in properties
|
|
106
|
+
expect(schema.required).toEqual(["activity"]);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
test("skips tools that already have activity in both properties and required", () => {
|
|
110
|
+
const defs = [
|
|
111
|
+
makeDef("my_tool", {
|
|
112
|
+
type: "object",
|
|
113
|
+
properties: { activity: { type: "number" } },
|
|
114
|
+
required: ["activity"],
|
|
115
|
+
}),
|
|
116
|
+
];
|
|
117
|
+
const result = injectActivityField(defs);
|
|
118
|
+
// Should be the exact same object reference (no clone needed)
|
|
119
|
+
expect(Object.is(result[0], defs[0])).toBe(true);
|
|
88
120
|
});
|
|
89
121
|
|
|
90
122
|
test("does NOT mutate original definition objects", () => {
|
|
@@ -125,6 +157,60 @@ describe("injectActivityField", () => {
|
|
|
125
157
|
expect(Object.is(result[0], defs[0])).toBe(true);
|
|
126
158
|
});
|
|
127
159
|
|
|
160
|
+
test("does NOT add activity to top-level required when only in oneOf branch", () => {
|
|
161
|
+
const defs = [
|
|
162
|
+
makeDef("my_tool", {
|
|
163
|
+
type: "object",
|
|
164
|
+
properties: { shared: { type: "string" } },
|
|
165
|
+
oneOf: [
|
|
166
|
+
{
|
|
167
|
+
properties: {
|
|
168
|
+
activity: { type: "string" },
|
|
169
|
+
branch_a: { type: "number" },
|
|
170
|
+
},
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
properties: { branch_b: { type: "boolean" } },
|
|
174
|
+
},
|
|
175
|
+
],
|
|
176
|
+
required: ["shared"],
|
|
177
|
+
}),
|
|
178
|
+
];
|
|
179
|
+
const result = injectActivityField(defs);
|
|
180
|
+
// Should be the exact same object reference (no modification)
|
|
181
|
+
expect(Object.is(result[0], defs[0])).toBe(true);
|
|
182
|
+
const schema = result[0].input_schema as Record<string, unknown>;
|
|
183
|
+
// Top-level required should NOT include activity
|
|
184
|
+
expect(schema.required).toEqual(["shared"]);
|
|
185
|
+
// Top-level properties should NOT have activity injected
|
|
186
|
+
const props = schema.properties as Record<string, unknown>;
|
|
187
|
+
expect("activity" in props).toBe(false);
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
test("does NOT add activity to top-level required when only in allOf sub-schema with additionalProperties: false", () => {
|
|
191
|
+
const defs = [
|
|
192
|
+
makeDef("my_tool", {
|
|
193
|
+
type: "object",
|
|
194
|
+
properties: { foo: { type: "string" } },
|
|
195
|
+
additionalProperties: false,
|
|
196
|
+
allOf: [
|
|
197
|
+
{
|
|
198
|
+
properties: { activity: { type: "string" } },
|
|
199
|
+
},
|
|
200
|
+
],
|
|
201
|
+
required: ["foo"],
|
|
202
|
+
}),
|
|
203
|
+
];
|
|
204
|
+
const result = injectActivityField(defs);
|
|
205
|
+
// Should be the exact same object reference (no modification)
|
|
206
|
+
expect(Object.is(result[0], defs[0])).toBe(true);
|
|
207
|
+
const schema = result[0].input_schema as Record<string, unknown>;
|
|
208
|
+
// Top-level required should NOT include activity
|
|
209
|
+
expect(schema.required).toEqual(["foo"]);
|
|
210
|
+
const props = schema.properties as Record<string, unknown>;
|
|
211
|
+
expect("activity" in props).toBe(false);
|
|
212
|
+
});
|
|
213
|
+
|
|
128
214
|
test("skips tools with activity defined inside allOf member (composite schema)", () => {
|
|
129
215
|
const defs = [
|
|
130
216
|
makeDef("my_tool", {
|
|
@@ -139,18 +225,92 @@ describe("injectActivityField", () => {
|
|
|
139
225
|
}),
|
|
140
226
|
];
|
|
141
227
|
const result = injectActivityField(defs);
|
|
142
|
-
// Should be the exact same object reference (no
|
|
228
|
+
// Should be the exact same object reference (no modification)
|
|
143
229
|
expect(Object.is(result[0], defs[0])).toBe(true);
|
|
144
230
|
const schema = result[0].input_schema as Record<string, unknown>;
|
|
145
231
|
const props = schema.properties as Record<string, unknown>;
|
|
146
|
-
// Top-level properties should NOT have activity injected
|
|
232
|
+
// Top-level properties should NOT have activity injected (it's in allOf)
|
|
147
233
|
expect("activity" in props).toBe(false);
|
|
234
|
+
// Top-level required should NOT include activity (it's only in composite sub-schemas)
|
|
235
|
+
expect(schema.required).toEqual([]);
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
test("skips allOf composite schema where activity is already required", () => {
|
|
239
|
+
const defs = [
|
|
240
|
+
makeDef("my_tool", {
|
|
241
|
+
type: "object",
|
|
242
|
+
properties: { foo: { type: "string" } },
|
|
243
|
+
allOf: [
|
|
244
|
+
{
|
|
245
|
+
properties: { activity: { type: "string" } },
|
|
246
|
+
},
|
|
247
|
+
],
|
|
248
|
+
required: ["activity"],
|
|
249
|
+
}),
|
|
250
|
+
];
|
|
251
|
+
const result = injectActivityField(defs);
|
|
252
|
+
// Should be the exact same object reference (no change needed)
|
|
253
|
+
expect(Object.is(result[0], defs[0])).toBe(true);
|
|
148
254
|
});
|
|
149
255
|
|
|
150
256
|
test("handles empty definitions array", () => {
|
|
151
257
|
const result = injectActivityField([]);
|
|
152
258
|
expect(result).toEqual([]);
|
|
153
259
|
});
|
|
260
|
+
|
|
261
|
+
test("injects activity only on tools that don't define it at all", () => {
|
|
262
|
+
const defs = [
|
|
263
|
+
// Normal tool without activity — should get it injected
|
|
264
|
+
makeDef("tool_a", {
|
|
265
|
+
type: "object",
|
|
266
|
+
properties: { foo: { type: "string" } },
|
|
267
|
+
required: ["foo"],
|
|
268
|
+
}),
|
|
269
|
+
// Tool defines activity in properties but NOT in required — left unchanged
|
|
270
|
+
makeDef("tool_b", {
|
|
271
|
+
type: "object",
|
|
272
|
+
properties: {
|
|
273
|
+
bar: { type: "string" },
|
|
274
|
+
activity: { type: "string", description: "custom activity" },
|
|
275
|
+
},
|
|
276
|
+
required: ["bar"],
|
|
277
|
+
}),
|
|
278
|
+
// Tool that defines activity in both properties AND required — left unchanged
|
|
279
|
+
makeDef("tool_c", {
|
|
280
|
+
type: "object",
|
|
281
|
+
properties: {
|
|
282
|
+
baz: { type: "number" },
|
|
283
|
+
activity: { type: "string", description: "custom activity" },
|
|
284
|
+
},
|
|
285
|
+
required: ["baz", "activity"],
|
|
286
|
+
}),
|
|
287
|
+
// Non-object schema — should be left alone
|
|
288
|
+
makeDef("tool_d", { type: "string" }),
|
|
289
|
+
// Object schema without properties — should be left alone
|
|
290
|
+
makeDef("tool_e", { type: "object" }),
|
|
291
|
+
];
|
|
292
|
+
|
|
293
|
+
const result = injectActivityField(defs);
|
|
294
|
+
|
|
295
|
+
// tool_a: activity injected and required
|
|
296
|
+
const schemaA = result[0].input_schema as Record<string, unknown>;
|
|
297
|
+
expect(
|
|
298
|
+
(schemaA.properties as Record<string, unknown>).activity,
|
|
299
|
+
).toBeDefined();
|
|
300
|
+
expect(schemaA.required).toEqual(["foo", "activity"]);
|
|
301
|
+
|
|
302
|
+
// tool_b: unchanged (activity optional, not promoted)
|
|
303
|
+
expect(Object.is(result[1], defs[1])).toBe(true);
|
|
304
|
+
const schemaB = result[1].input_schema as Record<string, unknown>;
|
|
305
|
+
expect(schemaB.required).toEqual(["bar"]);
|
|
306
|
+
|
|
307
|
+
// tool_c: unchanged (activity already present and required)
|
|
308
|
+
expect(Object.is(result[2], defs[2])).toBe(true);
|
|
309
|
+
|
|
310
|
+
// tool_d, tool_e: unchanged
|
|
311
|
+
expect(Object.is(result[3], defs[3])).toBe(true);
|
|
312
|
+
expect(Object.is(result[4], defs[4])).toBe(true);
|
|
313
|
+
});
|
|
154
314
|
});
|
|
155
315
|
|
|
156
316
|
describe("schemaDefinesProperty", () => {
|
|
@@ -330,7 +330,7 @@ describe("getAttachmentsForMessage", () => {
|
|
|
330
330
|
|
|
331
331
|
test("returns attachments linked to a message", async () => {
|
|
332
332
|
const msgId = await createMessage("assistant", "Here is a chart");
|
|
333
|
-
const stored = uploadAttachment("chart.png", "image/png", "
|
|
333
|
+
const stored = uploadAttachment("chart.png", "image/png", "iVBORw==");
|
|
334
334
|
linkAttachmentToMessage(msgId, stored.id, 0);
|
|
335
335
|
|
|
336
336
|
const result = getAttachmentsForMessage(msgId);
|
|
@@ -338,7 +338,7 @@ describe("getAttachmentsForMessage", () => {
|
|
|
338
338
|
expect(result[0].id).toBe(stored.id);
|
|
339
339
|
expect(result[0].originalFilename).toBe("chart.png");
|
|
340
340
|
expect(result[0].mimeType).toBe("image/png");
|
|
341
|
-
expect(result[0].dataBase64).toBe("
|
|
341
|
+
expect(result[0].dataBase64).toBe("iVBORw==");
|
|
342
342
|
});
|
|
343
343
|
|
|
344
344
|
test("returns empty array when no attachments are linked", () => {
|
|
@@ -138,14 +138,15 @@ describe("frontmatter feature-flag integration", () => {
|
|
|
138
138
|
expect(key).toBeUndefined();
|
|
139
139
|
});
|
|
140
140
|
|
|
141
|
-
test("resolveSkillStates
|
|
141
|
+
test("resolveSkillStates includes skill with featureFlag when flag defaults to ON", () => {
|
|
142
142
|
const skill = buildSkillSummary("contacts", SKILL_MD_WITH_FLAG)!;
|
|
143
|
-
// "contacts" is in the registry with defaultEnabled:
|
|
143
|
+
// "contacts" is in the registry with defaultEnabled: true
|
|
144
144
|
const config = makeConfig();
|
|
145
145
|
|
|
146
146
|
const resolved = resolveSkillStates([skill], config);
|
|
147
|
-
// Flag defaults to
|
|
148
|
-
expect(resolved.length).toBe(
|
|
147
|
+
// Flag defaults to true → skill passes through
|
|
148
|
+
expect(resolved.length).toBe(1);
|
|
149
|
+
expect(resolved[0].summary.id).toBe("contacts");
|
|
149
150
|
});
|
|
150
151
|
|
|
151
152
|
test("resolveSkillStates includes skill with featureFlag when flag is ON", () => {
|
|
@@ -192,22 +193,22 @@ describe("frontmatter feature-flag integration", () => {
|
|
|
192
193
|
const key = skillFlagKey(skill);
|
|
193
194
|
expect(key).toBe("feature_flags.contacts.enabled");
|
|
194
195
|
|
|
195
|
-
// Step 4: Check flag state — "contacts" has defaultEnabled:
|
|
196
|
-
const
|
|
197
|
-
expect(isAssistantFeatureFlagEnabled(key!,
|
|
196
|
+
// Step 4: Check flag state — "contacts" has defaultEnabled: true in registry
|
|
197
|
+
const configDefault = makeConfig();
|
|
198
|
+
expect(isAssistantFeatureFlagEnabled(key!, configDefault)).toBe(true);
|
|
198
199
|
|
|
199
|
-
// Step 5: resolveSkillStates
|
|
200
|
-
const
|
|
201
|
-
expect(
|
|
200
|
+
// Step 5: resolveSkillStates includes it by default
|
|
201
|
+
const resolvedDefault = resolveSkillStates([skill], configDefault);
|
|
202
|
+
expect(resolvedDefault.length).toBe(1);
|
|
203
|
+
expect(resolvedDefault[0].summary.id).toBe("contacts");
|
|
202
204
|
|
|
203
|
-
// Step 6: With override
|
|
204
|
-
const
|
|
205
|
-
assistantFeatureFlagValues: { [key!]:
|
|
205
|
+
// Step 6: With override disabled, skill is filtered out
|
|
206
|
+
const configOff = makeConfig({
|
|
207
|
+
assistantFeatureFlagValues: { [key!]: false },
|
|
206
208
|
});
|
|
207
|
-
expect(isAssistantFeatureFlagEnabled(key!,
|
|
209
|
+
expect(isAssistantFeatureFlagEnabled(key!, configOff)).toBe(false);
|
|
208
210
|
|
|
209
|
-
const
|
|
210
|
-
expect(
|
|
211
|
-
expect(resolvedOn[0].summary.id).toBe("contacts");
|
|
211
|
+
const resolvedOff = resolveSkillStates([skill], configOff);
|
|
212
|
+
expect(resolvedOff.length).toBe(0);
|
|
212
213
|
});
|
|
213
214
|
});
|
|
@@ -81,14 +81,14 @@ describe("skillFlagKey", () => {
|
|
|
81
81
|
// ---------------------------------------------------------------------------
|
|
82
82
|
|
|
83
83
|
describe("isAssistantFeatureFlagEnabled with skillFlagKey", () => {
|
|
84
|
-
test("returns
|
|
84
|
+
test("returns true when no flag overrides (registry default is true)", () => {
|
|
85
85
|
const config = makeConfig();
|
|
86
86
|
expect(
|
|
87
87
|
isAssistantFeatureFlagEnabled(
|
|
88
88
|
skillFlagKey({ featureFlag: DECLARED_FLAG_ID })!,
|
|
89
89
|
config,
|
|
90
90
|
),
|
|
91
|
-
).toBe(
|
|
91
|
+
).toBe(true);
|
|
92
92
|
});
|
|
93
93
|
|
|
94
94
|
test("returns true when skill key is explicitly true", () => {
|
|
@@ -140,10 +140,8 @@ describe("isAssistantFeatureFlagEnabled", () => {
|
|
|
140
140
|
|
|
141
141
|
test("falls back to registry default when no override", () => {
|
|
142
142
|
const config = makeConfig();
|
|
143
|
-
// contacts defaults to
|
|
144
|
-
expect(isAssistantFeatureFlagEnabled(DECLARED_FLAG_KEY, config)).toBe(
|
|
145
|
-
false,
|
|
146
|
-
);
|
|
143
|
+
// contacts defaults to true in the registry
|
|
144
|
+
expect(isAssistantFeatureFlagEnabled(DECLARED_FLAG_KEY, config)).toBe(true);
|
|
147
145
|
});
|
|
148
146
|
|
|
149
147
|
test("respects persisted overrides for undeclared keys", () => {
|
|
@@ -207,13 +205,14 @@ describe("resolveSkillStates with feature flags", () => {
|
|
|
207
205
|
expect(ids).toContain("browser");
|
|
208
206
|
});
|
|
209
207
|
|
|
210
|
-
test("declared flag key defaults to registry value (
|
|
208
|
+
test("declared flag key defaults to registry value (true)", () => {
|
|
211
209
|
const catalog = [makeSkill(DECLARED_SKILL_ID, "bundled", DECLARED_FLAG_ID)];
|
|
212
210
|
const config = makeConfig();
|
|
213
211
|
|
|
214
212
|
const resolved = resolveSkillStates(catalog, config);
|
|
215
|
-
// contacts registry default is
|
|
216
|
-
expect(resolved.length).toBe(
|
|
213
|
+
// contacts registry default is true, so it passes through
|
|
214
|
+
expect(resolved.length).toBe(1);
|
|
215
|
+
expect(resolved[0].summary.id).toBe(DECLARED_SKILL_ID);
|
|
217
216
|
});
|
|
218
217
|
|
|
219
218
|
test("skill without featureFlag is never flag-gated", () => {
|
|
@@ -280,14 +279,15 @@ describe("resolveSkillStates with feature flags", () => {
|
|
|
280
279
|
// ---------------------------------------------------------------------------
|
|
281
280
|
|
|
282
281
|
describe("resolveSkillStates with frontmatter featureFlag", () => {
|
|
283
|
-
test("skill with featureFlag (defaultEnabled:
|
|
284
|
-
// contacts has defaultEnabled:
|
|
282
|
+
test("skill with featureFlag (defaultEnabled: true) is included when no config override", () => {
|
|
283
|
+
// contacts has defaultEnabled: true in the registry
|
|
285
284
|
const catalog = [makeSkill(DECLARED_SKILL_ID, "bundled", DECLARED_FLAG_ID)];
|
|
286
285
|
const config = makeConfig();
|
|
287
286
|
|
|
288
287
|
const resolved = resolveSkillStates(catalog, config);
|
|
289
|
-
// No override, registry default is
|
|
290
|
-
expect(resolved.length).toBe(
|
|
288
|
+
// No override, registry default is true → passes through
|
|
289
|
+
expect(resolved.length).toBe(1);
|
|
290
|
+
expect(resolved[0].summary.id).toBe(DECLARED_SKILL_ID);
|
|
291
291
|
});
|
|
292
292
|
|
|
293
293
|
test("skill with featureFlag is included when config override enables it", () => {
|
|
@@ -166,7 +166,7 @@ describe("skill_load feature flag enforcement", () => {
|
|
|
166
166
|
expect(result.content).toContain("Skill: Contacts");
|
|
167
167
|
});
|
|
168
168
|
|
|
169
|
-
test("
|
|
169
|
+
test("loads skill when flag key is absent (registry defaults to enabled)", async () => {
|
|
170
170
|
writeSkill(
|
|
171
171
|
DECLARED_SKILL_ID,
|
|
172
172
|
"Contacts",
|
|
@@ -184,8 +184,8 @@ describe("skill_load feature flag enforcement", () => {
|
|
|
184
184
|
|
|
185
185
|
const result = await executeSkillLoad({ skill: DECLARED_SKILL_ID });
|
|
186
186
|
|
|
187
|
-
// contacts is declared in the registry with defaultEnabled:
|
|
188
|
-
expect(result.isError).toBe(
|
|
189
|
-
expect(result.content).toContain("
|
|
187
|
+
// contacts is declared in the registry with defaultEnabled: true
|
|
188
|
+
expect(result.isError).toBe(false);
|
|
189
|
+
expect(result.content).toContain("Skill: Contacts");
|
|
190
190
|
});
|
|
191
191
|
});
|
|
@@ -9,7 +9,9 @@ const skillContent = readFileSync(SKILL_PATH, "utf-8");
|
|
|
9
9
|
|
|
10
10
|
describe("slack-app-setup skill regression", () => {
|
|
11
11
|
test("keeps Slack token collection on the secure credential prompt path", () => {
|
|
12
|
-
expect(skillContent).toContain(
|
|
12
|
+
expect(skillContent).toContain(
|
|
13
|
+
'`credential_store` with `action: "prompt"`',
|
|
14
|
+
);
|
|
13
15
|
expect(skillContent).toContain(
|
|
14
16
|
"same Slack settings handler used by Settings",
|
|
15
17
|
);
|
|
@@ -163,11 +163,11 @@ describe("Slack inbound trusted contact verification", () => {
|
|
|
163
163
|
// Verification code is NOT sent to the requester — only the guardian
|
|
164
164
|
// receives it via the access request notification flow
|
|
165
165
|
|
|
166
|
-
// Channel reply tells user
|
|
166
|
+
// Channel reply tells user they're not recognized yet
|
|
167
167
|
expect(deliverReplyCalls.length).toBe(1);
|
|
168
168
|
expect(
|
|
169
169
|
(deliverReplyCalls[0].payload as Record<string, unknown>).text,
|
|
170
|
-
).toContain("
|
|
170
|
+
).toContain("I don't recognize you yet");
|
|
171
171
|
});
|
|
172
172
|
|
|
173
173
|
test("verification session is identity-bound to the Slack user", async () => {
|
|
@@ -39,6 +39,7 @@ function makeContext(): SurfaceConversationContext {
|
|
|
39
39
|
>(),
|
|
40
40
|
surfaceState: new Map(),
|
|
41
41
|
surfaceUndoStacks: new Map(),
|
|
42
|
+
accumulatedSurfaceState: new Map(),
|
|
42
43
|
surfaceActionRequestIds: new Set<string>(),
|
|
43
44
|
currentTurnSurfaces: [],
|
|
44
45
|
isProcessing: () => false,
|