@vellumai/assistant 0.4.49 → 0.4.51
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 +24 -33
- package/README.md +3 -3
- package/docs/architecture/integrations.md +2 -2
- package/docs/architecture/keychain-broker.md +6 -6
- package/docs/architecture/memory.md +180 -119
- package/knip.json +32 -0
- package/package.json +3 -2
- package/src/__tests__/agent-loop.test.ts +3 -1
- package/src/__tests__/anthropic-provider.test.ts +114 -23
- package/src/__tests__/approval-cascade.test.ts +1 -15
- package/src/__tests__/approval-routes-http.test.ts +2 -0
- package/src/__tests__/assistant-feature-flag-guard.test.ts +0 -23
- package/src/__tests__/btw-routes.test.ts +61 -5
- package/src/__tests__/canonical-guardian-store.test.ts +95 -0
- package/src/__tests__/checker.test.ts +13 -0
- package/src/__tests__/config-schema.test.ts +1 -68
- package/src/__tests__/config-watcher.test.ts +8 -0
- package/src/__tests__/context-memory-e2e.test.ts +11 -100
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +8 -0
- package/src/__tests__/conversation-routes-slash-commands.test.ts +1 -0
- package/src/__tests__/credential-security-e2e.test.ts +1 -0
- package/src/__tests__/credential-security-invariants.test.ts +8 -7
- package/src/__tests__/credential-vault-unit.test.ts +23 -18
- package/src/__tests__/credential-vault.test.ts +30 -18
- package/src/__tests__/credentials-cli.test.ts +257 -82
- package/src/__tests__/cu-unified-flow.test.ts +532 -0
- package/src/__tests__/date-context.test.ts +93 -77
- package/src/__tests__/deterministic-verification-control-plane.test.ts +64 -0
- package/src/__tests__/guardian-routing-invariants.test.ts +93 -0
- package/src/__tests__/history-repair.test.ts +245 -0
- package/src/__tests__/host-cu-proxy.test.ts +165 -3
- package/src/__tests__/http-user-message-parity.test.ts +1 -0
- package/src/__tests__/inbound-invite-redemption.test.ts +36 -7
- package/src/__tests__/integration-status.test.ts +31 -30
- package/src/__tests__/invite-redemption-service.test.ts +166 -13
- package/src/__tests__/invite-routes-http.test.ts +166 -5
- package/src/__tests__/keychain-broker-client.test.ts +4 -4
- package/src/__tests__/list-messages-attachments.test.ts +193 -0
- package/src/__tests__/memory-context-benchmark.benchmark.test.ts +56 -18
- package/src/__tests__/memory-lifecycle-e2e.test.ts +244 -387
- package/src/__tests__/memory-recall-quality.test.ts +244 -407
- package/src/__tests__/memory-regressions.experimental.test.ts +126 -101
- package/src/__tests__/memory-regressions.test.ts +477 -2841
- package/src/__tests__/memory-retrieval.benchmark.test.ts +33 -150
- package/src/__tests__/memory-upsert-concurrency.test.ts +5 -244
- package/src/__tests__/mime-builder.test.ts +28 -0
- package/src/__tests__/native-web-search.test.ts +1 -0
- package/src/__tests__/oauth-cli.test.ts +824 -31
- package/src/__tests__/oauth-provider-profiles.test.ts +1 -1
- package/src/__tests__/oauth-store.test.ts +363 -17
- package/src/__tests__/qdrant-collection-migration.test.ts +53 -8
- package/src/__tests__/registry.test.ts +0 -1
- package/src/__tests__/relay-server.test.ts +55 -1
- package/src/__tests__/schedule-tools.test.ts +32 -0
- package/src/__tests__/script-proxy-certs.test.ts +1 -1
- package/src/__tests__/secret-onetime-send.test.ts +1 -0
- package/src/__tests__/secret-routes-managed-proxy.test.ts +183 -0
- package/src/__tests__/secure-keys.test.ts +78 -18
- package/src/__tests__/send-endpoint-busy.test.ts +3 -0
- package/src/__tests__/server-history-render.test.ts +2 -2
- package/src/__tests__/session-abort-tool-results.test.ts +1 -14
- package/src/__tests__/session-agent-loop-overflow.test.ts +1583 -0
- package/src/__tests__/session-agent-loop.test.ts +19 -15
- package/src/__tests__/session-confirmation-signals.test.ts +1 -15
- package/src/__tests__/session-error.test.ts +124 -2
- package/src/__tests__/session-history-web-search.test.ts +918 -0
- package/src/__tests__/session-pre-run-repair.test.ts +1 -14
- package/src/__tests__/session-provider-retry-repair.test.ts +25 -28
- package/src/__tests__/session-queue.test.ts +37 -27
- package/src/__tests__/session-runtime-assembly.test.ts +54 -0
- package/src/__tests__/session-slash-known.test.ts +1 -15
- package/src/__tests__/session-slash-queue.test.ts +1 -15
- package/src/__tests__/session-slash-unknown.test.ts +1 -15
- package/src/__tests__/session-workspace-cache-state.test.ts +3 -33
- package/src/__tests__/session-workspace-injection.test.ts +3 -37
- package/src/__tests__/session-workspace-tool-tracking.test.ts +3 -37
- package/src/__tests__/skills-install-extract.test.ts +93 -0
- package/src/__tests__/skills.test.ts +2 -2
- package/src/__tests__/skillssh-registry.test.ts +451 -0
- package/src/__tests__/slack-channel-config.test.ts +10 -8
- package/src/__tests__/trust-store.test.ts +15 -0
- package/src/__tests__/twilio-config.test.ts +11 -10
- package/src/__tests__/twilio-provider.test.ts +9 -4
- package/src/__tests__/voice-invite-redemption.test.ts +85 -5
- package/src/agent/ax-tree-compaction.test.ts +51 -0
- package/src/agent/loop.ts +39 -12
- package/src/approvals/AGENTS.md +1 -1
- package/src/approvals/guardian-request-resolvers.ts +14 -2
- package/src/bundler/compiler-tools.ts +66 -2
- package/src/calls/call-domain.ts +134 -3
- package/src/calls/call-store.ts +6 -0
- package/src/calls/relay-server.ts +44 -6
- package/src/calls/relay-setup-router.ts +17 -1
- package/src/calls/twilio-config.ts +5 -4
- package/src/calls/twilio-provider.ts +14 -9
- package/src/calls/twilio-rest.ts +10 -7
- package/src/calls/types.ts +3 -1
- package/src/cli/commands/config.ts +14 -9
- package/src/cli/commands/contacts.ts +3 -0
- package/src/cli/commands/credentials.ts +170 -174
- package/src/cli/commands/doctor.ts +11 -8
- package/src/cli/commands/keys.ts +9 -9
- package/src/cli/commands/mcp.ts +46 -59
- package/src/cli/commands/memory.ts +16 -165
- package/src/cli/commands/oauth/apps.ts +68 -10
- package/src/cli/commands/oauth/connections.ts +475 -105
- package/src/cli/commands/oauth/index.ts +3 -3
- package/src/cli/commands/oauth/providers.ts +18 -4
- package/src/cli/commands/sessions.ts +5 -2
- package/src/cli/commands/skills.ts +173 -1
- package/src/cli/http-client.ts +0 -20
- package/src/cli/main-screen.tsx +2 -2
- package/src/cli/program.ts +5 -6
- package/src/cli.ts +20 -22
- package/src/config/__tests__/feature-flag-registry-bundled.test.ts +39 -0
- package/src/config/bundled-skills/computer-use/TOOLS.json +1 -1
- package/src/config/bundled-skills/computer-use/tools/computer-use-observe.ts +12 -0
- package/src/config/bundled-skills/contacts/SKILL.md +35 -11
- package/src/config/bundled-skills/contacts/tools/google-contacts.ts +1 -1
- package/src/config/bundled-skills/gmail/SKILL.md +1 -1
- package/src/config/bundled-skills/gmail/TOOLS.json +52 -0
- package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +13 -3
- package/src/config/bundled-skills/gmail/tools/gmail-attachments.ts +9 -2
- package/src/config/bundled-skills/gmail/tools/gmail-draft.ts +5 -1
- package/src/config/bundled-skills/gmail/tools/gmail-filters.ts +5 -1
- package/src/config/bundled-skills/gmail/tools/gmail-follow-up.ts +5 -1
- package/src/config/bundled-skills/gmail/tools/gmail-forward.ts +5 -1
- package/src/config/bundled-skills/gmail/tools/gmail-label.ts +9 -2
- package/src/config/bundled-skills/gmail/tools/gmail-outreach-scan.ts +5 -1
- package/src/config/bundled-skills/gmail/tools/gmail-send-draft.ts +5 -1
- package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +5 -1
- package/src/config/bundled-skills/gmail/tools/gmail-trash.ts +5 -1
- package/src/config/bundled-skills/gmail/tools/gmail-unsubscribe.ts +5 -1
- package/src/config/bundled-skills/gmail/tools/gmail-vacation.ts +5 -1
- package/src/config/bundled-skills/google-calendar/TOOLS.json +20 -0
- package/src/config/bundled-skills/google-calendar/tools/calendar-check-availability.ts +2 -1
- package/src/config/bundled-skills/google-calendar/tools/calendar-create-event.ts +2 -1
- package/src/config/bundled-skills/google-calendar/tools/calendar-get-event.ts +2 -1
- package/src/config/bundled-skills/google-calendar/tools/calendar-list-events.ts +2 -1
- package/src/config/bundled-skills/google-calendar/tools/calendar-rsvp.ts +2 -1
- package/src/config/bundled-skills/google-calendar/tools/shared.ts +8 -2
- package/src/config/bundled-skills/messaging/SKILL.md +1 -1
- package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +2 -2
- package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +2 -2
- package/src/config/bundled-skills/messaging/tools/messaging-auth-test.ts +2 -2
- package/src/config/bundled-skills/messaging/tools/messaging-list-conversations.ts +2 -2
- package/src/config/bundled-skills/messaging/tools/messaging-mark-read.ts +2 -2
- package/src/config/bundled-skills/messaging/tools/messaging-read.ts +2 -2
- package/src/config/bundled-skills/messaging/tools/messaging-search.ts +2 -2
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +2 -2
- package/src/config/bundled-skills/messaging/tools/messaging-sender-digest.ts +2 -2
- package/src/config/bundled-skills/messaging/tools/shared.ts +7 -5
- package/src/config/bundled-skills/slack/tools/shared.ts +1 -1
- package/src/config/bundled-skills/slack/tools/slack-add-reaction.ts +1 -1
- package/src/config/bundled-skills/slack/tools/slack-channel-details.ts +1 -1
- package/src/config/bundled-skills/slack/tools/slack-delete-message.ts +1 -1
- package/src/config/bundled-skills/slack/tools/slack-edit-message.ts +1 -1
- package/src/config/bundled-skills/slack/tools/slack-leave-channel.ts +1 -1
- package/src/config/bundled-skills/slack/tools/slack-scan-digest.ts +1 -1
- package/src/config/bundled-tool-registry.ts +2 -5
- package/src/config/loader.ts +6 -42
- package/src/config/schema.ts +1 -12
- package/src/config/schemas/memory-lifecycle.ts +0 -9
- package/src/config/schemas/memory-processing.ts +0 -180
- package/src/config/schemas/memory-retrieval.ts +32 -104
- package/src/config/schemas/memory.ts +0 -10
- package/src/config/types.ts +0 -4
- package/src/contacts/contact-store.ts +39 -2
- package/src/contacts/contacts-write.ts +9 -0
- package/src/context/window-manager.ts +4 -1
- package/src/daemon/config-watcher.ts +55 -2
- package/src/daemon/daemon-control.ts +1 -1
- package/src/daemon/date-context.ts +114 -31
- package/src/daemon/handlers/config-ingress.ts +2 -2
- package/src/daemon/handlers/config-slack-channel.ts +59 -39
- package/src/daemon/handlers/config-telegram.ts +23 -14
- package/src/daemon/handlers/session-history.ts +1 -358
- package/src/daemon/handlers/sessions.ts +18 -13
- package/src/daemon/handlers/shared.ts +3 -17
- package/src/daemon/handlers/skills.ts +20 -1
- package/src/daemon/history-repair.ts +72 -8
- package/src/daemon/host-cu-proxy.ts +55 -26
- package/src/daemon/lifecycle.ts +39 -4
- package/src/daemon/mcp-reload-service.ts +2 -2
- package/src/daemon/message-types/computer-use.ts +1 -12
- package/src/daemon/message-types/memory.ts +4 -16
- package/src/daemon/message-types/messages.ts +1 -0
- package/src/daemon/message-types/sessions.ts +4 -42
- package/src/daemon/server.ts +6 -1
- package/src/daemon/session-agent-loop-handlers.ts +38 -0
- package/src/daemon/session-agent-loop.ts +334 -48
- package/src/daemon/session-error.ts +89 -6
- package/src/daemon/session-history.ts +17 -7
- package/src/daemon/session-media-retry.ts +6 -2
- package/src/daemon/session-memory.ts +69 -149
- package/src/daemon/session-process.ts +10 -1
- package/src/daemon/session-runtime-assembly.ts +49 -19
- package/src/daemon/session-slash.ts +3 -5
- package/src/daemon/session-surfaces.ts +4 -1
- package/src/daemon/session-tool-setup.ts +7 -1
- package/src/daemon/session.ts +12 -2
- package/src/email/providers/index.ts +2 -2
- package/src/instrument.ts +61 -1
- package/src/media/avatar-router.ts +1 -1
- package/src/memory/admin.ts +2 -191
- package/src/memory/canonical-guardian-store.ts +38 -2
- package/src/memory/conversation-crud.ts +0 -33
- package/src/memory/conversation-queries.ts +25 -83
- package/src/memory/db-init.ts +32 -0
- package/src/memory/embedding-backend.ts +84 -8
- package/src/memory/embedding-types.ts +9 -1
- package/src/memory/indexer.ts +7 -46
- package/src/memory/invite-store.ts +19 -0
- package/src/memory/items-extractor.ts +274 -76
- package/src/memory/job-handlers/backfill.ts +2 -127
- package/src/memory/job-handlers/cleanup.ts +2 -16
- package/src/memory/job-handlers/extraction.ts +2 -138
- package/src/memory/job-handlers/index-maintenance.ts +1 -6
- package/src/memory/job-handlers/summarization.ts +3 -148
- package/src/memory/job-utils.ts +21 -59
- package/src/memory/jobs-store.ts +1 -159
- package/src/memory/jobs-worker.ts +9 -52
- package/src/memory/migrations/104-core-indexes.ts +3 -3
- package/src/memory/migrations/149-oauth-tables.ts +2 -0
- package/src/memory/migrations/150-oauth-apps-client-secret-path.ts +98 -0
- package/src/memory/migrations/151-oauth-providers-ping-url.ts +11 -0
- package/src/memory/migrations/152-memory-item-supersession.ts +44 -0
- package/src/memory/migrations/153-drop-entity-tables.ts +15 -0
- package/src/memory/migrations/154-drop-fts.ts +20 -0
- package/src/memory/migrations/155-drop-conflicts.ts +7 -0
- package/src/memory/migrations/156-call-session-invite-metadata.ts +24 -0
- package/src/memory/migrations/157-invite-contact-id.ts +104 -0
- package/src/memory/migrations/index.ts +8 -0
- package/src/memory/migrations/registry.ts +6 -0
- package/src/memory/qdrant-client.ts +148 -51
- package/src/memory/raw-query.ts +1 -1
- package/src/memory/retriever.test.ts +294 -273
- package/src/memory/retriever.ts +421 -645
- package/src/memory/schema/calls.ts +2 -0
- package/src/memory/schema/contacts.ts +1 -0
- package/src/memory/schema/memory-core.ts +3 -48
- package/src/memory/schema/oauth.ts +2 -0
- package/src/memory/search/formatting.ts +263 -176
- package/src/memory/search/lexical.ts +1 -254
- package/src/memory/search/ranking.ts +0 -455
- package/src/memory/search/semantic.ts +100 -14
- package/src/memory/search/staleness.ts +47 -0
- package/src/memory/search/tier-classifier.ts +21 -0
- package/src/memory/search/types.ts +15 -77
- package/src/memory/task-memory-cleanup.ts +4 -6
- package/src/messaging/provider.ts +1 -1
- package/src/messaging/providers/gmail/adapter.ts +1 -1
- package/src/messaging/providers/gmail/mime-builder.ts +17 -7
- package/src/messaging/providers/telegram-bot/adapter.ts +17 -8
- package/src/messaging/providers/whatsapp/adapter.ts +13 -9
- package/src/messaging/registry.ts +9 -5
- package/src/oauth/byo-connection.test.ts +40 -25
- package/src/oauth/connect-orchestrator.ts +4 -10
- package/src/oauth/connection-resolver.ts +20 -6
- package/src/oauth/manual-token-connection.ts +5 -5
- package/src/oauth/oauth-store.ts +183 -31
- package/src/oauth/platform-connection.test.ts +1 -1
- package/src/oauth/provider-behaviors.ts +503 -4
- package/src/oauth/seed-providers.ts +214 -8
- package/src/oauth/token-persistence.ts +31 -16
- package/src/permissions/defaults.ts +1 -0
- package/src/permissions/trust-store.ts +23 -1
- package/src/playbooks/playbook-compiler.ts +1 -1
- package/src/prompts/system-prompt.ts +18 -2
- package/src/providers/anthropic/client.ts +56 -126
- package/src/providers/types.ts +7 -1
- package/src/runtime/AGENTS.md +9 -0
- package/src/runtime/auth/route-policy.ts +6 -3
- package/src/runtime/channel-readiness-service.ts +48 -40
- package/src/runtime/guardian-reply-router.ts +24 -22
- package/src/runtime/http-server.ts +2 -2
- package/src/runtime/http-types.ts +2 -0
- package/src/runtime/invite-redemption-service.ts +72 -12
- package/src/runtime/invite-service.ts +43 -0
- package/src/runtime/middleware/twilio-validation.ts +1 -1
- package/src/runtime/pending-interactions.ts +2 -2
- package/src/runtime/routes/brain-graph-routes.ts +10 -90
- package/src/runtime/routes/btw-routes.ts +10 -5
- package/src/runtime/routes/conversation-routes.ts +56 -11
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +21 -12
- package/src/runtime/routes/integrations/slack/channel.ts +2 -2
- package/src/runtime/routes/integrations/telegram.ts +2 -2
- package/src/runtime/routes/integrations/twilio.ts +17 -17
- package/src/runtime/routes/invite-routes.ts +29 -4
- package/src/runtime/routes/memory-item-routes.test.ts +754 -0
- package/src/runtime/routes/memory-item-routes.ts +503 -0
- package/src/runtime/routes/secret-routes.ts +17 -0
- package/src/runtime/routes/session-management-routes.ts +3 -3
- package/src/runtime/routes/settings-routes.ts +3 -3
- package/src/runtime/routes/trust-rules-routes.ts +14 -0
- package/src/runtime/routes/workspace-routes.ts +9 -4
- package/src/runtime/routes/workspace-utils.ts +8 -2
- package/src/schedule/integration-status.ts +26 -19
- package/src/security/keychain-broker-client.ts +17 -4
- package/src/security/oauth2.ts +6 -7
- package/src/security/secure-keys.ts +44 -19
- package/src/security/token-manager.ts +46 -39
- package/src/services/vercel-deploy.ts +0 -24
- package/src/signals/confirm.ts +78 -0
- package/src/signals/mcp-reload.ts +18 -0
- package/src/skills/catalog-install.ts +74 -18
- package/src/skills/skillssh-registry.ts +503 -0
- package/src/tools/assets/search.ts +5 -1
- package/src/tools/computer-use/definitions.ts +0 -10
- package/src/tools/computer-use/registry.ts +1 -1
- package/src/tools/credentials/vault.ts +22 -7
- package/src/tools/memory/definitions.ts +4 -13
- package/src/tools/memory/handlers.test.ts +83 -103
- package/src/tools/memory/handlers.ts +50 -85
- package/src/tools/network/script-proxy/session-manager.ts +8 -8
- package/src/tools/schedule/create.ts +10 -3
- package/src/tools/schedule/update.ts +8 -1
- package/src/tools/skills/load.ts +25 -2
- package/src/watcher/provider-types.ts +1 -1
- package/src/watcher/providers/github.ts +1 -1
- package/src/watcher/providers/gmail.ts +3 -3
- package/src/watcher/providers/google-calendar.ts +3 -3
- package/src/watcher/providers/linear.ts +1 -1
- package/src/__tests__/clarification-resolver.test.ts +0 -193
- package/src/__tests__/conflict-intent-tokenization.test.ts +0 -160
- package/src/__tests__/conflict-policy.test.ts +0 -269
- package/src/__tests__/conflict-store.test.ts +0 -372
- package/src/__tests__/contradiction-checker.test.ts +0 -361
- package/src/__tests__/entity-extractor.test.ts +0 -211
- package/src/__tests__/entity-search.test.ts +0 -1117
- package/src/__tests__/profile-compiler.test.ts +0 -392
- package/src/__tests__/session-conflict-gate.test.ts +0 -1228
- package/src/__tests__/session-profile-injection.test.ts +0 -557
- package/src/config/bundled-skills/knowledge-graph/SKILL.md +0 -25
- package/src/config/bundled-skills/knowledge-graph/TOOLS.json +0 -66
- package/src/config/bundled-skills/knowledge-graph/tools/graph-query.ts +0 -211
- package/src/daemon/session-conflict-gate.ts +0 -167
- package/src/daemon/session-dynamic-profile.ts +0 -77
- package/src/memory/clarification-resolver.ts +0 -417
- package/src/memory/conflict-intent.ts +0 -205
- package/src/memory/conflict-policy.ts +0 -127
- package/src/memory/conflict-store.ts +0 -410
- package/src/memory/contradiction-checker.ts +0 -508
- package/src/memory/entity-extractor.ts +0 -535
- package/src/memory/format-recall.ts +0 -47
- package/src/memory/fts-reconciler.ts +0 -165
- package/src/memory/job-handlers/conflict.ts +0 -200
- package/src/memory/profile-compiler.ts +0 -195
- package/src/memory/recall-cache.ts +0 -117
- package/src/memory/search/entity.ts +0 -535
- package/src/memory/search/query-expansion.test.ts +0 -70
- package/src/memory/search/query-expansion.ts +0 -118
- package/src/runtime/routes/mcp-routes.ts +0 -20
|
@@ -4,10 +4,15 @@ import { seedProviders } from "./oauth-store.js";
|
|
|
4
4
|
* Protocol-level seed data for each well-known OAuth provider.
|
|
5
5
|
*
|
|
6
6
|
* These values are upserted into the `oauth_providers` SQLite table on
|
|
7
|
-
* every startup
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
7
|
+
* every startup. Only Vellum implementation fields (authUrl, tokenUrl,
|
|
8
|
+
* tokenEndpointAuthMethod, extraParams, callbackTransport, loopbackPort,
|
|
9
|
+
* pingUrl) are overwritten on subsequent startups — user-customizable
|
|
10
|
+
* fields (defaultScopes, scopePolicy, userinfoUrl, baseUrl) are only
|
|
11
|
+
* written on initial insert and preserved across restarts.
|
|
12
|
+
*
|
|
13
|
+
* Code-side behavioral fields (identityVerifier, injectionTemplates,
|
|
14
|
+
* setup, etc.) live in `provider-behaviors.ts` and are never persisted
|
|
15
|
+
* to the DB.
|
|
11
16
|
*/
|
|
12
17
|
const PROVIDER_SEED_DATA: Record<
|
|
13
18
|
string,
|
|
@@ -17,6 +22,7 @@ const PROVIDER_SEED_DATA: Record<
|
|
|
17
22
|
tokenUrl: string;
|
|
18
23
|
tokenEndpointAuthMethod?: string;
|
|
19
24
|
userinfoUrl?: string;
|
|
25
|
+
pingUrl?: string;
|
|
20
26
|
baseUrl?: string;
|
|
21
27
|
defaultScopes: string[];
|
|
22
28
|
scopePolicy: {
|
|
@@ -29,11 +35,12 @@ const PROVIDER_SEED_DATA: Record<
|
|
|
29
35
|
loopbackPort?: number;
|
|
30
36
|
}
|
|
31
37
|
> = {
|
|
32
|
-
"integration:
|
|
33
|
-
providerKey: "integration:
|
|
38
|
+
"integration:google": {
|
|
39
|
+
providerKey: "integration:google",
|
|
34
40
|
authUrl: "https://accounts.google.com/o/oauth2/v2/auth",
|
|
35
41
|
tokenUrl: "https://oauth2.googleapis.com/token",
|
|
36
42
|
userinfoUrl: "https://www.googleapis.com/oauth2/v2/userinfo",
|
|
43
|
+
pingUrl: "https://www.googleapis.com/oauth2/v2/userinfo",
|
|
37
44
|
baseUrl: "https://gmail.googleapis.com/gmail/v1/users/me",
|
|
38
45
|
defaultScopes: [
|
|
39
46
|
"https://www.googleapis.com/auth/gmail.readonly",
|
|
@@ -45,8 +52,11 @@ const PROVIDER_SEED_DATA: Record<
|
|
|
45
52
|
"https://www.googleapis.com/auth/contacts.readonly",
|
|
46
53
|
],
|
|
47
54
|
scopePolicy: {
|
|
48
|
-
allowAdditionalScopes:
|
|
49
|
-
allowedOptionalScopes: [
|
|
55
|
+
allowAdditionalScopes: true,
|
|
56
|
+
allowedOptionalScopes: [
|
|
57
|
+
"https://www.googleapis.com/auth/drive.readonly",
|
|
58
|
+
"https://www.googleapis.com/auth/drive.file",
|
|
59
|
+
],
|
|
50
60
|
forbiddenScopes: [],
|
|
51
61
|
},
|
|
52
62
|
extraParams: { access_type: "offline", prompt: "consent" },
|
|
@@ -57,6 +67,7 @@ const PROVIDER_SEED_DATA: Record<
|
|
|
57
67
|
providerKey: "integration:slack",
|
|
58
68
|
authUrl: "https://slack.com/oauth/v2/authorize",
|
|
59
69
|
tokenUrl: "https://slack.com/api/oauth.v2.access",
|
|
70
|
+
pingUrl: "https://slack.com/api/auth.test",
|
|
60
71
|
baseUrl: "https://slack.com/api",
|
|
61
72
|
defaultScopes: [
|
|
62
73
|
"channels:read",
|
|
@@ -90,6 +101,7 @@ const PROVIDER_SEED_DATA: Record<
|
|
|
90
101
|
providerKey: "integration:notion",
|
|
91
102
|
authUrl: "https://api.notion.com/v1/oauth/authorize",
|
|
92
103
|
tokenUrl: "https://api.notion.com/v1/oauth/token",
|
|
104
|
+
pingUrl: "https://api.notion.com/v1/users/me",
|
|
93
105
|
baseUrl: "https://api.notion.com",
|
|
94
106
|
defaultScopes: [],
|
|
95
107
|
scopePolicy: {
|
|
@@ -99,12 +111,14 @@ const PROVIDER_SEED_DATA: Record<
|
|
|
99
111
|
},
|
|
100
112
|
extraParams: { owner: "user" },
|
|
101
113
|
tokenEndpointAuthMethod: "client_secret_basic",
|
|
114
|
+
callbackTransport: "gateway",
|
|
102
115
|
},
|
|
103
116
|
|
|
104
117
|
"integration:twitter": {
|
|
105
118
|
providerKey: "integration:twitter",
|
|
106
119
|
authUrl: "https://twitter.com/i/oauth2/authorize",
|
|
107
120
|
tokenUrl: "https://api.x.com/2/oauth2/token",
|
|
121
|
+
pingUrl: "https://api.x.com/2/users/me",
|
|
108
122
|
baseUrl: "https://api.x.com",
|
|
109
123
|
defaultScopes: [
|
|
110
124
|
"tweet.read",
|
|
@@ -121,6 +135,197 @@ const PROVIDER_SEED_DATA: Record<
|
|
|
121
135
|
callbackTransport: "gateway",
|
|
122
136
|
},
|
|
123
137
|
|
|
138
|
+
"integration:github": {
|
|
139
|
+
providerKey: "integration:github",
|
|
140
|
+
authUrl: "https://github.com/login/oauth/authorize",
|
|
141
|
+
tokenUrl: "https://github.com/login/oauth/access_token",
|
|
142
|
+
pingUrl: "https://api.github.com/user",
|
|
143
|
+
baseUrl: "https://api.github.com",
|
|
144
|
+
defaultScopes: ["repo", "read:user", "notifications"],
|
|
145
|
+
scopePolicy: {
|
|
146
|
+
allowAdditionalScopes: true,
|
|
147
|
+
allowedOptionalScopes: [
|
|
148
|
+
"read:org",
|
|
149
|
+
"write:discussion",
|
|
150
|
+
"gist",
|
|
151
|
+
"project",
|
|
152
|
+
],
|
|
153
|
+
forbiddenScopes: ["delete_repo", "admin:org"],
|
|
154
|
+
},
|
|
155
|
+
callbackTransport: "loopback",
|
|
156
|
+
},
|
|
157
|
+
|
|
158
|
+
"integration:linear": {
|
|
159
|
+
providerKey: "integration:linear",
|
|
160
|
+
authUrl: "https://linear.app/oauth/authorize",
|
|
161
|
+
tokenUrl: "https://api.linear.app/oauth/token",
|
|
162
|
+
pingUrl: "https://api.linear.app/graphql",
|
|
163
|
+
baseUrl: "https://api.linear.app",
|
|
164
|
+
defaultScopes: ["read", "write", "issues:create"],
|
|
165
|
+
scopePolicy: {
|
|
166
|
+
allowAdditionalScopes: false,
|
|
167
|
+
allowedOptionalScopes: [],
|
|
168
|
+
forbiddenScopes: [],
|
|
169
|
+
},
|
|
170
|
+
extraParams: { prompt: "consent" },
|
|
171
|
+
callbackTransport: "loopback",
|
|
172
|
+
},
|
|
173
|
+
|
|
174
|
+
"integration:spotify": {
|
|
175
|
+
providerKey: "integration:spotify",
|
|
176
|
+
authUrl: "https://accounts.spotify.com/authorize",
|
|
177
|
+
tokenUrl: "https://accounts.spotify.com/api/token",
|
|
178
|
+
pingUrl: "https://api.spotify.com/v1/me",
|
|
179
|
+
baseUrl: "https://api.spotify.com/v1",
|
|
180
|
+
defaultScopes: [
|
|
181
|
+
"user-read-playback-state",
|
|
182
|
+
"user-modify-playback-state",
|
|
183
|
+
"user-read-currently-playing",
|
|
184
|
+
"user-read-recently-played",
|
|
185
|
+
"playlist-read-private",
|
|
186
|
+
"playlist-modify-public",
|
|
187
|
+
"playlist-modify-private",
|
|
188
|
+
"user-library-read",
|
|
189
|
+
"user-library-modify",
|
|
190
|
+
],
|
|
191
|
+
scopePolicy: {
|
|
192
|
+
allowAdditionalScopes: false,
|
|
193
|
+
allowedOptionalScopes: [],
|
|
194
|
+
forbiddenScopes: [],
|
|
195
|
+
},
|
|
196
|
+
callbackTransport: "loopback",
|
|
197
|
+
},
|
|
198
|
+
|
|
199
|
+
"integration:todoist": {
|
|
200
|
+
providerKey: "integration:todoist",
|
|
201
|
+
authUrl: "https://todoist.com/oauth/authorize",
|
|
202
|
+
tokenUrl: "https://todoist.com/oauth/access_token",
|
|
203
|
+
pingUrl: "https://api.todoist.com/rest/v2/projects",
|
|
204
|
+
baseUrl: "https://api.todoist.com/rest/v2",
|
|
205
|
+
defaultScopes: ["data:read_write"],
|
|
206
|
+
scopePolicy: {
|
|
207
|
+
allowAdditionalScopes: false,
|
|
208
|
+
allowedOptionalScopes: [],
|
|
209
|
+
forbiddenScopes: ["data:delete"],
|
|
210
|
+
},
|
|
211
|
+
callbackTransport: "loopback",
|
|
212
|
+
},
|
|
213
|
+
|
|
214
|
+
"integration:discord": {
|
|
215
|
+
providerKey: "integration:discord",
|
|
216
|
+
authUrl: "https://discord.com/oauth2/authorize",
|
|
217
|
+
tokenUrl: "https://discord.com/api/v10/oauth2/token",
|
|
218
|
+
pingUrl: "https://discord.com/api/v10/users/@me",
|
|
219
|
+
baseUrl: "https://discord.com/api/v10",
|
|
220
|
+
defaultScopes: [
|
|
221
|
+
"identify",
|
|
222
|
+
"guilds",
|
|
223
|
+
"guilds.members.read",
|
|
224
|
+
"messages.read",
|
|
225
|
+
],
|
|
226
|
+
scopePolicy: {
|
|
227
|
+
allowAdditionalScopes: false,
|
|
228
|
+
allowedOptionalScopes: ["bot"],
|
|
229
|
+
forbiddenScopes: [],
|
|
230
|
+
},
|
|
231
|
+
callbackTransport: "loopback",
|
|
232
|
+
},
|
|
233
|
+
|
|
234
|
+
"integration:dropbox": {
|
|
235
|
+
providerKey: "integration:dropbox",
|
|
236
|
+
authUrl: "https://www.dropbox.com/oauth2/authorize",
|
|
237
|
+
tokenUrl: "https://api.dropboxapi.com/oauth2/token",
|
|
238
|
+
pingUrl: "https://api.dropboxapi.com/2/users/get_current_account",
|
|
239
|
+
baseUrl: "https://api.dropboxapi.com/2",
|
|
240
|
+
defaultScopes: [
|
|
241
|
+
"files.metadata.read",
|
|
242
|
+
"files.content.read",
|
|
243
|
+
"files.content.write",
|
|
244
|
+
"sharing.read",
|
|
245
|
+
],
|
|
246
|
+
scopePolicy: {
|
|
247
|
+
allowAdditionalScopes: false,
|
|
248
|
+
allowedOptionalScopes: [],
|
|
249
|
+
forbiddenScopes: [],
|
|
250
|
+
},
|
|
251
|
+
extraParams: { token_access_type: "offline" },
|
|
252
|
+
callbackTransport: "loopback",
|
|
253
|
+
},
|
|
254
|
+
|
|
255
|
+
"integration:asana": {
|
|
256
|
+
providerKey: "integration:asana",
|
|
257
|
+
authUrl: "https://app.asana.com/-/oauth_authorize",
|
|
258
|
+
tokenUrl: "https://app.asana.com/-/oauth_token",
|
|
259
|
+
pingUrl: "https://app.asana.com/api/1.0/users/me",
|
|
260
|
+
baseUrl: "https://app.asana.com/api/1.0",
|
|
261
|
+
defaultScopes: ["default"],
|
|
262
|
+
scopePolicy: {
|
|
263
|
+
allowAdditionalScopes: false,
|
|
264
|
+
allowedOptionalScopes: [],
|
|
265
|
+
forbiddenScopes: [],
|
|
266
|
+
},
|
|
267
|
+
callbackTransport: "loopback",
|
|
268
|
+
},
|
|
269
|
+
|
|
270
|
+
"integration:airtable": {
|
|
271
|
+
providerKey: "integration:airtable",
|
|
272
|
+
authUrl: "https://airtable.com/oauth2/v1/authorize",
|
|
273
|
+
tokenUrl: "https://airtable.com/oauth2/v1/token",
|
|
274
|
+
pingUrl: "https://api.airtable.com/v0/meta/whoami",
|
|
275
|
+
baseUrl: "https://api.airtable.com/v0",
|
|
276
|
+
defaultScopes: [
|
|
277
|
+
"data.records:read",
|
|
278
|
+
"data.records:write",
|
|
279
|
+
"schema.bases:read",
|
|
280
|
+
],
|
|
281
|
+
scopePolicy: {
|
|
282
|
+
allowAdditionalScopes: false,
|
|
283
|
+
allowedOptionalScopes: [],
|
|
284
|
+
forbiddenScopes: [],
|
|
285
|
+
},
|
|
286
|
+
tokenEndpointAuthMethod: "client_secret_post",
|
|
287
|
+
callbackTransport: "loopback",
|
|
288
|
+
},
|
|
289
|
+
|
|
290
|
+
"integration:hubspot": {
|
|
291
|
+
providerKey: "integration:hubspot",
|
|
292
|
+
authUrl: "https://app.hubspot.com/oauth/authorize",
|
|
293
|
+
tokenUrl: "https://api.hubapi.com/oauth/v1/token",
|
|
294
|
+
pingUrl: "https://api.hubapi.com/crm/v3/objects/contacts?limit=1",
|
|
295
|
+
baseUrl: "https://api.hubapi.com",
|
|
296
|
+
defaultScopes: [
|
|
297
|
+
"crm.objects.contacts.read",
|
|
298
|
+
"crm.objects.contacts.write",
|
|
299
|
+
"crm.objects.deals.read",
|
|
300
|
+
"crm.objects.deals.write",
|
|
301
|
+
"crm.objects.companies.read",
|
|
302
|
+
],
|
|
303
|
+
scopePolicy: {
|
|
304
|
+
allowAdditionalScopes: true,
|
|
305
|
+
allowedOptionalScopes: [
|
|
306
|
+
"crm.objects.companies.write",
|
|
307
|
+
"crm.objects.owners.read",
|
|
308
|
+
],
|
|
309
|
+
forbiddenScopes: [],
|
|
310
|
+
},
|
|
311
|
+
callbackTransport: "loopback",
|
|
312
|
+
},
|
|
313
|
+
|
|
314
|
+
"integration:figma": {
|
|
315
|
+
providerKey: "integration:figma",
|
|
316
|
+
authUrl: "https://www.figma.com/oauth",
|
|
317
|
+
tokenUrl: "https://api.figma.com/v1/oauth/token",
|
|
318
|
+
pingUrl: "https://api.figma.com/v1/me",
|
|
319
|
+
baseUrl: "https://api.figma.com/v1",
|
|
320
|
+
defaultScopes: ["files:read", "file_comments:write"],
|
|
321
|
+
scopePolicy: {
|
|
322
|
+
allowAdditionalScopes: false,
|
|
323
|
+
allowedOptionalScopes: [],
|
|
324
|
+
forbiddenScopes: [],
|
|
325
|
+
},
|
|
326
|
+
callbackTransport: "loopback",
|
|
327
|
+
},
|
|
328
|
+
|
|
124
329
|
// Manual-token providers: these don't use OAuth2 flows but need provider
|
|
125
330
|
// rows so that oauth_app and oauth_connection FK chains can reference them.
|
|
126
331
|
// The authUrl/tokenUrl values are placeholders — never used at runtime.
|
|
@@ -128,6 +333,7 @@ const PROVIDER_SEED_DATA: Record<
|
|
|
128
333
|
providerKey: "slack_channel",
|
|
129
334
|
authUrl: "urn:manual-token",
|
|
130
335
|
tokenUrl: "urn:manual-token",
|
|
336
|
+
pingUrl: "https://slack.com/api/auth.test",
|
|
131
337
|
baseUrl: "https://slack.com/api",
|
|
132
338
|
defaultScopes: [],
|
|
133
339
|
scopePolicy: {
|
|
@@ -10,19 +10,17 @@
|
|
|
10
10
|
* `oauth_connection/{id}/...`).
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
import type {
|
|
14
|
-
OAuth2FlowResult,
|
|
15
|
-
TokenEndpointAuthMethod,
|
|
16
|
-
} from "../security/oauth2.js";
|
|
13
|
+
import type { OAuth2FlowResult } from "../security/oauth2.js";
|
|
17
14
|
import {
|
|
18
15
|
deleteSecureKeyAsync,
|
|
19
16
|
setSecureKeyAsync,
|
|
20
17
|
} from "../security/secure-keys.js";
|
|
21
|
-
import type { CredentialInjectionTemplate } from "../tools/credentials/policy-types.js";
|
|
22
18
|
import { runPostConnectHook } from "../tools/credentials/post-connect-hooks.js";
|
|
23
19
|
import {
|
|
24
20
|
createConnection,
|
|
21
|
+
getApp,
|
|
25
22
|
getConnectionByProvider,
|
|
23
|
+
getConnectionByProviderAndAccount,
|
|
26
24
|
updateConnection,
|
|
27
25
|
upsertApp,
|
|
28
26
|
} from "./oauth-store.js";
|
|
@@ -38,11 +36,7 @@ export interface StoreOAuth2TokensParams {
|
|
|
38
36
|
rawTokenResponse: Record<string, unknown>;
|
|
39
37
|
clientId: string;
|
|
40
38
|
clientSecret?: string;
|
|
41
|
-
tokenUrl: string;
|
|
42
|
-
tokenEndpointAuthMethod?: TokenEndpointAuthMethod;
|
|
43
39
|
userinfoUrl?: string;
|
|
44
|
-
allowedTools?: string[];
|
|
45
|
-
wellKnownInjectionTemplates?: CredentialInjectionTemplate[];
|
|
46
40
|
/** Fallback account info from an identity verifier (e.g. @username, email). */
|
|
47
41
|
identityAccountInfo?: string;
|
|
48
42
|
/** Pre-resolved oauth_app ID — skips the upsertApp() call if provided. */
|
|
@@ -101,13 +95,20 @@ export async function storeOAuth2Tokens(
|
|
|
101
95
|
|
|
102
96
|
// 1. Upsert the oauth_app row (or use the pre-resolved ID).
|
|
103
97
|
const app = params.oauthAppId
|
|
104
|
-
?
|
|
105
|
-
|
|
98
|
+
? (getApp(params.oauthAppId) ?? {
|
|
99
|
+
id: params.oauthAppId,
|
|
100
|
+
clientSecretCredentialPath: `oauth_app/${params.oauthAppId}/client_secret`,
|
|
101
|
+
})
|
|
102
|
+
: await upsertApp(
|
|
103
|
+
service,
|
|
104
|
+
clientId,
|
|
105
|
+
clientSecret ? { clientSecretValue: clientSecret } : undefined,
|
|
106
|
+
);
|
|
106
107
|
|
|
107
108
|
// When oauthAppId is pre-resolved, still persist clientSecret if provided.
|
|
108
109
|
if (params.oauthAppId && clientSecret) {
|
|
109
110
|
const stored = await setSecureKeyAsync(
|
|
110
|
-
|
|
111
|
+
app.clientSecretCredentialPath,
|
|
111
112
|
clientSecret,
|
|
112
113
|
);
|
|
113
114
|
if (!stored) {
|
|
@@ -115,14 +116,28 @@ export async function storeOAuth2Tokens(
|
|
|
115
116
|
}
|
|
116
117
|
}
|
|
117
118
|
|
|
118
|
-
// 2. Upsert oauth_connection — reuse existing active connection for
|
|
119
|
-
//
|
|
120
|
-
|
|
119
|
+
// 2. Upsert oauth_connection — reuse existing active connection for the
|
|
120
|
+
// same account, or create a new one for a different account.
|
|
121
|
+
// First try to match by account info (email); fall back to provider-only
|
|
122
|
+
// lookup so that re-auth without userinfo still updates the right row.
|
|
123
|
+
const existingConn = resolvedAccountInfo
|
|
124
|
+
? getConnectionByProviderAndAccount(service, resolvedAccountInfo)
|
|
125
|
+
: getConnectionByProvider(service);
|
|
121
126
|
let connId: string;
|
|
122
127
|
|
|
123
128
|
const hasRefreshToken = !!tokens.refreshToken;
|
|
124
129
|
|
|
125
|
-
if (
|
|
130
|
+
// Only reuse the existing connection if it's the same account (or we can't
|
|
131
|
+
// tell). When the user connects a different account for the same service,
|
|
132
|
+
// create a separate connection so we don't overwrite the first account's
|
|
133
|
+
// tokens.
|
|
134
|
+
const isNewAccount =
|
|
135
|
+
existingConn &&
|
|
136
|
+
resolvedAccountInfo !== undefined &&
|
|
137
|
+
existingConn.accountInfo !== undefined &&
|
|
138
|
+
resolvedAccountInfo !== existingConn.accountInfo;
|
|
139
|
+
|
|
140
|
+
if (existingConn && !isNewAccount) {
|
|
126
141
|
connId = existingConn.id;
|
|
127
142
|
updateConnection(connId, {
|
|
128
143
|
oauthAppId: app.id,
|
|
@@ -283,12 +283,28 @@ function loadFromDisk(): TrustRule[] {
|
|
|
283
283
|
// Restore persisted starter bundle flag
|
|
284
284
|
cachedStarterBundleAccepted = data.starterBundleAccepted === true;
|
|
285
285
|
|
|
286
|
+
// Defense-in-depth: strip any __internal: prefixed rules that may have
|
|
287
|
+
// been hand-edited into trust.json.
|
|
288
|
+
const sanitizedRules = rawRules.filter((r) => {
|
|
289
|
+
if (typeof r.tool === "string" && r.tool.startsWith("__internal:")) {
|
|
290
|
+
log.warn(
|
|
291
|
+
{ ruleId: r.id, tool: r.tool },
|
|
292
|
+
"Stripping __internal: rule from trust file on load",
|
|
293
|
+
);
|
|
294
|
+
return false;
|
|
295
|
+
}
|
|
296
|
+
return true;
|
|
297
|
+
});
|
|
298
|
+
|
|
286
299
|
if (
|
|
287
300
|
data.version === TRUST_FILE_VERSION ||
|
|
288
301
|
data.version === 1 ||
|
|
289
302
|
data.version === 2
|
|
290
303
|
) {
|
|
291
|
-
rules =
|
|
304
|
+
rules = sanitizedRules;
|
|
305
|
+
if (sanitizedRules.length < rawRules.length) {
|
|
306
|
+
needsSave = true;
|
|
307
|
+
}
|
|
292
308
|
if (data.version !== TRUST_FILE_VERSION) {
|
|
293
309
|
needsSave = true;
|
|
294
310
|
log.info(
|
|
@@ -395,6 +411,8 @@ export function addRule(
|
|
|
395
411
|
executionTarget?: string;
|
|
396
412
|
},
|
|
397
413
|
): TrustRule {
|
|
414
|
+
if (tool.startsWith("__internal:"))
|
|
415
|
+
throw new Error(`Cannot create internal pseudo-rule via addRule: ${tool}`);
|
|
398
416
|
// Re-read from disk to avoid lost updates if another call modified rules
|
|
399
417
|
// between our last read and now (e.g. two rapid trust rule additions).
|
|
400
418
|
cachedRules = null;
|
|
@@ -437,6 +455,10 @@ export function updateRule(
|
|
|
437
455
|
const defaultIds = new Set(getDefaultRuleTemplates().map((t) => t.id));
|
|
438
456
|
if (defaultIds.has(id))
|
|
439
457
|
throw new Error(`Cannot modify default trust rule: ${id}`);
|
|
458
|
+
if (updates.tool?.startsWith("__internal:"))
|
|
459
|
+
throw new Error(
|
|
460
|
+
`Cannot update tool to internal pseudo-rule: ${updates.tool}`,
|
|
461
|
+
);
|
|
440
462
|
|
|
441
463
|
// Re-read from disk to avoid lost updates from concurrent modifications.
|
|
442
464
|
cachedRules = null;
|
|
@@ -690,7 +690,7 @@ function buildMemoryRecallSection(): string {
|
|
|
690
690
|
"- The auto-injected memory context doesn't contain what you need",
|
|
691
691
|
"- The user references something from a previous session",
|
|
692
692
|
"",
|
|
693
|
-
"The tool
|
|
693
|
+
"The tool uses hybrid search (dense and sparse vectors) supplemented by recency. Be specific in your query for best results.",
|
|
694
694
|
].join("\n");
|
|
695
695
|
}
|
|
696
696
|
|
|
@@ -845,7 +845,7 @@ export function buildCliReferenceSection(): string {
|
|
|
845
845
|
return [
|
|
846
846
|
"## Assistant CLI",
|
|
847
847
|
"",
|
|
848
|
-
"The `assistant` CLI is
|
|
848
|
+
"The `assistant` CLI is available in the sandbox. Always use the `bash` tool (never `host_bash`) when running `assistant` commands.",
|
|
849
849
|
"For account and authentication work, prefer real `assistant` CLI workflows over any legacy account-record abstraction.",
|
|
850
850
|
"- Use `assistant credentials ...` for stored secrets and credential metadata.",
|
|
851
851
|
"- Use `assistant oauth connections token <provider-key>` for connected integration tokens.",
|
|
@@ -960,6 +960,22 @@ function buildDynamicSkillWorkflowSection(
|
|
|
960
960
|
);
|
|
961
961
|
}
|
|
962
962
|
|
|
963
|
+
lines.push(
|
|
964
|
+
"",
|
|
965
|
+
"### Community Skills Discovery",
|
|
966
|
+
"",
|
|
967
|
+
"When no built-in skill satisfies a request, search the community skills.sh registry:",
|
|
968
|
+
"1. Run `assistant skills search <query>` to find community skills. Results include install counts and security audit badges (ATH, Socket, Snyk).",
|
|
969
|
+
"2. Present the search results to the user, highlighting the security audit status. ATH is Gen Agent Trust Hub. Audits show PASS (safe/low risk), WARN (medium risk), or FAIL (high/critical risk) for each provider.",
|
|
970
|
+
"3. Check the skill's **source owner** to determine the trust level:",
|
|
971
|
+
" - **Vellum-owned** (source starts with `vellum-ai/`): These are first-party skills published by the Vellum team. Install them directly without prompting — they are vetted and trusted.",
|
|
972
|
+
" - **Third-party** (any other owner): Ask the user for permission before installing. Say something like: \"I found a community skill that could help with this, but it's published by a third party — we haven't vetted it. Want to install it anyway?\" Share the skill name, source, audit results, and install count.",
|
|
973
|
+
"4. Install with `assistant skills add <owner>/<repo>@<skill-name>` (e.g., `assistant skills add vercel-labs/skills@find-skills`).",
|
|
974
|
+
"5. After installation, load the skill with `skill_load` as usual.",
|
|
975
|
+
"",
|
|
976
|
+
"**Never install third-party community skills without explicit user confirmation.** Vellum-owned skills (`vellum-ai/*`) can be installed automatically.",
|
|
977
|
+
);
|
|
978
|
+
|
|
963
979
|
return lines.join("\n");
|
|
964
980
|
}
|
|
965
981
|
|