@vellumai/assistant 0.4.44 → 0.4.45
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/.prettierignore +4 -0
- package/ARCHITECTURE.md +34 -31
- package/README.md +4 -4
- package/bun.lock +10 -35
- package/docs/architecture/integrations.md +102 -197
- package/docs/architecture/keychain-broker.md +1 -1
- package/docs/architecture/memory.md +2 -2
- package/docs/architecture/scheduling.md +1 -1
- package/docs/architecture/security.md +11 -11
- package/docs/error-handling.md +1 -1
- package/docs/trusted-contact-access.md +3 -3
- package/drizzle/meta/0000_snapshot.json +34 -100
- package/drizzle/meta/_journal.json +1 -1
- package/drizzle.config.ts +4 -4
- package/package.json +3 -2
- package/scripts/capture-x-graphql.ts +237 -141
- package/scripts/generate-bundled-tool-registry.ts +223 -0
- package/src/__tests__/access-request-decision.test.ts +0 -1
- package/src/__tests__/actor-token-service.test.ts +23 -24
- package/src/__tests__/agent-loop.test.ts +0 -131
- package/src/__tests__/always-loaded-tools-guard.test.ts +71 -0
- package/src/__tests__/amazon-cdp-integration.test.ts +11 -9
- package/src/__tests__/approval-primitive.test.ts +0 -1
- package/src/__tests__/approval-routes-http.test.ts +11 -1
- package/src/__tests__/asset-materialize-tool.test.ts +0 -1
- package/src/__tests__/asset-search-tool.test.ts +0 -1
- package/src/__tests__/assistant-attachment-directive.test.ts +1 -1
- package/src/__tests__/assistant-events-sse-hardening.test.ts +0 -1
- package/src/__tests__/assistant-feature-flag-guardrails.test.ts +0 -2
- package/src/__tests__/assistant-feature-flags-integration.test.ts +70 -18
- package/src/__tests__/assistant-id-boundary-guard.test.ts +6 -6
- package/src/__tests__/attachments-store.test.ts +0 -1
- package/src/__tests__/avatar-e2e.test.ts +74 -115
- package/src/__tests__/avatar-router.test.ts +25 -62
- package/src/__tests__/browser-manager.test.ts +24 -0
- package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +4 -3
- package/src/__tests__/browser-skill-endstate.test.ts +8 -11
- package/src/__tests__/btw-routes.test.ts +326 -0
- package/src/__tests__/bundled-skill-retrieval-guard.test.ts +23 -9
- package/src/__tests__/call-controller.test.ts +0 -1
- package/src/__tests__/call-conversation-messages.test.ts +0 -1
- package/src/__tests__/call-domain.test.ts +0 -1
- package/src/__tests__/call-pointer-messages.test.ts +0 -1
- package/src/__tests__/call-recovery.test.ts +0 -1
- package/src/__tests__/call-routes-http.test.ts +0 -1
- package/src/__tests__/call-store.test.ts +0 -1
- package/src/__tests__/canonical-guardian-store.test.ts +0 -1
- package/src/__tests__/channel-approval-routes.test.ts +1 -1
- package/src/__tests__/channel-approvals.test.ts +1 -1
- package/src/__tests__/channel-delivery-store.test.ts +0 -1
- package/src/__tests__/channel-guardian.test.ts +5 -7
- package/src/__tests__/channel-retry-sweep.test.ts +0 -1
- package/src/__tests__/checker.test.ts +4 -11
- package/src/__tests__/compaction.benchmark.test.ts +16 -14
- package/src/__tests__/computer-use-session-lifecycle.test.ts +10 -11
- package/src/__tests__/computer-use-session-working-dir.test.ts +2 -6
- package/src/__tests__/computer-use-skill-lifecycle-cleanup.test.ts +2 -5
- package/src/__tests__/computer-use-tools.test.ts +35 -31
- package/src/__tests__/config-schema.test.ts +11 -15
- package/src/__tests__/config-watcher.test.ts +0 -1
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +0 -1
- package/src/__tests__/conflict-store.test.ts +0 -1
- package/src/__tests__/connection-policy.test.ts +4 -7
- package/src/__tests__/contacts-tools.test.ts +0 -1
- package/src/__tests__/context-memory-e2e.test.ts +2 -4
- package/src/__tests__/context-overflow-reducer.test.ts +2 -4
- package/src/__tests__/context-window-manager.test.ts +147 -60
- package/src/__tests__/contradiction-checker.test.ts +0 -1
- package/src/__tests__/conversation-attention-store.test.ts +0 -1
- package/src/__tests__/conversation-attention-telegram.test.ts +1 -1
- package/src/__tests__/conversation-pairing.test.ts +2 -2
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +25 -1
- package/src/__tests__/conversation-routes-slash-commands.test.ts +381 -0
- package/src/__tests__/conversation-store.test.ts +0 -1
- package/src/__tests__/conversation-unread-route.test.ts +1 -2
- package/src/__tests__/credential-security-invariants.test.ts +7 -8
- package/src/__tests__/cross-provider-web-search.test.ts +353 -0
- package/src/__tests__/daemon-assistant-events.test.ts +6 -7
- package/src/__tests__/db-schedule-syntax-migration.test.ts +15 -3
- package/src/__tests__/delete-managed-skill-tool.test.ts +5 -9
- package/src/__tests__/deterministic-verification-control-plane.test.ts +0 -1
- package/src/__tests__/diagnostics-export.test.ts +189 -0
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +0 -1
- package/src/__tests__/emit-signal-routing-intent.test.ts +3 -3
- package/src/__tests__/entity-extractor.test.ts +0 -1
- package/src/__tests__/entity-search.test.ts +0 -1
- package/src/__tests__/ephemeral-permissions.test.ts +2 -4
- package/src/__tests__/file-read-tool.test.ts +86 -0
- package/src/__tests__/followup-tools.test.ts +0 -1
- package/src/__tests__/frontmatter.test.ts +77 -34
- package/src/__tests__/gateway-only-enforcement.test.ts +0 -1
- package/src/__tests__/gateway-only-guard.test.ts +1 -1
- package/src/__tests__/guardian-action-conversation-turn.test.ts +0 -1
- package/src/__tests__/guardian-action-followup-executor.test.ts +0 -1
- package/src/__tests__/guardian-action-followup-store.test.ts +0 -1
- package/src/__tests__/guardian-action-grant-mint-consume.test.ts +0 -1
- package/src/__tests__/guardian-action-late-reply.test.ts +0 -1
- package/src/__tests__/guardian-action-store.test.ts +0 -1
- package/src/__tests__/guardian-action-sweep.test.ts +0 -1
- package/src/__tests__/guardian-decision-primitive-canonical.test.ts +0 -1
- package/src/__tests__/guardian-dispatch.test.ts +1 -2
- package/src/__tests__/guardian-grant-minting.test.ts +1 -1
- package/src/__tests__/guardian-outbound-http.test.ts +0 -1
- package/src/__tests__/guardian-principal-id-roundtrip.test.ts +0 -1
- package/src/__tests__/guardian-routing-invariants.test.ts +1 -1
- package/src/__tests__/guardian-routing-state.test.ts +0 -1
- package/src/__tests__/guardian-verification-voice-binding.test.ts +0 -1
- package/src/__tests__/guardian-verify-setup-skill-regression.test.ts +3 -5
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +28 -426
- package/src/__tests__/host-bash-proxy.test.ts +335 -0
- package/src/__tests__/host-file-proxy.test.ts +374 -0
- package/src/__tests__/host-shell-tool.test.ts +147 -1
- package/src/__tests__/http-user-message-parity.test.ts +361 -0
- package/src/__tests__/inbound-invite-redemption.test.ts +0 -1
- package/src/__tests__/integration-status.test.ts +3 -8
- package/src/__tests__/intent-routing.test.ts +7 -46
- package/src/__tests__/invite-redemption-service.test.ts +0 -1
- package/src/__tests__/invite-routes-http.test.ts +0 -1
- package/src/__tests__/llm-usage-store.test.ts +0 -1
- package/src/__tests__/managed-avatar-client.test.ts +101 -55
- package/src/__tests__/managed-skill-lifecycle.test.ts +9 -18
- package/src/__tests__/managed-store.test.ts +94 -21
- package/src/__tests__/media-reuse-story.e2e.test.ts +0 -1
- package/src/__tests__/memory-context-benchmark.benchmark.test.ts +2 -4
- package/src/__tests__/memory-lifecycle-e2e.test.ts +0 -1
- package/src/__tests__/memory-recall-quality.test.ts +0 -1
- package/src/__tests__/memory-regressions.experimental.test.ts +0 -1
- package/src/__tests__/memory-regressions.test.ts +0 -1
- package/src/__tests__/memory-retrieval.benchmark.test.ts +0 -1
- package/src/__tests__/memory-upsert-concurrency.test.ts +0 -1
- package/src/__tests__/messaging-send-tool.test.ts +35 -0
- package/src/__tests__/messaging-skill-split.test.ts +138 -0
- package/src/__tests__/migration-cross-version-compatibility.test.ts +0 -1
- package/src/__tests__/migration-export-http.test.ts +2 -3
- package/src/__tests__/migration-import-commit-http.test.ts +1 -2
- package/src/__tests__/migration-import-preflight-http.test.ts +1 -2
- package/src/__tests__/migration-validate-http.test.ts +1 -2
- package/src/__tests__/native-web-search.test.ts +475 -0
- package/src/__tests__/navigate-settings-tab.test.ts +84 -0
- package/src/__tests__/non-member-access-request.test.ts +0 -1
- package/src/__tests__/notification-broadcaster.test.ts +15 -15
- package/src/__tests__/notification-decision-strategy.test.ts +6 -6
- package/src/__tests__/notification-deep-link.test.ts +7 -7
- package/src/__tests__/notification-guardian-path.test.ts +2 -3
- package/src/__tests__/notification-telegram-adapter.test.ts +1 -1
- package/src/__tests__/notification-thread-candidates.test.ts +4 -4
- package/src/__tests__/onboarding-starter-tasks.test.ts +0 -1
- package/src/__tests__/playbook-execution.test.ts +0 -1
- package/src/__tests__/playbook-tools.test.ts +0 -1
- package/src/__tests__/profile-compiler.test.ts +0 -1
- package/src/__tests__/provider-managed-proxy-integration.test.ts +25 -0
- package/src/__tests__/qdrant-collection-migration.test.ts +223 -0
- package/src/__tests__/recording-handler.test.ts +30 -94
- package/src/__tests__/registry.test.ts +28 -35
- package/src/__tests__/relay-server.test.ts +0 -1
- package/src/__tests__/ride-shotgun-handler.test.ts +4 -20
- package/src/__tests__/runtime-attachment-metadata.test.ts +0 -1
- package/src/__tests__/runtime-events-sse-parity.test.ts +3 -4
- package/src/__tests__/runtime-events-sse.test.ts +0 -1
- package/src/__tests__/sandbox-diagnostics.test.ts +0 -1
- package/src/__tests__/scaffold-managed-skill-tool.test.ts +30 -28
- package/src/__tests__/schedule-store.test.ts +441 -1
- package/src/__tests__/schedule-tools.test.ts +468 -7
- package/src/__tests__/scheduler-recurrence.test.ts +196 -23
- package/src/__tests__/scoped-approval-grants.test.ts +0 -1
- package/src/__tests__/scoped-grant-security-matrix.test.ts +0 -1
- package/src/__tests__/secret-prompt-log-hygiene.test.ts +6 -3
- package/src/__tests__/secret-response-routing.test.ts +4 -1
- package/src/__tests__/send-endpoint-busy.test.ts +14 -2
- package/src/__tests__/send-notification-tool.test.ts +0 -7
- package/src/__tests__/sequence-store.test.ts +0 -1
- package/src/__tests__/server-history-render.test.ts +1 -2
- package/src/__tests__/session-abort-tool-results.test.ts +0 -1
- package/src/__tests__/session-agent-loop.test.ts +46 -6
- package/src/__tests__/session-confirmation-signals.test.ts +0 -1
- package/src/__tests__/session-conflict-gate.test.ts +2 -6
- package/src/__tests__/session-error.test.ts +5 -14
- package/src/__tests__/session-init.benchmark.test.ts +3 -5
- package/src/__tests__/session-load-history-repair.test.ts +0 -1
- package/src/__tests__/session-media-retry.test.ts +12 -74
- package/src/__tests__/session-pre-run-repair.test.ts +0 -1
- package/src/__tests__/session-profile-injection.test.ts +2 -6
- package/src/__tests__/session-provider-retry-repair.test.ts +2 -6
- package/src/__tests__/session-queue.test.ts +94 -139
- package/src/__tests__/session-skill-tools.test.ts +115 -115
- package/src/__tests__/session-slash-known.test.ts +0 -1
- package/src/__tests__/session-slash-queue.test.ts +0 -1
- package/src/__tests__/session-slash-unknown.test.ts +0 -1
- package/src/__tests__/session-surfaces-task-progress.test.ts +34 -0
- package/src/__tests__/session-usage.test.ts +0 -1
- package/src/__tests__/session-workspace-cache-state.test.ts +2 -6
- package/src/__tests__/session-workspace-injection.test.ts +2 -6
- package/src/__tests__/session-workspace-tool-tracking.test.ts +2 -6
- package/src/__tests__/skill-feature-flags-integration.test.ts +180 -184
- package/src/__tests__/skill-feature-flags.test.ts +125 -18
- package/src/__tests__/skill-load-feature-flag.test.ts +1 -2
- package/src/__tests__/skill-load-tool.test.ts +194 -2
- package/src/__tests__/skill-projection-feature-flag.test.ts +27 -16
- package/src/__tests__/skill-projection.benchmark.test.ts +15 -14
- package/src/__tests__/skills.test.ts +14 -53
- package/src/__tests__/slack-channel-config.test.ts +0 -1
- package/src/__tests__/slack-inbound-verification.test.ts +0 -1
- package/src/__tests__/slack-skill.test.ts +1 -1
- package/src/__tests__/subagent-tools.test.ts +2 -2
- package/src/__tests__/system-prompt.test.ts +4 -3
- package/src/__tests__/task-compiler.test.ts +0 -1
- package/src/__tests__/task-management-tools.test.ts +0 -1
- package/src/__tests__/task-memory-cleanup.test.ts +0 -1
- package/src/__tests__/task-runner.test.ts +0 -1
- package/src/__tests__/task-scheduler.test.ts +0 -1
- package/src/__tests__/terminal-tools.test.ts +0 -1
- package/src/__tests__/test-support/computer-use-skill-harness.ts +2 -4
- package/src/__tests__/thread-seed-composer.test.ts +5 -5
- package/src/__tests__/tool-approval-handler.test.ts +0 -1
- package/src/__tests__/tool-execution-abort-cleanup.test.ts +0 -1
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +0 -1
- package/src/__tests__/tool-executor.test.ts +8 -86
- package/src/__tests__/tool-grant-request-escalation.test.ts +0 -1
- package/src/__tests__/tool-notification-listener.test.ts +1 -1
- package/src/__tests__/tool-preview-lifecycle.test.ts +416 -0
- package/src/__tests__/trust-store.test.ts +80 -4
- package/src/__tests__/trusted-contact-approval-notifier.test.ts +0 -1
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +0 -1
- package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +0 -1
- package/src/__tests__/trusted-contact-multichannel.test.ts +0 -1
- package/src/__tests__/trusted-contact-verification.test.ts +0 -1
- package/src/__tests__/twilio-provider.test.ts +0 -1
- package/src/__tests__/twilio-routes.test.ts +0 -1
- package/src/__tests__/{request-file-tool.test.ts → ui-file-upload-surface.test.ts} +11 -72
- package/src/__tests__/update-bulletin.test.ts +0 -1
- package/src/__tests__/usage-cache-backfill-migration.test.ts +0 -1
- package/src/__tests__/usage-routes.test.ts +0 -1
- package/src/__tests__/verification-control-plane-policy.test.ts +4 -4
- package/src/__tests__/voice-invite-redemption.test.ts +0 -1
- package/src/__tests__/voice-scoped-grant-consumer.test.ts +0 -1
- package/src/__tests__/voice-session-bridge.test.ts +9 -1
- package/src/__tests__/web-fetch.test.ts +57 -0
- package/src/__tests__/workspace-git-service.test.ts +5 -14
- package/src/__tests__/workspace-policy.test.ts +0 -1
- package/src/agent/loop.ts +22 -34
- package/src/bundler/bundle-signer.ts +4 -4
- package/src/calls/call-controller.ts +1 -1
- package/src/calls/relay-server.ts +1 -1
- package/src/calls/twilio-rest.ts +1 -1
- package/src/calls/voice-session-bridge.ts +3 -1
- package/src/cli/__tests__/notifications.test.ts +3 -4
- package/src/cli/commands/map.ts +2 -6
- package/src/cli/commands/mcp.ts +73 -15
- package/src/cli/commands/notifications.ts +4 -4
- package/src/cli/commands/sessions.ts +9 -1
- package/src/cli/commands/skills.ts +6 -10
- package/src/cli/http-client.ts +2 -3
- package/src/cli/main-screen.tsx +10 -10
- package/src/cli/program.ts +0 -4
- package/src/cli/reference.ts +0 -2
- package/src/cli.ts +15 -9
- package/src/config/__tests__/bundled-tool-registry-guard.test.ts +120 -0
- package/src/config/bundled-skills/_shared/CLI_RETRIEVAL_PATTERN.md +11 -0
- package/src/config/bundled-skills/app-builder/SKILL.md +6 -1
- package/src/config/bundled-skills/browser/SKILL.md +6 -1
- package/src/config/bundled-skills/chatgpt-import/SKILL.md +5 -1
- package/src/config/bundled-skills/claude-code/SKILL.md +5 -1
- package/src/config/bundled-skills/computer-use/SKILL.md +6 -1
- package/src/config/bundled-skills/computer-use/TOOLS.json +6 -69
- package/src/config/bundled-skills/computer-use/tools/computer-use-click.ts +10 -1
- package/src/config/bundled-skills/contacts/SKILL.md +10 -1
- package/src/config/bundled-skills/contacts/TOOLS.json +35 -0
- package/src/config/bundled-skills/{messaging → contacts}/tools/google-contacts.ts +9 -2
- package/src/config/bundled-skills/document/SKILL.md +4 -1
- package/src/config/bundled-skills/doordash/SKILL.md +8 -1
- package/src/config/bundled-skills/doordash/lib/shared/platform.ts +4 -1
- package/src/config/bundled-skills/followups/SKILL.md +4 -1
- package/src/config/bundled-skills/gmail/SKILL.md +180 -0
- package/src/config/bundled-skills/gmail/TOOLS.json +506 -0
- package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +149 -0
- package/src/config/bundled-skills/gmail/tools/gmail-attachments.ts +110 -0
- package/src/config/bundled-skills/{messaging → gmail}/tools/gmail-draft.ts +1 -1
- package/src/config/bundled-skills/{messaging → gmail}/tools/gmail-filters.ts +1 -1
- package/src/config/bundled-skills/{messaging → gmail}/tools/gmail-follow-up.ts +1 -1
- package/src/config/bundled-skills/{messaging → gmail}/tools/gmail-forward.ts +1 -1
- package/src/config/bundled-skills/gmail/tools/gmail-label.ts +50 -0
- package/src/config/bundled-skills/{messaging → gmail}/tools/gmail-outreach-scan.ts +8 -90
- package/src/config/bundled-skills/{messaging → gmail}/tools/gmail-send-draft.ts +1 -1
- package/src/config/bundled-skills/{messaging → gmail}/tools/gmail-sender-digest.ts +2 -2
- package/src/config/bundled-skills/{messaging → gmail}/tools/gmail-trash.ts +1 -1
- package/src/config/bundled-skills/{messaging → gmail}/tools/gmail-unsubscribe.ts +1 -1
- package/src/config/bundled-skills/{messaging → gmail}/tools/gmail-vacation.ts +1 -1
- package/src/config/bundled-skills/gmail/tools/shared.ts +47 -0
- package/src/config/bundled-skills/google-calendar/SKILL.md +5 -1
- package/src/config/bundled-skills/image-studio/SKILL.md +5 -1
- package/src/config/bundled-skills/knowledge-graph/SKILL.md +4 -1
- package/src/config/bundled-skills/media-processing/SKILL.md +7 -13
- package/src/config/bundled-skills/media-processing/TOOLS.json +0 -22
- package/src/config/bundled-skills/media-processing/tools/generate-clip.ts +12 -1
- package/src/config/bundled-skills/messaging/SKILL.md +23 -139
- package/src/config/bundled-skills/messaging/TOOLS.json +33 -1215
- package/src/config/bundled-skills/messaging/tools/gmail-mime-helpers.ts +42 -0
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +165 -2
- package/src/config/bundled-skills/messaging/tools/messaging-sender-digest.ts +1 -13
- package/src/config/bundled-skills/messaging/tools/shared.ts +81 -34
- package/src/config/bundled-skills/notifications/SKILL.md +5 -1
- package/src/config/bundled-skills/orchestration/SKILL.md +30 -0
- package/src/config/bundled-skills/orchestration/TOOLS.json +35 -0
- package/src/config/bundled-skills/{reminder/tools/reminder-create.ts → orchestration/tools/swarm-delegate.ts} +3 -3
- package/src/config/bundled-skills/phone-calls/SKILL.md +9 -1
- package/src/config/bundled-skills/playbooks/SKILL.md +4 -1
- package/src/config/bundled-skills/schedule/SKILL.md +70 -9
- package/src/config/bundled-skills/schedule/TOOLS.json +38 -6
- package/src/config/bundled-skills/screen-watch/SKILL.md +28 -0
- package/src/config/bundled-skills/screen-watch/TOOLS.json +35 -0
- package/src/config/bundled-skills/{reminder/tools/reminder-cancel.ts → screen-watch/tools/start-screen-watch.ts} +3 -3
- package/src/config/bundled-skills/sequences/SKILL.md +47 -0
- package/src/config/bundled-skills/sequences/TOOLS.json +340 -0
- package/src/config/bundled-skills/sequences/tools/sequence-update.ts +128 -0
- package/src/config/bundled-skills/sequences/tools/shared.ts +9 -0
- package/src/config/bundled-skills/settings/SKILL.md +12 -0
- package/src/config/bundled-skills/settings/TOOLS.json +112 -0
- package/src/config/bundled-skills/settings/tools/navigate-settings-tab.ts +43 -0
- package/src/config/bundled-skills/settings/tools/open-system-settings.ts +52 -0
- package/src/config/bundled-skills/{computer-use/tools/computer-use-right-click.ts → settings/tools/set-avatar.ts} +2 -6
- package/src/{tools/system/voice-config.ts → config/bundled-skills/settings/tools/voice-config-update.ts} +59 -96
- package/src/config/bundled-skills/skill-management/SKILL.md +18 -0
- package/src/config/bundled-skills/skill-management/TOOLS.json +90 -0
- package/src/config/bundled-skills/{computer-use/tools/computer-use-double-click.ts → skill-management/tools/delete-managed.ts} +2 -6
- package/src/config/bundled-skills/skill-management/tools/scaffold-managed.ts +12 -0
- package/src/config/bundled-skills/slack/SKILL.md +5 -1
- package/src/config/bundled-skills/subagent/SKILL.md +4 -1
- package/src/config/bundled-skills/tasks/SKILL.md +5 -2
- package/src/config/bundled-skills/transcribe/SKILL.md +4 -1
- package/src/config/bundled-skills/watcher/SKILL.md +4 -1
- package/src/config/bundled-tool-registry.ts +118 -107
- package/src/config/env.ts +5 -2
- package/src/config/feature-flag-registry.json +25 -9
- package/src/config/loader.ts +10 -2
- package/src/config/schema.ts +19 -16
- package/src/config/schemas/inference.ts +12 -22
- package/src/config/schemas/memory-storage.ts +19 -1
- package/src/config/schemas/platform.ts +0 -16
- package/src/config/skill-state.ts +11 -8
- package/src/config/skills.ts +83 -32
- package/src/context/token-estimator.ts +11 -0
- package/src/context/window-manager.ts +180 -151
- package/src/daemon/computer-use-session.ts +11 -43
- package/src/daemon/daemon-control.ts +4 -1
- package/src/daemon/handlers/config-channels.ts +5 -9
- package/src/daemon/handlers/config-ingress.ts +0 -4
- package/src/daemon/handlers/config-model.ts +7 -13
- package/src/daemon/handlers/config-telegram.ts +4 -8
- package/src/daemon/handlers/config-voice.ts +2 -5
- package/src/daemon/handlers/dictation.ts +2 -12
- package/src/daemon/handlers/identity.ts +0 -105
- package/src/daemon/handlers/recording.ts +3 -23
- package/src/daemon/handlers/session-history.ts +1 -1
- package/src/daemon/handlers/sessions.ts +53 -72
- package/src/daemon/handlers/shared.ts +7 -28
- package/src/daemon/handlers/skills.ts +31 -27
- package/src/daemon/host-bash-proxy.ts +148 -0
- package/src/daemon/host-file-proxy.ts +135 -0
- package/src/daemon/lifecycle.ts +49 -24
- package/src/daemon/mcp-reload-service.ts +123 -0
- package/src/daemon/message-protocol.ts +6 -0
- package/src/daemon/message-types/browser.ts +1 -1
- package/src/daemon/message-types/computer-use.ts +1 -4
- package/src/daemon/message-types/guardian-actions.ts +1 -1
- package/src/daemon/message-types/host-bash.ts +18 -0
- package/src/daemon/message-types/host-file.ts +44 -0
- package/src/daemon/message-types/integrations.ts +1 -67
- package/src/daemon/message-types/messages.ts +15 -0
- package/src/daemon/message-types/schedules.ts +11 -27
- package/src/daemon/message-types/sessions.ts +2 -1
- package/src/daemon/message-types/settings.ts +1 -1
- package/src/daemon/message-types/shared.ts +1 -1
- package/src/daemon/ride-shotgun-handler.ts +2 -42
- package/src/daemon/server.ts +43 -10
- package/src/daemon/session-agent-loop-handlers.ts +48 -7
- package/src/daemon/session-agent-loop.ts +97 -66
- package/src/daemon/session-attachments.ts +1 -1
- package/src/daemon/session-error.ts +17 -16
- package/src/daemon/session-lifecycle.ts +20 -1
- package/src/daemon/session-media-retry.ts +1 -15
- package/src/daemon/session-messaging.ts +14 -6
- package/src/daemon/session-process.ts +36 -7
- package/src/daemon/session-queue-manager.ts +62 -103
- package/src/daemon/session-runtime-assembly.ts +27 -0
- package/src/daemon/session-skill-tools.ts +12 -11
- package/src/daemon/session-slash.ts +7 -0
- package/src/daemon/session-surfaces.ts +19 -97
- package/src/daemon/session-tool-setup.ts +146 -6
- package/src/daemon/session.ts +77 -13
- package/src/errors.ts +0 -2
- package/src/export/formatter.ts +6 -0
- package/src/mcp/mcp-oauth-provider.ts +1 -3
- package/src/media/avatar-router.ts +20 -28
- package/src/media/avatar-types.ts +7 -14
- package/src/media/managed-avatar-client.ts +70 -34
- package/src/memory/conversation-title-service.ts +1 -2
- package/src/memory/db-init.ts +16 -0
- package/src/memory/embedding-backend.ts +129 -27
- package/src/memory/embedding-gemini.test.ts +256 -0
- package/src/memory/embedding-gemini.ts +47 -13
- package/src/memory/embedding-local.ts +14 -2
- package/src/memory/embedding-ollama.ts +15 -2
- package/src/memory/embedding-openai.ts +15 -2
- package/src/memory/embedding-types.test.ts +116 -0
- package/src/memory/embedding-types.ts +61 -0
- package/src/memory/fingerprint.ts +1 -1
- package/src/memory/indexer.ts +25 -1
- package/src/memory/job-handlers/embedding.test.ts +258 -0
- package/src/memory/job-handlers/embedding.ts +81 -1
- package/src/memory/job-handlers/index-maintenance.ts +35 -1
- package/src/memory/job-handlers/media-processing.ts +11 -1
- package/src/memory/job-utils.ts +21 -6
- package/src/memory/jobs-store.ts +5 -1
- package/src/memory/jobs-worker.ts +8 -0
- package/src/memory/message-content.ts +66 -0
- package/src/memory/migrations/100-core-tables.ts +1 -31
- package/src/memory/migrations/104-core-indexes.ts +0 -11
- package/src/memory/migrations/145-drop-accounts-table.ts +19 -0
- package/src/memory/migrations/146-schedule-oneshot-routing.ts +94 -0
- package/src/memory/migrations/147-migrate-reminders-to-schedules.ts +129 -0
- package/src/memory/migrations/148-drop-reminders-table.ts +18 -0
- package/src/memory/migrations/index.ts +4 -0
- package/src/memory/migrations/registry.ts +19 -0
- package/src/memory/qdrant-client.ts +158 -43
- package/src/memory/retriever.test.ts +0 -1
- package/src/memory/retriever.ts +12 -2
- package/src/memory/schema/infrastructure.ts +5 -29
- package/src/memory/search/formatting.ts +34 -9
- package/src/memory/search/semantic.ts +57 -2
- package/src/memory/search/types.ts +2 -1
- package/src/notifications/AGENTS.md +2 -2
- package/src/notifications/README.md +59 -58
- package/src/notifications/adapters/macos.ts +1 -1
- package/src/notifications/broadcaster.ts +5 -5
- package/src/notifications/copy-composer.ts +1 -1
- package/src/notifications/decision-engine.ts +2 -2
- package/src/notifications/destination-resolver.ts +2 -2
- package/src/notifications/emit-signal.ts +8 -8
- package/src/notifications/signal.ts +1 -1
- package/src/notifications/thread-seed-composer.ts +1 -1
- package/src/oauth/connect-orchestrator.ts +1 -1
- package/src/oauth/token-persistence.ts +1 -1
- package/src/permissions/checker.ts +12 -1
- package/src/permissions/defaults.ts +10 -14
- package/src/permissions/trust-store.ts +37 -0
- package/src/permissions/workspace-policy.ts +0 -1
- package/src/prompts/__tests__/build-cli-reference-section.test.ts +11 -0
- package/src/prompts/computer-use-prompt.ts +1 -1
- package/src/prompts/system-prompt.ts +29 -30
- package/src/prompts/templates/SOUL.md +1 -2
- package/src/prompts/templates/UPDATES.md +16 -7
- package/src/providers/anthropic/client.ts +87 -33
- package/src/providers/gemini/client.ts +6 -0
- package/src/providers/managed-proxy/constants.ts +5 -0
- package/src/providers/openai/client.ts +15 -0
- package/src/providers/registry.ts +2 -2
- package/src/providers/types.ts +24 -2
- package/src/runtime/AGENTS.md +18 -0
- package/src/runtime/assistant-event-hub.ts +2 -3
- package/src/runtime/assistant-event.ts +4 -4
- package/src/runtime/auth/__tests__/context.test.ts +5 -5
- package/src/runtime/auth/__tests__/credential-service.test.ts +0 -1
- package/src/runtime/auth/__tests__/guard-tests.test.ts +2 -2
- package/src/runtime/auth/__tests__/{ipc-auth-context.test.ts → local-auth-context.test.ts} +21 -21
- package/src/runtime/auth/__tests__/route-policy.test.ts +2 -2
- package/src/runtime/auth/__tests__/scopes.test.ts +7 -7
- package/src/runtime/auth/__tests__/subject.test.ts +8 -8
- package/src/runtime/auth/__tests__/token-service.test.ts +0 -1
- package/src/runtime/auth/route-policy.ts +8 -4
- package/src/runtime/auth/scopes.ts +1 -1
- package/src/runtime/auth/subject.ts +4 -4
- package/src/runtime/auth/token-service.ts +0 -23
- package/src/runtime/auth/types.ts +3 -3
- package/src/runtime/guardian-action-followup-executor.ts +1 -1
- package/src/runtime/guardian-action-grant-minter.ts +1 -1
- package/src/runtime/guardian-action-service.ts +3 -3
- package/src/runtime/http-server.ts +15 -2
- package/src/runtime/invite-service.ts +3 -3
- package/src/runtime/local-actor-identity.ts +17 -22
- package/src/runtime/pending-interactions.ts +21 -9
- package/src/runtime/routes/app-management-routes.ts +2 -3
- package/src/runtime/routes/approval-routes.ts +1 -3
- package/src/runtime/routes/btw-routes.ts +155 -0
- package/src/runtime/routes/computer-use-routes.ts +77 -31
- package/src/runtime/routes/conversation-routes.ts +230 -46
- package/src/runtime/routes/diagnostics-routes.ts +63 -29
- package/src/runtime/routes/documents-routes.ts +2 -2
- package/src/runtime/routes/global-search-routes.ts +1 -1
- package/src/runtime/routes/host-bash-routes.ts +83 -0
- package/src/runtime/routes/host-file-routes.ts +79 -0
- package/src/runtime/routes/integrations/slack/share.ts +1 -1
- package/src/runtime/routes/log-export-routes.ts +120 -0
- package/src/runtime/routes/mcp-routes.ts +20 -0
- package/src/runtime/routes/migration-routes.ts +3 -3
- package/src/runtime/routes/pairing-routes.ts +1 -1
- package/src/runtime/routes/recording-routes.ts +6 -4
- package/src/runtime/routes/schedule-routes.ts +31 -5
- package/src/runtime/routes/session-management-routes.ts +2 -6
- package/src/runtime/routes/session-query-routes.ts +18 -15
- package/src/runtime/routes/settings-routes.ts +7 -261
- package/src/runtime/routes/skills-routes.ts +7 -6
- package/src/runtime/routes/subagents-routes.ts +4 -10
- package/src/runtime/routes/surface-action-routes.ts +3 -14
- package/src/runtime/routes/surface-content-routes.ts +22 -5
- package/src/runtime/routes/work-items-routes.ts +21 -25
- package/src/runtime/routes/workspace-routes.test.ts +3 -3
- package/src/runtime/routes/workspace-utils.ts +1 -1
- package/src/runtime/telegram-streaming-delivery.ts +3 -0
- package/src/runtime/verification-outbound-actions.ts +2 -2
- package/src/schedule/integration-status.ts +0 -6
- package/src/schedule/schedule-store.ts +234 -43
- package/src/schedule/scheduler.ts +73 -74
- package/src/security/oauth2.ts +1 -1
- package/src/sequence/store.ts +12 -2
- package/src/skills/frontmatter.ts +19 -77
- package/src/skills/managed-store.ts +11 -2
- package/src/subagent/manager.ts +5 -3
- package/src/tasks/ephemeral-permissions.ts +3 -5
- package/src/tools/AGENTS.md +0 -1
- package/src/tools/browser/browser-manager.ts +17 -11
- package/src/tools/browser/jit-auth.ts +4 -1
- package/src/tools/claude-code/claude-code.ts +1 -1
- package/src/tools/computer-use/definitions.ts +48 -60
- package/src/tools/document/document-tool.ts +6 -6
- package/src/tools/filesystem/edit.ts +2 -1
- package/src/tools/filesystem/read.ts +20 -2
- package/src/tools/filesystem/write.ts +2 -1
- package/src/tools/host-filesystem/edit.ts +17 -1
- package/src/tools/host-filesystem/read.ts +16 -1
- package/src/tools/host-filesystem/write.ts +15 -1
- package/src/tools/host-terminal/host-shell.ts +24 -0
- package/src/tools/memory/definitions.ts +45 -81
- package/src/tools/memory/handlers.test.ts +0 -1
- package/src/tools/memory/handlers.ts +1 -1
- package/src/tools/memory/register.ts +26 -60
- package/src/tools/network/script-proxy/session-manager.ts +6 -8
- package/src/tools/network/web-fetch.ts +7 -1
- package/src/tools/network/web-search.ts +2 -1
- package/src/tools/registry.ts +23 -0
- package/src/tools/schedule/create.ts +113 -5
- package/src/tools/schedule/list.ts +57 -15
- package/src/tools/schedule/update.ts +73 -3
- package/src/tools/shared/filesystem/image-read.ts +192 -0
- package/src/tools/side-effects.ts +1 -7
- package/src/tools/skills/delete-managed.ts +27 -64
- package/src/tools/skills/execute.ts +54 -0
- package/src/tools/skills/load.ts +127 -5
- package/src/tools/skills/scaffold-managed.ts +93 -172
- package/src/tools/subagent/message.ts +0 -7
- package/src/tools/subagent/spawn.ts +1 -1
- package/src/tools/swarm/delegate.ts +0 -3
- package/src/tools/system/avatar-generator.ts +13 -19
- package/src/tools/system/request-permission.ts +2 -1
- package/src/tools/terminal/safe-env.ts +1 -0
- package/src/tools/tool-manifest.ts +41 -47
- package/src/tools/types.ts +6 -2
- package/src/tools/ui-surface/definitions.ts +0 -55
- package/src/util/errors.ts +0 -10
- package/src/workspace/git-service.ts +0 -2
- package/src/__tests__/account-registry.test.ts +0 -258
- package/src/__tests__/email-classifier.test.ts +0 -25
- package/src/__tests__/gmail-integration.test.ts +0 -97
- package/src/__tests__/handle-user-message-secret-resume.test.ts +0 -172
- package/src/__tests__/managed-twitter-guardrails.test.ts +0 -357
- package/src/__tests__/recording-intent-fallback.test.ts +0 -199
- package/src/__tests__/recording-intent.test.ts +0 -985
- package/src/__tests__/recording-state-machine.test.ts +0 -1574
- package/src/__tests__/reminder-store.test.ts +0 -350
- package/src/__tests__/reminder.test.ts +0 -337
- package/src/__tests__/scan-result-store.test.ts +0 -121
- package/src/__tests__/twitter-platform-proxy-client.test.ts +0 -475
- package/src/__tests__/view-image-tool.test.ts +0 -241
- package/src/cli/commands/amazon/cart.ts +0 -513
- package/src/cli/commands/amazon/checkout.ts +0 -394
- package/src/cli/commands/amazon/client.ts +0 -513
- package/src/cli/commands/amazon/index.ts +0 -885
- package/src/cli/commands/amazon/product-details.ts +0 -145
- package/src/cli/commands/amazon/request-extractor.ts +0 -187
- package/src/cli/commands/amazon/search.ts +0 -76
- package/src/cli/commands/amazon/session.ts +0 -108
- package/src/cli/commands/twitter/__tests__/cli-read-routing.test.ts +0 -345
- package/src/cli/commands/twitter/__tests__/cli-routing.test.ts +0 -252
- package/src/cli/commands/twitter/__tests__/oauth-client.test.ts +0 -151
- package/src/cli/commands/twitter/index.ts +0 -420
- package/src/cli/commands/twitter/oauth-client.ts +0 -60
- package/src/cli/commands/twitter/router.ts +0 -351
- package/src/cli/commands/twitter/types.ts +0 -30
- package/src/config/bundled-skills/agentmail/SKILL.md +0 -132
- package/src/config/bundled-skills/agentmail/icon.svg +0 -21
- package/src/config/bundled-skills/amazon/SKILL.md +0 -136
- package/src/config/bundled-skills/amazon/icon.svg +0 -13
- package/src/config/bundled-skills/api-mapping/SKILL.md +0 -78
- package/src/config/bundled-skills/api-mapping/icon.svg +0 -18
- package/src/config/bundled-skills/cli-discover/SKILL.md +0 -68
- package/src/config/bundled-skills/deploy-fullstack-vercel/SKILL.md +0 -179
- package/src/config/bundled-skills/document-writer/SKILL.md +0 -195
- package/src/config/bundled-skills/elevenlabs-voice/SKILL.md +0 -140
- package/src/config/bundled-skills/email-setup/SKILL.md +0 -68
- package/src/config/bundled-skills/frontend-design/SKILL.md +0 -44
- package/src/config/bundled-skills/frontend-design/icon.svg +0 -16
- package/src/config/bundled-skills/google-oauth-setup/SKILL.md +0 -452
- package/src/config/bundled-skills/guardian-verify-setup/SKILL.md +0 -203
- package/src/config/bundled-skills/influencer/SKILL.md +0 -144
- package/src/config/bundled-skills/influencer/scripts/client.ts +0 -1269
- package/src/config/bundled-skills/influencer/scripts/influencer.ts +0 -267
- package/src/config/bundled-skills/macos-automation/SKILL.md +0 -65
- package/src/config/bundled-skills/macos-automation/icon.svg +0 -12
- package/src/config/bundled-skills/mcp-setup/SKILL.md +0 -75
- package/src/config/bundled-skills/media-processing/tools/media-diagnostics.ts +0 -184
- package/src/config/bundled-skills/messaging/tools/gmail-archive-by-query.ts +0 -80
- package/src/config/bundled-skills/messaging/tools/gmail-archive.ts +0 -29
- package/src/config/bundled-skills/messaging/tools/gmail-batch-archive.ts +0 -56
- package/src/config/bundled-skills/messaging/tools/gmail-batch-label.ts +0 -34
- package/src/config/bundled-skills/messaging/tools/gmail-download-attachment.ts +0 -47
- package/src/config/bundled-skills/messaging/tools/gmail-label.ts +0 -31
- package/src/config/bundled-skills/messaging/tools/gmail-list-attachments.ts +0 -67
- package/src/config/bundled-skills/messaging/tools/gmail-send-with-attachments.ts +0 -97
- package/src/config/bundled-skills/messaging/tools/gmail-summarize-thread.ts +0 -87
- package/src/config/bundled-skills/messaging/tools/gmail-triage.ts +0 -135
- package/src/config/bundled-skills/messaging/tools/messaging-analyze-activity.ts +0 -24
- package/src/config/bundled-skills/messaging/tools/messaging-reply.ts +0 -201
- package/src/config/bundled-skills/messaging/tools/send-notification.ts +0 -1
- package/src/config/bundled-skills/messaging/tools/sequence-cancel.ts +0 -27
- package/src/config/bundled-skills/messaging/tools/sequence-pause.ts +0 -48
- package/src/config/bundled-skills/messaging/tools/sequence-resume.ts +0 -27
- package/src/config/bundled-skills/messaging/tools/sequence-update.ts +0 -56
- package/src/config/bundled-skills/notion/SKILL.md +0 -240
- package/src/config/bundled-skills/notion-oauth-setup/SKILL.md +0 -126
- package/src/config/bundled-skills/oauth-setup/SKILL.md +0 -143
- package/src/config/bundled-skills/public-ingress/SKILL.md +0 -258
- package/src/config/bundled-skills/reminder/SKILL.md +0 -79
- package/src/config/bundled-skills/reminder/TOOLS.json +0 -89
- package/src/config/bundled-skills/reminder/tools/reminder-list.ts +0 -12
- package/src/config/bundled-skills/restaurant-reservation/SKILL.md +0 -141
- package/src/config/bundled-skills/screen-recording/SKILL.md +0 -148
- package/src/config/bundled-skills/self-upgrade/SKILL.md +0 -69
- package/src/config/bundled-skills/skills-catalog/SKILL.md +0 -78
- package/src/config/bundled-skills/slack-app-setup/SKILL.md +0 -178
- package/src/config/bundled-skills/slack-digest-setup/SKILL.md +0 -163
- package/src/config/bundled-skills/slack-oauth-setup/SKILL.md +0 -157
- package/src/config/bundled-skills/start-the-day/SKILL.md +0 -70
- package/src/config/bundled-skills/start-the-day/icon.svg +0 -13
- package/src/config/bundled-skills/telegram-setup/SKILL.md +0 -105
- package/src/config/bundled-skills/time-based-actions/SKILL.md +0 -142
- package/src/config/bundled-skills/twilio-setup/SKILL.md +0 -232
- package/src/config/bundled-skills/twitter/SKILL.md +0 -206
- package/src/config/bundled-skills/twitter/icon.svg +0 -14
- package/src/config/bundled-skills/typescript-eval/SKILL.md +0 -60
- package/src/config/bundled-skills/vercel-token-setup/SKILL.md +0 -214
- package/src/config/bundled-skills/voice-setup/SKILL.md +0 -131
- package/src/config/bundled-skills/voice-setup/icon.svg +0 -20
- package/src/daemon/handlers/pairing.ts +0 -119
- package/src/daemon/handlers/session-user-message.ts +0 -961
- package/src/daemon/recording-executor.ts +0 -180
- package/src/daemon/recording-intent-fallback.ts +0 -162
- package/src/daemon/recording-intent.ts +0 -493
- package/src/memory/account-store.ts +0 -117
- package/src/messaging/activity-analyzer.ts +0 -76
- package/src/messaging/email-classifier.ts +0 -208
- package/src/messaging/index.ts +0 -2
- package/src/messaging/outreach-classifier.ts +0 -185
- package/src/messaging/thread-summarizer.ts +0 -346
- package/src/messaging/types.ts +0 -17
- package/src/tools/browser/x-auto-navigate.ts +0 -254
- package/src/tools/credentials/account-registry.ts +0 -144
- package/src/tools/filesystem/view-image.ts +0 -244
- package/src/tools/reminder/reminder-store.ts +0 -194
- package/src/tools/reminder/reminder.ts +0 -158
- package/src/tools/system/navigate-settings.ts +0 -74
- package/src/tools/system/open-system-settings.ts +0 -85
- package/src/tools/system/version.ts +0 -54
- package/src/twitter/platform-proxy-client.ts +0 -408
- /package/src/config/bundled-skills/{messaging → gmail}/tools/scan-result-store.ts +0 -0
- /package/src/config/bundled-skills/{messaging → sequences}/tools/sequence-analytics.ts +0 -0
- /package/src/config/bundled-skills/{messaging → sequences}/tools/sequence-create.ts +0 -0
- /package/src/config/bundled-skills/{messaging → sequences}/tools/sequence-delete.ts +0 -0
- /package/src/config/bundled-skills/{messaging → sequences}/tools/sequence-enroll.ts +0 -0
- /package/src/config/bundled-skills/{messaging → sequences}/tools/sequence-enrollment-list.ts +0 -0
- /package/src/config/bundled-skills/{messaging → sequences}/tools/sequence-get.ts +0 -0
- /package/src/config/bundled-skills/{messaging → sequences}/tools/sequence-import.ts +0 -0
- /package/src/config/bundled-skills/{messaging → sequences}/tools/sequence-list.ts +0 -0
|
@@ -5,7 +5,8 @@ import type { AssistantConfig } from "../config/schema.js";
|
|
|
5
5
|
import { resolveSkillStates, skillFlagKey } from "../config/skill-state.js";
|
|
6
6
|
import type { SkillSummary } from "../config/skills.js";
|
|
7
7
|
|
|
8
|
-
const
|
|
8
|
+
const DECLARED_FLAG_ID = "hatch-new-assistant";
|
|
9
|
+
const DECLARED_FLAG_KEY = `feature_flags.${DECLARED_FLAG_ID}.enabled`;
|
|
9
10
|
const DECLARED_SKILL_ID = "hatch-new-assistant";
|
|
10
11
|
// ---------------------------------------------------------------------------
|
|
11
12
|
// Helpers
|
|
@@ -37,6 +38,7 @@ function makeConfig(overrides: Partial<AssistantConfig> = {}): AssistantConfig {
|
|
|
37
38
|
function makeSkill(
|
|
38
39
|
id: string,
|
|
39
40
|
source: "bundled" | "managed" = "bundled",
|
|
41
|
+
featureFlag?: string,
|
|
40
42
|
): SkillSummary {
|
|
41
43
|
return {
|
|
42
44
|
id,
|
|
@@ -49,9 +51,32 @@ function makeSkill(
|
|
|
49
51
|
userInvocable: true,
|
|
50
52
|
disableModelInvocation: false,
|
|
51
53
|
source,
|
|
54
|
+
featureFlag,
|
|
52
55
|
};
|
|
53
56
|
}
|
|
54
57
|
|
|
58
|
+
// ---------------------------------------------------------------------------
|
|
59
|
+
// skillFlagKey — unit tests
|
|
60
|
+
// ---------------------------------------------------------------------------
|
|
61
|
+
|
|
62
|
+
describe("skillFlagKey", () => {
|
|
63
|
+
test("returns canonical key when featureFlag is present", () => {
|
|
64
|
+
expect(skillFlagKey({ featureFlag: "my-flag" })).toBe(
|
|
65
|
+
"feature_flags.my-flag.enabled",
|
|
66
|
+
);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
test("returns undefined when featureFlag is undefined", () => {
|
|
70
|
+
expect(skillFlagKey({ featureFlag: undefined })).toBeUndefined();
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
test("returns undefined when featureFlag field is absent", () => {
|
|
74
|
+
expect(
|
|
75
|
+
skillFlagKey({} as Pick<SkillSummary, "featureFlag">),
|
|
76
|
+
).toBeUndefined();
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
|
|
55
80
|
// ---------------------------------------------------------------------------
|
|
56
81
|
// isAssistantFeatureFlagEnabled with skillFlagKey (canonical path)
|
|
57
82
|
// ---------------------------------------------------------------------------
|
|
@@ -60,7 +85,10 @@ describe("isAssistantFeatureFlagEnabled with skillFlagKey", () => {
|
|
|
60
85
|
test("returns false when no flag overrides (registry default is false)", () => {
|
|
61
86
|
const config = makeConfig();
|
|
62
87
|
expect(
|
|
63
|
-
isAssistantFeatureFlagEnabled(
|
|
88
|
+
isAssistantFeatureFlagEnabled(
|
|
89
|
+
skillFlagKey({ featureFlag: DECLARED_FLAG_ID })!,
|
|
90
|
+
config,
|
|
91
|
+
),
|
|
64
92
|
).toBe(false);
|
|
65
93
|
});
|
|
66
94
|
|
|
@@ -69,7 +97,10 @@ describe("isAssistantFeatureFlagEnabled with skillFlagKey", () => {
|
|
|
69
97
|
assistantFeatureFlagValues: { [DECLARED_FLAG_KEY]: true },
|
|
70
98
|
});
|
|
71
99
|
expect(
|
|
72
|
-
isAssistantFeatureFlagEnabled(
|
|
100
|
+
isAssistantFeatureFlagEnabled(
|
|
101
|
+
skillFlagKey({ featureFlag: DECLARED_FLAG_ID })!,
|
|
102
|
+
config,
|
|
103
|
+
),
|
|
73
104
|
).toBe(true);
|
|
74
105
|
});
|
|
75
106
|
|
|
@@ -78,7 +109,10 @@ describe("isAssistantFeatureFlagEnabled with skillFlagKey", () => {
|
|
|
78
109
|
assistantFeatureFlagValues: { [DECLARED_FLAG_KEY]: false },
|
|
79
110
|
});
|
|
80
111
|
expect(
|
|
81
|
-
isAssistantFeatureFlagEnabled(
|
|
112
|
+
isAssistantFeatureFlagEnabled(
|
|
113
|
+
skillFlagKey({ featureFlag: DECLARED_FLAG_ID })!,
|
|
114
|
+
config,
|
|
115
|
+
),
|
|
82
116
|
).toBe(false);
|
|
83
117
|
});
|
|
84
118
|
});
|
|
@@ -137,11 +171,14 @@ describe("isAssistantFeatureFlagEnabled", () => {
|
|
|
137
171
|
|
|
138
172
|
describe("resolveSkillStates with feature flags", () => {
|
|
139
173
|
test("flag OFF skill does not appear in resolved list", () => {
|
|
140
|
-
const catalog = [
|
|
174
|
+
const catalog = [
|
|
175
|
+
makeSkill(DECLARED_SKILL_ID, "bundled", DECLARED_FLAG_ID),
|
|
176
|
+
makeSkill("browser", "bundled", "browser"),
|
|
177
|
+
];
|
|
141
178
|
const config = makeConfig({
|
|
142
179
|
assistantFeatureFlagValues: {
|
|
143
180
|
[DECLARED_FLAG_KEY]: false,
|
|
144
|
-
"feature_flags.
|
|
181
|
+
"feature_flags.browser.enabled": true,
|
|
145
182
|
},
|
|
146
183
|
});
|
|
147
184
|
|
|
@@ -149,15 +186,18 @@ describe("resolveSkillStates with feature flags", () => {
|
|
|
149
186
|
const ids = resolved.map((r) => r.summary.id);
|
|
150
187
|
|
|
151
188
|
expect(ids).not.toContain(DECLARED_SKILL_ID);
|
|
152
|
-
expect(ids).toContain("
|
|
189
|
+
expect(ids).toContain("browser");
|
|
153
190
|
});
|
|
154
191
|
|
|
155
192
|
test("flag ON skill appears normally", () => {
|
|
156
|
-
const catalog = [
|
|
193
|
+
const catalog = [
|
|
194
|
+
makeSkill(DECLARED_SKILL_ID, "bundled", DECLARED_FLAG_ID),
|
|
195
|
+
makeSkill("browser", "bundled", "browser"),
|
|
196
|
+
];
|
|
157
197
|
const config = makeConfig({
|
|
158
198
|
assistantFeatureFlagValues: {
|
|
159
199
|
[DECLARED_FLAG_KEY]: true,
|
|
160
|
-
"feature_flags.
|
|
200
|
+
"feature_flags.browser.enabled": true,
|
|
161
201
|
},
|
|
162
202
|
});
|
|
163
203
|
|
|
@@ -165,11 +205,11 @@ describe("resolveSkillStates with feature flags", () => {
|
|
|
165
205
|
const ids = resolved.map((r) => r.summary.id);
|
|
166
206
|
|
|
167
207
|
expect(ids).toContain(DECLARED_SKILL_ID);
|
|
168
|
-
expect(ids).toContain("
|
|
208
|
+
expect(ids).toContain("browser");
|
|
169
209
|
});
|
|
170
210
|
|
|
171
211
|
test("declared flag key defaults to registry value (false)", () => {
|
|
172
|
-
const catalog = [makeSkill(DECLARED_SKILL_ID)];
|
|
212
|
+
const catalog = [makeSkill(DECLARED_SKILL_ID, "bundled", DECLARED_FLAG_ID)];
|
|
173
213
|
const config = makeConfig();
|
|
174
214
|
|
|
175
215
|
const resolved = resolveSkillStates(catalog, config);
|
|
@@ -177,8 +217,19 @@ describe("resolveSkillStates with feature flags", () => {
|
|
|
177
217
|
expect(resolved.length).toBe(0);
|
|
178
218
|
});
|
|
179
219
|
|
|
220
|
+
test("skill without featureFlag is never flag-gated", () => {
|
|
221
|
+
const catalog = [makeSkill("no-flag-skill")];
|
|
222
|
+
const config = makeConfig();
|
|
223
|
+
|
|
224
|
+
const resolved = resolveSkillStates(catalog, config);
|
|
225
|
+
const ids = resolved.map((r) => r.summary.id);
|
|
226
|
+
|
|
227
|
+
// Skills without featureFlag are never gated — always pass through
|
|
228
|
+
expect(ids).toContain("no-flag-skill");
|
|
229
|
+
});
|
|
230
|
+
|
|
180
231
|
test("feature flag OFF takes precedence over user-enabled config entry", () => {
|
|
181
|
-
const catalog = [makeSkill(DECLARED_SKILL_ID)];
|
|
232
|
+
const catalog = [makeSkill(DECLARED_SKILL_ID, "bundled", DECLARED_FLAG_ID)];
|
|
182
233
|
const config = makeConfig({
|
|
183
234
|
assistantFeatureFlagValues: { [DECLARED_FLAG_KEY]: false },
|
|
184
235
|
skills: {
|
|
@@ -205,14 +256,14 @@ describe("resolveSkillStates with feature flags", () => {
|
|
|
205
256
|
|
|
206
257
|
test("multiple skills with mixed flags — persisted overrides respected", () => {
|
|
207
258
|
const catalog = [
|
|
208
|
-
makeSkill(DECLARED_SKILL_ID),
|
|
209
|
-
makeSkill("
|
|
210
|
-
makeSkill("deploy"),
|
|
259
|
+
makeSkill(DECLARED_SKILL_ID, "bundled", DECLARED_FLAG_ID),
|
|
260
|
+
makeSkill("browser", "bundled", "browser"),
|
|
261
|
+
makeSkill("deploy", "bundled", "deploy"),
|
|
211
262
|
];
|
|
212
263
|
const config = makeConfig({
|
|
213
264
|
assistantFeatureFlagValues: {
|
|
214
265
|
[DECLARED_FLAG_KEY]: false,
|
|
215
|
-
"feature_flags.
|
|
266
|
+
"feature_flags.browser.enabled": true,
|
|
216
267
|
"feature_flags.deploy.enabled": false,
|
|
217
268
|
},
|
|
218
269
|
});
|
|
@@ -220,7 +271,63 @@ describe("resolveSkillStates with feature flags", () => {
|
|
|
220
271
|
const resolved = resolveSkillStates(catalog, config);
|
|
221
272
|
const ids = resolved.map((r) => r.summary.id);
|
|
222
273
|
|
|
223
|
-
// hatch-new-assistant and deploy explicitly false;
|
|
224
|
-
expect(ids).toEqual(["
|
|
274
|
+
// hatch-new-assistant and deploy explicitly false; browser explicitly true
|
|
275
|
+
expect(ids).toEqual(["browser"]);
|
|
276
|
+
});
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
// ---------------------------------------------------------------------------
|
|
280
|
+
// resolveSkillStates — frontmatter featureFlag gating
|
|
281
|
+
// ---------------------------------------------------------------------------
|
|
282
|
+
|
|
283
|
+
describe("resolveSkillStates with frontmatter featureFlag", () => {
|
|
284
|
+
test("skill with featureFlag (defaultEnabled: false) is filtered when no config override", () => {
|
|
285
|
+
// hatch-new-assistant has defaultEnabled: false in the registry
|
|
286
|
+
const catalog = [makeSkill(DECLARED_SKILL_ID, "bundled", DECLARED_FLAG_ID)];
|
|
287
|
+
const config = makeConfig();
|
|
288
|
+
|
|
289
|
+
const resolved = resolveSkillStates(catalog, config);
|
|
290
|
+
// No override, registry default is false → filtered out
|
|
291
|
+
expect(resolved.length).toBe(0);
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
test("skill with featureFlag is included when config override enables it", () => {
|
|
295
|
+
const catalog = [makeSkill(DECLARED_SKILL_ID, "bundled", DECLARED_FLAG_ID)];
|
|
296
|
+
const config = makeConfig({
|
|
297
|
+
assistantFeatureFlagValues: { [DECLARED_FLAG_KEY]: true },
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
const resolved = resolveSkillStates(catalog, config);
|
|
301
|
+
const ids = resolved.map((r) => r.summary.id);
|
|
302
|
+
expect(ids).toContain(DECLARED_SKILL_ID);
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
test("skill without featureFlag is NEVER filtered by the flag system", () => {
|
|
306
|
+
const catalog = [makeSkill("no-flag-skill")];
|
|
307
|
+
const config = makeConfig();
|
|
308
|
+
|
|
309
|
+
const resolved = resolveSkillStates(catalog, config);
|
|
310
|
+
const ids = resolved.map((r) => r.summary.id);
|
|
311
|
+
|
|
312
|
+
// No featureFlag declared → always passes through regardless of any flags
|
|
313
|
+
expect(ids).toContain("no-flag-skill");
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
test("skill without featureFlag passes through even when feature_flags.<skillId>.enabled is explicitly false", () => {
|
|
317
|
+
// This proves the implicit skillId→flag mapping is gone:
|
|
318
|
+
// setting feature_flags.my-skill.enabled = false has no effect
|
|
319
|
+
// when the skill itself does not declare a featureFlag.
|
|
320
|
+
const catalog = [makeSkill("my-skill")];
|
|
321
|
+
const config = makeConfig({
|
|
322
|
+
assistantFeatureFlagValues: {
|
|
323
|
+
"feature_flags.my-skill.enabled": false,
|
|
324
|
+
},
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
const resolved = resolveSkillStates(catalog, config);
|
|
328
|
+
const ids = resolved.map((r) => r.summary.id);
|
|
329
|
+
|
|
330
|
+
// The skill has no featureFlag field, so it is never gated
|
|
331
|
+
expect(ids).toContain("my-skill");
|
|
225
332
|
});
|
|
226
333
|
});
|
|
@@ -21,7 +21,6 @@ const platformOverrides: Record<string, (...args: unknown[]) => unknown> = {
|
|
|
21
21
|
getRootDir: () => TEST_DIR,
|
|
22
22
|
getDataDir: () => TEST_DIR,
|
|
23
23
|
ensureDataDir: () => {},
|
|
24
|
-
getSocketPath: () => join(TEST_DIR, "vellum.sock"),
|
|
25
24
|
getPidPath: () => join(TEST_DIR, "vellum.pid"),
|
|
26
25
|
getDbPath: () => join(TEST_DIR, "data", "assistant.db"),
|
|
27
26
|
getLogPath: () => join(TEST_DIR, "logs", "vellum.log"),
|
|
@@ -93,7 +92,7 @@ function writeSkill(
|
|
|
93
92
|
mkdirSync(skillDir, { recursive: true });
|
|
94
93
|
writeFileSync(
|
|
95
94
|
join(skillDir, "SKILL.md"),
|
|
96
|
-
`---\nname: "${name}"\ndescription: "${description}"\n---\n\n${body}\n`,
|
|
95
|
+
`---\nname: "${name}"\ndescription: "${description}"\nmetadata: {"vellum":{"feature-flag":"${skillId}"}}\n---\n\n${body}\n`,
|
|
97
96
|
);
|
|
98
97
|
}
|
|
99
98
|
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
existsSync,
|
|
3
|
+
mkdirSync,
|
|
4
|
+
rmSync,
|
|
5
|
+
symlinkSync,
|
|
6
|
+
writeFileSync,
|
|
7
|
+
} from "node:fs";
|
|
2
8
|
import { tmpdir } from "node:os";
|
|
3
9
|
import { join } from "node:path";
|
|
4
10
|
import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test";
|
|
@@ -14,7 +20,6 @@ const platformOverrides: Record<string, (...args: unknown[]) => unknown> = {
|
|
|
14
20
|
getRootDir: () => TEST_DIR,
|
|
15
21
|
getDataDir: () => TEST_DIR,
|
|
16
22
|
ensureDataDir: () => {},
|
|
17
|
-
getSocketPath: () => join(TEST_DIR, "vellum.sock"),
|
|
18
23
|
getPidPath: () => join(TEST_DIR, "vellum.pid"),
|
|
19
24
|
getDbPath: () => join(TEST_DIR, "data", "assistant.db"),
|
|
20
25
|
getLogPath: () => join(TEST_DIR, "logs", "vellum.log"),
|
|
@@ -93,6 +98,35 @@ function writeSkillWithIncludes(
|
|
|
93
98
|
);
|
|
94
99
|
}
|
|
95
100
|
|
|
101
|
+
function writeToolsJson(
|
|
102
|
+
skillId: string,
|
|
103
|
+
tools: Array<{
|
|
104
|
+
name: string;
|
|
105
|
+
description: string;
|
|
106
|
+
category?: string;
|
|
107
|
+
risk?: string;
|
|
108
|
+
input_schema?: Record<string, unknown>;
|
|
109
|
+
executor?: string;
|
|
110
|
+
execution_target?: string;
|
|
111
|
+
}>,
|
|
112
|
+
): void {
|
|
113
|
+
const skillDir = join(TEST_DIR, "skills", skillId);
|
|
114
|
+
mkdirSync(skillDir, { recursive: true });
|
|
115
|
+
const manifest = {
|
|
116
|
+
version: 1,
|
|
117
|
+
tools: tools.map((t) => ({
|
|
118
|
+
name: t.name,
|
|
119
|
+
description: t.description,
|
|
120
|
+
category: t.category ?? "general",
|
|
121
|
+
risk: t.risk ?? "low",
|
|
122
|
+
input_schema: t.input_schema ?? { type: "object", properties: {} },
|
|
123
|
+
executor: t.executor ?? "scripts/run.sh",
|
|
124
|
+
execution_target: t.execution_target ?? "host",
|
|
125
|
+
})),
|
|
126
|
+
};
|
|
127
|
+
writeFileSync(join(skillDir, "TOOLS.json"), JSON.stringify(manifest));
|
|
128
|
+
}
|
|
129
|
+
|
|
96
130
|
async function executeSkillLoad(
|
|
97
131
|
input: Record<string, unknown>,
|
|
98
132
|
): Promise<{ content: string; isError: boolean }> {
|
|
@@ -614,6 +648,33 @@ describe("skill_load tool", () => {
|
|
|
614
648
|
expect(result.content).not.toContain("--- Reference:");
|
|
615
649
|
});
|
|
616
650
|
|
|
651
|
+
test("references/ directory skips symlinked markdown files that escape the skill directory", async () => {
|
|
652
|
+
if (process.platform === "win32") {
|
|
653
|
+
// Symlink creation is not consistently available in Windows test environments.
|
|
654
|
+
return;
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
const skillDir = join(TEST_DIR, "skills", "refs-symlink");
|
|
658
|
+
mkdirSync(skillDir, { recursive: true });
|
|
659
|
+
mkdirSync(join(skillDir, "references"), { recursive: true });
|
|
660
|
+
writeFileSync(
|
|
661
|
+
join(skillDir, "SKILL.md"),
|
|
662
|
+
'---\nname: "Refs Symlink"\ndescription: "Skips symlinks"\n---\n\nBody.\n',
|
|
663
|
+
);
|
|
664
|
+
|
|
665
|
+
const outsideSecretPath = join(TEST_DIR, "outside-secret.md");
|
|
666
|
+
writeFileSync(outsideSecretPath, "TOP_SECRET_DO_NOT_LOAD");
|
|
667
|
+
symlinkSync(outsideSecretPath, join(skillDir, "references", "secret.md"));
|
|
668
|
+
|
|
669
|
+
writeFileSync(join(TEST_DIR, "skills", "SKILLS.md"), "- refs-symlink\n");
|
|
670
|
+
|
|
671
|
+
const result = await executeSkillLoad({ skill: "refs-symlink" });
|
|
672
|
+
expect(result.isError).toBe(false);
|
|
673
|
+
expect(result.content).toContain("Body.");
|
|
674
|
+
expect(result.content).not.toContain("--- Reference: Secret ---");
|
|
675
|
+
expect(result.content).not.toContain("TOP_SECRET_DO_NOT_LOAD");
|
|
676
|
+
});
|
|
677
|
+
|
|
617
678
|
test("references/ directory ignores non-markdown files", async () => {
|
|
618
679
|
const skillDir = join(TEST_DIR, "skills", "refs-filter");
|
|
619
680
|
mkdirSync(skillDir, { recursive: true });
|
|
@@ -658,4 +719,135 @@ describe("skill_load tool", () => {
|
|
|
658
719
|
/<loaded_skill id="empty-includes" version="v1:[a-f0-9]{64}" \/>/,
|
|
659
720
|
);
|
|
660
721
|
});
|
|
722
|
+
|
|
723
|
+
test("skill with TOOLS.json includes tool schemas section in output", async () => {
|
|
724
|
+
writeSkill(
|
|
725
|
+
"skill-with-tools",
|
|
726
|
+
"Skill With Tools",
|
|
727
|
+
"Has tools",
|
|
728
|
+
"Main body.",
|
|
729
|
+
);
|
|
730
|
+
writeToolsJson("skill-with-tools", [
|
|
731
|
+
{
|
|
732
|
+
name: "deploy_app",
|
|
733
|
+
description: "Deploy the application to production",
|
|
734
|
+
input_schema: {
|
|
735
|
+
type: "object",
|
|
736
|
+
properties: {
|
|
737
|
+
environment: {
|
|
738
|
+
type: "string",
|
|
739
|
+
description: "Target environment",
|
|
740
|
+
},
|
|
741
|
+
force: {
|
|
742
|
+
type: "boolean",
|
|
743
|
+
description: "Force deploy even if checks fail",
|
|
744
|
+
},
|
|
745
|
+
},
|
|
746
|
+
required: ["environment"],
|
|
747
|
+
},
|
|
748
|
+
},
|
|
749
|
+
{
|
|
750
|
+
name: "rollback_app",
|
|
751
|
+
description: "Rollback to previous version",
|
|
752
|
+
input_schema: {
|
|
753
|
+
type: "object",
|
|
754
|
+
properties: {
|
|
755
|
+
version: {
|
|
756
|
+
type: "string",
|
|
757
|
+
description: "Version to rollback to",
|
|
758
|
+
},
|
|
759
|
+
},
|
|
760
|
+
required: ["version"],
|
|
761
|
+
},
|
|
762
|
+
},
|
|
763
|
+
]);
|
|
764
|
+
writeFileSync(
|
|
765
|
+
join(TEST_DIR, "skills", "SKILLS.md"),
|
|
766
|
+
"- skill-with-tools\n",
|
|
767
|
+
);
|
|
768
|
+
|
|
769
|
+
const result = await executeSkillLoad({ skill: "skill-with-tools" });
|
|
770
|
+
expect(result.isError).toBe(false);
|
|
771
|
+
|
|
772
|
+
// Should contain the Available Tools section header
|
|
773
|
+
expect(result.content).toContain("## Available Tools");
|
|
774
|
+
|
|
775
|
+
// Should instruct the LLM to use skill_execute
|
|
776
|
+
expect(result.content).toContain(
|
|
777
|
+
"Use `skill_execute` to call these tools.",
|
|
778
|
+
);
|
|
779
|
+
|
|
780
|
+
// Should contain tool names as headings
|
|
781
|
+
expect(result.content).toContain("### deploy_app");
|
|
782
|
+
expect(result.content).toContain("### rollback_app");
|
|
783
|
+
|
|
784
|
+
// Should contain tool descriptions
|
|
785
|
+
expect(result.content).toContain("Deploy the application to production");
|
|
786
|
+
expect(result.content).toContain("Rollback to previous version");
|
|
787
|
+
|
|
788
|
+
// Should list parameters with types and required/optional markers
|
|
789
|
+
expect(result.content).toContain(
|
|
790
|
+
"- environment (string, required): Target environment",
|
|
791
|
+
);
|
|
792
|
+
expect(result.content).toContain(
|
|
793
|
+
"- force (boolean, optional): Force deploy even if checks fail",
|
|
794
|
+
);
|
|
795
|
+
expect(result.content).toContain(
|
|
796
|
+
"- version (string, required): Version to rollback to",
|
|
797
|
+
);
|
|
798
|
+
});
|
|
799
|
+
|
|
800
|
+
test("skill without TOOLS.json does not include tool schemas section", async () => {
|
|
801
|
+
writeSkill("no-tools", "No Tools", "No tools manifest", "Body.");
|
|
802
|
+
writeFileSync(join(TEST_DIR, "skills", "SKILLS.md"), "- no-tools\n");
|
|
803
|
+
|
|
804
|
+
const result = await executeSkillLoad({ skill: "no-tools" });
|
|
805
|
+
expect(result.isError).toBe(false);
|
|
806
|
+
expect(result.content).not.toContain("## Available Tools");
|
|
807
|
+
expect(result.content).not.toContain("skill_execute");
|
|
808
|
+
});
|
|
809
|
+
|
|
810
|
+
test("included child skill with TOOLS.json has its tool schemas in output", async () => {
|
|
811
|
+
writeSkillWithIncludes(
|
|
812
|
+
"parent-tools",
|
|
813
|
+
"Parent Tools",
|
|
814
|
+
"Parent with tooled child",
|
|
815
|
+
"Parent body.",
|
|
816
|
+
["child-tools"],
|
|
817
|
+
);
|
|
818
|
+
writeSkill("child-tools", "Child Tools", "Child with tools", "Child body.");
|
|
819
|
+
writeToolsJson("child-tools", [
|
|
820
|
+
{
|
|
821
|
+
name: "child_action",
|
|
822
|
+
description: "A child tool action",
|
|
823
|
+
input_schema: {
|
|
824
|
+
type: "object",
|
|
825
|
+
properties: {
|
|
826
|
+
target: {
|
|
827
|
+
type: "string",
|
|
828
|
+
description: "Action target",
|
|
829
|
+
},
|
|
830
|
+
},
|
|
831
|
+
required: ["target"],
|
|
832
|
+
},
|
|
833
|
+
},
|
|
834
|
+
]);
|
|
835
|
+
writeFileSync(
|
|
836
|
+
join(TEST_DIR, "skills", "SKILLS.md"),
|
|
837
|
+
"- parent-tools\n- child-tools\n",
|
|
838
|
+
);
|
|
839
|
+
|
|
840
|
+
const result = await executeSkillLoad({ skill: "parent-tools" });
|
|
841
|
+
expect(result.isError).toBe(false);
|
|
842
|
+
|
|
843
|
+
// The child skill's tool schemas should appear (#### level under ### Tools from …)
|
|
844
|
+
expect(result.content).toContain("#### child_action");
|
|
845
|
+
expect(result.content).toContain("A child tool action");
|
|
846
|
+
expect(result.content).toContain(
|
|
847
|
+
"- target (string, required): Action target",
|
|
848
|
+
);
|
|
849
|
+
expect(result.content).toContain(
|
|
850
|
+
"Use `skill_execute` to call these tools.",
|
|
851
|
+
);
|
|
852
|
+
});
|
|
661
853
|
});
|
|
@@ -58,7 +58,10 @@ mock.module("../config/assistant-feature-flags.js", () => ({
|
|
|
58
58
|
}));
|
|
59
59
|
|
|
60
60
|
mock.module("../config/skill-state.js", () => ({
|
|
61
|
-
skillFlagKey: (
|
|
61
|
+
skillFlagKey: (skill: { featureFlag?: string }) =>
|
|
62
|
+
skill.featureFlag
|
|
63
|
+
? `feature_flags.${skill.featureFlag}.enabled`
|
|
64
|
+
: undefined,
|
|
62
65
|
}));
|
|
63
66
|
|
|
64
67
|
mock.module("../skills/active-skill-tools.js", () => {
|
|
@@ -221,7 +224,7 @@ const { projectSkillTools, resetSkillToolProjection } =
|
|
|
221
224
|
// Helpers
|
|
222
225
|
// ---------------------------------------------------------------------------
|
|
223
226
|
|
|
224
|
-
function makeSkill(id: string): SkillSummary {
|
|
227
|
+
function makeSkill(id: string, featureFlag?: string): SkillSummary {
|
|
225
228
|
return {
|
|
226
229
|
id,
|
|
227
230
|
name: id,
|
|
@@ -232,6 +235,7 @@ function makeSkill(id: string): SkillSummary {
|
|
|
232
235
|
userInvocable: true,
|
|
233
236
|
disableModelInvocation: false,
|
|
234
237
|
source: "managed",
|
|
238
|
+
featureFlag,
|
|
235
239
|
};
|
|
236
240
|
}
|
|
237
241
|
|
|
@@ -293,7 +297,7 @@ describe("projectSkillTools feature flag enforcement", () => {
|
|
|
293
297
|
});
|
|
294
298
|
|
|
295
299
|
test("no skill tools projected for flag OFF skill even with old markers", () => {
|
|
296
|
-
mockCatalog = [makeSkill(DECLARED_SKILL_ID)];
|
|
300
|
+
mockCatalog = [makeSkill(DECLARED_SKILL_ID, DECLARED_SKILL_ID)];
|
|
297
301
|
mockManifests = {
|
|
298
302
|
[DECLARED_SKILL_ID]: makeManifest(["browser_navigate", "browser_click"]),
|
|
299
303
|
};
|
|
@@ -317,7 +321,7 @@ describe("projectSkillTools feature flag enforcement", () => {
|
|
|
317
321
|
});
|
|
318
322
|
|
|
319
323
|
test("skill tools projected normally when flag is ON", () => {
|
|
320
|
-
mockCatalog = [makeSkill(DECLARED_SKILL_ID)];
|
|
324
|
+
mockCatalog = [makeSkill(DECLARED_SKILL_ID, DECLARED_SKILL_ID)];
|
|
321
325
|
mockManifests = {
|
|
322
326
|
[DECLARED_SKILL_ID]: makeManifest(["browser_navigate", "browser_click"]),
|
|
323
327
|
};
|
|
@@ -334,34 +338,41 @@ describe("projectSkillTools feature flag enforcement", () => {
|
|
|
334
338
|
previouslyActiveSkillIds: prevActive,
|
|
335
339
|
});
|
|
336
340
|
|
|
337
|
-
|
|
341
|
+
// Tool definitions are no longer returned (dispatched via skill_execute),
|
|
342
|
+
// but allowedToolNames should contain the registered tool names.
|
|
343
|
+
expect(result.toolDefinitions).toHaveLength(0);
|
|
344
|
+
expect(result.allowedToolNames.size).toBe(2);
|
|
338
345
|
expect(result.allowedToolNames.has("browser_navigate")).toBe(true);
|
|
339
346
|
expect(result.allowedToolNames.has("browser_click")).toBe(true);
|
|
340
347
|
});
|
|
341
348
|
|
|
342
|
-
test("skill tools projected normally when
|
|
349
|
+
test("skill tools projected normally when no featureFlag declared (never gated)", () => {
|
|
343
350
|
mockCatalog = [makeSkill(DECLARED_SKILL_ID)];
|
|
344
351
|
mockManifests = { [DECLARED_SKILL_ID]: makeManifest(["browser_navigate"]) };
|
|
345
352
|
|
|
346
353
|
const history = buildHistoryWithMarker(DECLARED_SKILL_ID);
|
|
347
354
|
const prevActive = new Map<string, string>();
|
|
348
355
|
|
|
349
|
-
// No overrides —
|
|
356
|
+
// No overrides — skill has no featureFlag so it's never gated
|
|
350
357
|
currentConfig = {};
|
|
351
358
|
|
|
352
359
|
const result = projectSkillTools(history, {
|
|
353
360
|
previouslyActiveSkillIds: prevActive,
|
|
354
361
|
});
|
|
355
362
|
|
|
356
|
-
expect(result.toolDefinitions).toHaveLength(
|
|
363
|
+
expect(result.toolDefinitions).toHaveLength(0);
|
|
364
|
+
expect(result.allowedToolNames.size).toBe(1);
|
|
357
365
|
expect(result.allowedToolNames.has("browser_navigate")).toBe(true);
|
|
358
366
|
});
|
|
359
367
|
|
|
360
368
|
test("mixed flag-on and flag-off skills — only flag-on tools projected", () => {
|
|
361
|
-
mockCatalog = [
|
|
369
|
+
mockCatalog = [
|
|
370
|
+
makeSkill(DECLARED_SKILL_ID, DECLARED_SKILL_ID),
|
|
371
|
+
makeSkill("plain-skill"),
|
|
372
|
+
];
|
|
362
373
|
mockManifests = {
|
|
363
374
|
[DECLARED_SKILL_ID]: makeManifest(["browser_navigate"]),
|
|
364
|
-
|
|
375
|
+
"plain-skill": makeManifest(["plain_action"]),
|
|
365
376
|
};
|
|
366
377
|
|
|
367
378
|
const history: Message[] = [
|
|
@@ -393,7 +404,7 @@ describe("projectSkillTools feature flag enforcement", () => {
|
|
|
393
404
|
type: "tool_use",
|
|
394
405
|
id: "tu-2",
|
|
395
406
|
name: "skill_load",
|
|
396
|
-
input: { skill: "
|
|
407
|
+
input: { skill: "plain-skill" },
|
|
397
408
|
},
|
|
398
409
|
],
|
|
399
410
|
},
|
|
@@ -404,14 +415,14 @@ describe("projectSkillTools feature flag enforcement", () => {
|
|
|
404
415
|
type: "tool_result",
|
|
405
416
|
tool_use_id: "tu-2",
|
|
406
417
|
content:
|
|
407
|
-
'<loaded_skill id="
|
|
418
|
+
'<loaded_skill id="plain-skill" version="v1:default-hash-plain-skill" />',
|
|
408
419
|
},
|
|
409
420
|
],
|
|
410
421
|
},
|
|
411
422
|
];
|
|
412
423
|
const prevActive = new Map<string, string>();
|
|
413
424
|
|
|
414
|
-
// Declared skill is OFF,
|
|
425
|
+
// Declared skill is OFF, plain-skill is undeclared with no persisted override so remains ON.
|
|
415
426
|
currentConfig = {
|
|
416
427
|
assistantFeatureFlagValues: { [DECLARED_FLAG_KEY]: false },
|
|
417
428
|
};
|
|
@@ -420,8 +431,8 @@ describe("projectSkillTools feature flag enforcement", () => {
|
|
|
420
431
|
previouslyActiveSkillIds: prevActive,
|
|
421
432
|
});
|
|
422
433
|
|
|
423
|
-
|
|
424
|
-
expect(
|
|
425
|
-
expect(
|
|
434
|
+
// Tool definitions are no longer returned; check allowedToolNames instead
|
|
435
|
+
expect(result.allowedToolNames.has("plain_action")).toBe(true);
|
|
436
|
+
expect(result.allowedToolNames.has("browser_navigate")).toBe(false);
|
|
426
437
|
});
|
|
427
438
|
});
|
|
@@ -68,7 +68,10 @@ mock.module("../config/skills.js", () => ({
|
|
|
68
68
|
// Mock skill-state.js to break the transitive import chain — the benchmark
|
|
69
69
|
// only needs skillFlagKey and doesn't exercise resolveSkillStates.
|
|
70
70
|
mock.module("../config/skill-state.js", () => ({
|
|
71
|
-
skillFlagKey: (
|
|
71
|
+
skillFlagKey: (skill: { featureFlag?: string }) =>
|
|
72
|
+
skill.featureFlag
|
|
73
|
+
? `feature_flags.${skill.featureFlag}.enabled`
|
|
74
|
+
: undefined,
|
|
72
75
|
resolveSkillStates: () => [],
|
|
73
76
|
}));
|
|
74
77
|
|
|
@@ -276,7 +279,6 @@ describe("Skill projection benchmark", () => {
|
|
|
276
279
|
|
|
277
280
|
const elapsed = timeMs(() => {
|
|
278
281
|
const result = projectSkillTools(history);
|
|
279
|
-
expect(result.toolDefinitions.length).toBeGreaterThan(0);
|
|
280
282
|
expect(result.allowedToolNames.size).toBeGreaterThan(0);
|
|
281
283
|
});
|
|
282
284
|
|
|
@@ -327,12 +329,12 @@ describe("Skill projection benchmark", () => {
|
|
|
327
329
|
expect(cache.derived!.entries.length).toBe(entriesCountAfterWarm);
|
|
328
330
|
expect(cache.derived!.seenIds.size).toBe(seenIdsSizeAfterWarm);
|
|
329
331
|
|
|
330
|
-
// Assert tool
|
|
331
|
-
expect(cachedResult!.
|
|
332
|
-
warmResult.
|
|
332
|
+
// Assert allowed tool names are identical between warm and cached calls
|
|
333
|
+
expect(cachedResult!.allowedToolNames.size).toBe(
|
|
334
|
+
warmResult.allowedToolNames.size,
|
|
333
335
|
);
|
|
334
|
-
const warmNames = warmResult.
|
|
335
|
-
const cachedNames = cachedResult!.
|
|
336
|
+
const warmNames = [...warmResult.allowedToolNames].sort();
|
|
337
|
+
const cachedNames = [...cachedResult!.allowedToolNames].sort();
|
|
336
338
|
expect(cachedNames).toEqual(warmNames);
|
|
337
339
|
|
|
338
340
|
console.log(` Cached projection (no change): ${elapsed.toFixed(2)}ms`);
|
|
@@ -373,12 +375,12 @@ describe("Skill projection benchmark", () => {
|
|
|
373
375
|
expect(cache.derived!.entries.length).toBe(snapshotEntriesCount);
|
|
374
376
|
expect(cache.derived!.seenIds.size).toBe(snapshotSeenIdsSize);
|
|
375
377
|
|
|
376
|
-
//
|
|
377
|
-
expect(result.
|
|
378
|
-
firstResult.
|
|
378
|
+
// Allowed tool names must match the first call exactly
|
|
379
|
+
expect(result.allowedToolNames.size).toBe(
|
|
380
|
+
firstResult.allowedToolNames.size,
|
|
379
381
|
);
|
|
380
|
-
expect(result.
|
|
381
|
-
firstResult.
|
|
382
|
+
expect([...result.allowedToolNames].sort()).toEqual(
|
|
383
|
+
[...firstResult.allowedToolNames].sort(),
|
|
382
384
|
);
|
|
383
385
|
}
|
|
384
386
|
});
|
|
@@ -396,7 +398,6 @@ describe("Skill projection benchmark", () => {
|
|
|
396
398
|
|
|
397
399
|
const elapsed = timeMs(() => {
|
|
398
400
|
const result = projectSkillTools(history);
|
|
399
|
-
expect(result.toolDefinitions.length).toBeGreaterThan(0);
|
|
400
401
|
expect(result.allowedToolNames.size).toBeGreaterThan(0);
|
|
401
402
|
});
|
|
402
403
|
|
|
@@ -429,7 +430,7 @@ describe("Skill projection benchmark", () => {
|
|
|
429
430
|
cache,
|
|
430
431
|
previouslyActiveSkillIds: prevActive,
|
|
431
432
|
});
|
|
432
|
-
expect(result.
|
|
433
|
+
expect(result.allowedToolNames.size).toBeGreaterThan(0);
|
|
433
434
|
});
|
|
434
435
|
|
|
435
436
|
console.log(` Incremental scan (10 new msgs): ${elapsed.toFixed(2)}ms`);
|