@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
|
@@ -63,20 +63,6 @@ function isToolUseBlock(block: unknown): block is Anthropic.ToolUseBlockParam {
|
|
|
63
63
|
);
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
-
/** Type-guard for server_tool_use blocks (e.g. native web search). */
|
|
67
|
-
function isServerToolUseBlock(block: unknown): block is {
|
|
68
|
-
type: "server_tool_use";
|
|
69
|
-
id: string;
|
|
70
|
-
name: string;
|
|
71
|
-
input: unknown;
|
|
72
|
-
} {
|
|
73
|
-
return (
|
|
74
|
-
typeof block === "object" &&
|
|
75
|
-
block != null &&
|
|
76
|
-
(block as { type: string }).type === "server_tool_use"
|
|
77
|
-
);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
66
|
/** Type-guard for tool_result blocks in Anthropic-formatted content. */
|
|
81
67
|
function isToolResultBlock(
|
|
82
68
|
block: unknown,
|
|
@@ -88,19 +74,6 @@ function isToolResultBlock(
|
|
|
88
74
|
);
|
|
89
75
|
}
|
|
90
76
|
|
|
91
|
-
/** Type-guard for web_search_tool_result blocks. */
|
|
92
|
-
function isWebSearchToolResultBlock(block: unknown): block is {
|
|
93
|
-
type: "web_search_tool_result";
|
|
94
|
-
tool_use_id: string;
|
|
95
|
-
content: unknown;
|
|
96
|
-
} {
|
|
97
|
-
return (
|
|
98
|
-
typeof block === "object" &&
|
|
99
|
-
block != null &&
|
|
100
|
-
(block as { type: string }).type === "web_search_tool_result"
|
|
101
|
-
);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
77
|
/**
|
|
105
78
|
* Build a short diagnostic summary of a message array for error logging.
|
|
106
79
|
* Shows role + block types (with tool_use/tool_result IDs) for each message.
|
|
@@ -134,79 +107,55 @@ function buildSyntheticToolResult(
|
|
|
134
107
|
};
|
|
135
108
|
}
|
|
136
109
|
|
|
137
|
-
function buildSyntheticWebSearchToolResult(
|
|
138
|
-
toolUseId: string,
|
|
139
|
-
): Anthropic.ContentBlockParam {
|
|
140
|
-
return {
|
|
141
|
-
type: "web_search_tool_result",
|
|
142
|
-
tool_use_id: toolUseId,
|
|
143
|
-
content: {
|
|
144
|
-
type: "web_search_tool_result_error",
|
|
145
|
-
error_code: "unavailable",
|
|
146
|
-
},
|
|
147
|
-
} as unknown as Anthropic.ContentBlockParam;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
/** Build the appropriate synthetic result block based on whether the ID is for a server tool or regular tool. */
|
|
151
|
-
function buildSyntheticResult(
|
|
152
|
-
toolUseId: string,
|
|
153
|
-
serverToolIds: ReadonlySet<string>,
|
|
154
|
-
): Anthropic.ContentBlockParam {
|
|
155
|
-
if (serverToolIds.has(toolUseId)) {
|
|
156
|
-
return buildSyntheticWebSearchToolResult(toolUseId);
|
|
157
|
-
}
|
|
158
|
-
return buildSyntheticToolResult(toolUseId);
|
|
159
|
-
}
|
|
160
110
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
111
|
+
/**
|
|
112
|
+
* Collect ordered IDs of client-side tool_use blocks only.
|
|
113
|
+
* Server-side tools (server_tool_use / web_search_tool_result) are self-paired
|
|
114
|
+
* within the assistant message and do not need cross-message pairing.
|
|
115
|
+
*/
|
|
116
|
+
function getOrderedToolUseIds(
|
|
117
|
+
content: Anthropic.ContentBlockParam[],
|
|
118
|
+
): string[] {
|
|
165
119
|
const ids: string[] = [];
|
|
166
120
|
const seen = new Set<string>();
|
|
167
|
-
const serverToolIds = new Set<string>();
|
|
168
121
|
for (const block of content) {
|
|
169
122
|
if (isToolUseBlock(block)) {
|
|
170
123
|
if (!seen.has(block.id)) {
|
|
171
124
|
seen.add(block.id);
|
|
172
125
|
ids.push(block.id);
|
|
173
126
|
}
|
|
174
|
-
} else if (isServerToolUseBlock(block)) {
|
|
175
|
-
if (!seen.has(block.id)) {
|
|
176
|
-
seen.add(block.id);
|
|
177
|
-
ids.push(block.id);
|
|
178
|
-
serverToolIds.add(block.id);
|
|
179
|
-
}
|
|
180
127
|
}
|
|
181
128
|
}
|
|
182
|
-
return
|
|
129
|
+
return ids;
|
|
183
130
|
}
|
|
184
131
|
|
|
185
132
|
function hasOrderedToolResultPrefix(
|
|
186
133
|
content: Anthropic.ContentBlockParam[],
|
|
187
134
|
orderedToolUseIds: string[],
|
|
188
|
-
serverToolIds: ReadonlySet<string>,
|
|
189
135
|
): boolean {
|
|
190
136
|
if (content.length < orderedToolUseIds.length) return false;
|
|
191
137
|
for (let idx = 0; idx < orderedToolUseIds.length; idx++) {
|
|
192
138
|
const block = content[idx];
|
|
193
139
|
const expectedId = orderedToolUseIds[idx];
|
|
194
|
-
if (
|
|
195
|
-
|
|
196
|
-
if (block.tool_use_id !== expectedId) return false;
|
|
197
|
-
} else {
|
|
198
|
-
if (!isToolResultBlock(block)) return false;
|
|
199
|
-
if (block.tool_use_id !== expectedId) return false;
|
|
200
|
-
}
|
|
140
|
+
if (!isToolResultBlock(block)) return false;
|
|
141
|
+
if (block.tool_use_id !== expectedId) return false;
|
|
201
142
|
}
|
|
202
143
|
return true;
|
|
203
144
|
}
|
|
204
145
|
|
|
146
|
+
/**
|
|
147
|
+
* Split an assistant message into:
|
|
148
|
+
* - pairedContent: everything up to and including client-side tool_use blocks
|
|
149
|
+
* - carryoverContent: trailing non-tool blocks after the last tool_use
|
|
150
|
+
*
|
|
151
|
+
* Server-side tools (server_tool_use / web_search_tool_result) are treated as
|
|
152
|
+
* regular content — they are self-paired within the assistant message and must
|
|
153
|
+
* not be separated by the cross-message pairing logic.
|
|
154
|
+
*/
|
|
205
155
|
function splitAssistantForToolPairing(content: Anthropic.ContentBlockParam[]): {
|
|
206
156
|
pairedContent: Anthropic.ContentBlockParam[];
|
|
207
157
|
carryoverContent: Anthropic.ContentBlockParam[];
|
|
208
158
|
toolUseIds: string[];
|
|
209
|
-
serverToolIds: Set<string>;
|
|
210
159
|
} {
|
|
211
160
|
const leading: Anthropic.ContentBlockParam[] = [];
|
|
212
161
|
const toolUseBlocks: Anthropic.ContentBlockParam[] = [];
|
|
@@ -214,7 +163,7 @@ function splitAssistantForToolPairing(content: Anthropic.ContentBlockParam[]): {
|
|
|
214
163
|
let seenToolUse = false;
|
|
215
164
|
|
|
216
165
|
for (const block of content) {
|
|
217
|
-
if (isToolUseBlock(block)
|
|
166
|
+
if (isToolUseBlock(block)) {
|
|
218
167
|
seenToolUse = true;
|
|
219
168
|
toolUseBlocks.push(block);
|
|
220
169
|
continue;
|
|
@@ -231,7 +180,6 @@ function splitAssistantForToolPairing(content: Anthropic.ContentBlockParam[]): {
|
|
|
231
180
|
pairedContent: content,
|
|
232
181
|
carryoverContent: [],
|
|
233
182
|
toolUseIds: [],
|
|
234
|
-
serverToolIds: new Set(),
|
|
235
183
|
};
|
|
236
184
|
}
|
|
237
185
|
|
|
@@ -239,19 +187,16 @@ function splitAssistantForToolPairing(content: Anthropic.ContentBlockParam[]): {
|
|
|
239
187
|
...leading,
|
|
240
188
|
...toolUseBlocks,
|
|
241
189
|
];
|
|
242
|
-
const { ids, serverToolIds } = getOrderedToolUseIds(pairedContent);
|
|
243
190
|
return {
|
|
244
191
|
pairedContent,
|
|
245
192
|
carryoverContent: carryover,
|
|
246
|
-
toolUseIds:
|
|
247
|
-
serverToolIds,
|
|
193
|
+
toolUseIds: getOrderedToolUseIds(pairedContent),
|
|
248
194
|
};
|
|
249
195
|
}
|
|
250
196
|
|
|
251
197
|
function normalizeFollowingUserContent(
|
|
252
198
|
nextContent: Anthropic.ContentBlockParam[],
|
|
253
199
|
orderedToolUseIds: string[],
|
|
254
|
-
serverToolIds: ReadonlySet<string>,
|
|
255
200
|
): {
|
|
256
201
|
toolResultPrefix: Anthropic.ContentBlockParam[];
|
|
257
202
|
remainingContent: Anthropic.ContentBlockParam[];
|
|
@@ -266,41 +211,24 @@ function normalizeFollowingUserContent(
|
|
|
266
211
|
if (
|
|
267
212
|
isToolResultBlock(block) &&
|
|
268
213
|
pendingIds.has(block.tool_use_id) &&
|
|
269
|
-
!matchedById.has(block.tool_use_id)
|
|
270
|
-
!serverToolIds.has(block.tool_use_id)
|
|
214
|
+
!matchedById.has(block.tool_use_id)
|
|
271
215
|
) {
|
|
272
216
|
matchedById.set(block.tool_use_id, block);
|
|
273
217
|
continue;
|
|
274
218
|
}
|
|
275
|
-
if (
|
|
276
|
-
isWebSearchToolResultBlock(block) &&
|
|
277
|
-
pendingIds.has(block.tool_use_id) &&
|
|
278
|
-
!matchedById.has(block.tool_use_id) &&
|
|
279
|
-
serverToolIds.has(block.tool_use_id)
|
|
280
|
-
) {
|
|
281
|
-
matchedById.set(
|
|
282
|
-
block.tool_use_id,
|
|
283
|
-
block as unknown as Anthropic.ContentBlockParam,
|
|
284
|
-
);
|
|
285
|
-
continue;
|
|
286
|
-
}
|
|
287
219
|
remaining.push(block);
|
|
288
220
|
}
|
|
289
221
|
|
|
290
222
|
const missingIds = orderedToolUseIds.filter((id) => !matchedById.has(id));
|
|
291
223
|
const orderedResults = orderedToolUseIds.map(
|
|
292
|
-
(id) => matchedById.get(id) ??
|
|
224
|
+
(id) => matchedById.get(id) ?? buildSyntheticToolResult(id),
|
|
293
225
|
);
|
|
294
226
|
|
|
295
227
|
return {
|
|
296
228
|
toolResultPrefix: orderedResults,
|
|
297
229
|
remainingContent: remaining,
|
|
298
230
|
missingIds,
|
|
299
|
-
hadOrderedPrefix: hasOrderedToolResultPrefix(
|
|
300
|
-
nextContent,
|
|
301
|
-
orderedToolUseIds,
|
|
302
|
-
serverToolIds,
|
|
303
|
-
),
|
|
231
|
+
hadOrderedPrefix: hasOrderedToolResultPrefix(nextContent, orderedToolUseIds),
|
|
304
232
|
};
|
|
305
233
|
}
|
|
306
234
|
|
|
@@ -328,7 +256,7 @@ function ensureToolPairing(
|
|
|
328
256
|
}
|
|
329
257
|
|
|
330
258
|
const content = Array.isArray(msg.content) ? msg.content : [];
|
|
331
|
-
const { pairedContent, carryoverContent, toolUseIds
|
|
259
|
+
const { pairedContent, carryoverContent, toolUseIds } =
|
|
332
260
|
splitAssistantForToolPairing(content);
|
|
333
261
|
|
|
334
262
|
if (toolUseIds.length === 0) {
|
|
@@ -337,7 +265,7 @@ function ensureToolPairing(
|
|
|
337
265
|
continue;
|
|
338
266
|
}
|
|
339
267
|
|
|
340
|
-
// Assistant message — push the paired portion (pre-tool text + tool_use
|
|
268
|
+
// Assistant message — push the paired portion (pre-tool text + tool_use blocks)
|
|
341
269
|
result.push({
|
|
342
270
|
role: "assistant" as const,
|
|
343
271
|
content: pairedContent,
|
|
@@ -358,11 +286,7 @@ function ensureToolPairing(
|
|
|
358
286
|
const next = messages[i + 1];
|
|
359
287
|
if (next && next.role === "user") {
|
|
360
288
|
const nextContent = Array.isArray(next.content) ? next.content : [];
|
|
361
|
-
const normalized = normalizeFollowingUserContent(
|
|
362
|
-
nextContent,
|
|
363
|
-
toolUseIds,
|
|
364
|
-
serverToolIds,
|
|
365
|
-
);
|
|
289
|
+
const normalized = normalizeFollowingUserContent(nextContent, toolUseIds);
|
|
366
290
|
if (normalized.missingIds.length > 0) {
|
|
367
291
|
log.warn(
|
|
368
292
|
{
|
|
@@ -427,9 +351,7 @@ function ensureToolPairing(
|
|
|
427
351
|
);
|
|
428
352
|
result.push({
|
|
429
353
|
role: "user" as const,
|
|
430
|
-
content: toolUseIds.map((id) =>
|
|
431
|
-
buildSyntheticResult(id, serverToolIds),
|
|
432
|
-
),
|
|
354
|
+
content: toolUseIds.map((id) => buildSyntheticToolResult(id)),
|
|
433
355
|
});
|
|
434
356
|
|
|
435
357
|
// If the assistant contained collapsed post-tool text, preserve it as a
|
|
@@ -445,13 +367,14 @@ function ensureToolPairing(
|
|
|
445
367
|
}
|
|
446
368
|
}
|
|
447
369
|
|
|
448
|
-
// Self-validation: verify no tool_use/tool_result mismatches remain
|
|
370
|
+
// Self-validation: verify no client-side tool_use/tool_result mismatches remain.
|
|
371
|
+
// Server-side tools (server_tool_use / web_search_tool_result) are self-paired
|
|
372
|
+
// within assistant messages and are not validated here.
|
|
449
373
|
for (let j = 0; j < result.length; j++) {
|
|
450
374
|
const m = result[j];
|
|
451
375
|
if (m.role !== "assistant") continue;
|
|
452
376
|
const c = Array.isArray(m.content) ? m.content : [];
|
|
453
|
-
const
|
|
454
|
-
getOrderedToolUseIds(c);
|
|
377
|
+
const validationIds = getOrderedToolUseIds(c);
|
|
455
378
|
if (validationIds.length === 0) continue;
|
|
456
379
|
|
|
457
380
|
const nxt = result[j + 1];
|
|
@@ -459,20 +382,9 @@ function ensureToolPairing(
|
|
|
459
382
|
nxt && nxt.role === "user" && Array.isArray(nxt.content)
|
|
460
383
|
? nxt.content
|
|
461
384
|
: [];
|
|
462
|
-
if (
|
|
463
|
-
!hasOrderedToolResultPrefix(
|
|
464
|
-
nxtContent,
|
|
465
|
-
validationIds,
|
|
466
|
-
validationServerToolIds,
|
|
467
|
-
)
|
|
468
|
-
) {
|
|
385
|
+
if (!hasOrderedToolResultPrefix(nxtContent, validationIds)) {
|
|
469
386
|
const unmatchedIds = validationIds.filter((id, idx) => {
|
|
470
387
|
const block = nxtContent[idx];
|
|
471
|
-
if (validationServerToolIds.has(id)) {
|
|
472
|
-
return !(
|
|
473
|
-
isWebSearchToolResultBlock(block) && block.tool_use_id === id
|
|
474
|
-
);
|
|
475
|
-
}
|
|
476
388
|
return !(isToolResultBlock(block) && block.tool_use_id === id);
|
|
477
389
|
});
|
|
478
390
|
log.error(
|
|
@@ -768,10 +680,14 @@ export class AnthropicProvider implements Provider {
|
|
|
768
680
|
onEvent?.({ type: "text_delta", text: " " });
|
|
769
681
|
}
|
|
770
682
|
hasSeenTextBlock = true;
|
|
771
|
-
} else if (
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
683
|
+
} else if (
|
|
684
|
+
event.type === "content_block_start" &&
|
|
685
|
+
event.content_block.type === "tool_use"
|
|
686
|
+
) {
|
|
687
|
+
// Reset only for client-side tool_use blocks, which create visual
|
|
688
|
+
// separators in the UI. Server-side tool blocks (server_tool_use,
|
|
689
|
+
// web_search_tool_result) are transparent in the text stream and
|
|
690
|
+
// need the space preserved between surrounding text blocks.
|
|
775
691
|
hasSeenTextBlock = false;
|
|
776
692
|
}
|
|
777
693
|
if (
|
|
@@ -796,6 +712,20 @@ export class AnthropicProvider implements Provider {
|
|
|
796
712
|
type: "server_tool_start",
|
|
797
713
|
name: event.content_block.name,
|
|
798
714
|
toolUseId: event.content_block.id,
|
|
715
|
+
input: (
|
|
716
|
+
event.content_block as { input?: Record<string, unknown> }
|
|
717
|
+
).input ?? {},
|
|
718
|
+
});
|
|
719
|
+
}
|
|
720
|
+
if (
|
|
721
|
+
event.type === "content_block_start" &&
|
|
722
|
+
event.content_block.type === "web_search_tool_result"
|
|
723
|
+
) {
|
|
724
|
+
onEvent?.({
|
|
725
|
+
type: "server_tool_complete",
|
|
726
|
+
toolUseId: (
|
|
727
|
+
event.content_block as { tool_use_id: string }
|
|
728
|
+
).tool_use_id,
|
|
799
729
|
});
|
|
800
730
|
}
|
|
801
731
|
if (event.type === "content_block_stop") {
|
package/src/providers/types.ts
CHANGED
|
@@ -117,7 +117,13 @@ export type ProviderEvent =
|
|
|
117
117
|
toolUseId: string;
|
|
118
118
|
accumulatedJson: string;
|
|
119
119
|
}
|
|
120
|
-
| {
|
|
120
|
+
| {
|
|
121
|
+
type: "server_tool_start";
|
|
122
|
+
name: string;
|
|
123
|
+
toolUseId: string;
|
|
124
|
+
input: Record<string, unknown>;
|
|
125
|
+
}
|
|
126
|
+
| { type: "server_tool_complete"; toolUseId: string };
|
|
121
127
|
|
|
122
128
|
export interface SendMessageConfig {
|
|
123
129
|
model?: string;
|
package/src/runtime/AGENTS.md
CHANGED
|
@@ -43,6 +43,15 @@ Host file allows the assistant to perform file operations (read, write, edit) on
|
|
|
43
43
|
- `POST /v1/host-file-result` — `{ requestId, content, isError }`
|
|
44
44
|
- **Tracking**: Uses the same `pending-interactions` tracker as approvals and host bash, with `kind: "host_file"`. The endpoint validates the interaction kind before resolving.
|
|
45
45
|
|
|
46
|
+
### Host CU (desktop proxy computer-use execution)
|
|
47
|
+
|
|
48
|
+
Host CU allows the assistant to proxy computer-use actions (screenshots, mouse/keyboard input) to the desktop host via the client, following the same pattern as host bash and host file.
|
|
49
|
+
|
|
50
|
+
- **Discovery**: Clients discover pending host CU requests via SSE events (`host_cu_request`) which include a `requestId`.
|
|
51
|
+
- **Resolution**: Clients execute the CU action on the host and respond via:
|
|
52
|
+
- `POST /v1/host-cu-result` — `{ requestId, axTree?, axDiff?, screenshot?, screenshotWidthPx?, screenshotHeightPx?, screenWidthPt?, screenHeightPt?, executionResult?, executionError?, secondaryWindows?, userGuidance? }`
|
|
53
|
+
- **Tracking**: Uses the same `pending-interactions` tracker as the other host proxy types, with `kind: "host_cu"`. Registration happens in `conversation-routes.ts` and the route handler is in `host-cu-routes.ts`.
|
|
54
|
+
|
|
46
55
|
### Channel approvals (Telegram, Slack)
|
|
47
56
|
|
|
48
57
|
Channel approval flows use `requestId` (not `runId`) as the primary identifier:
|
|
@@ -347,6 +347,12 @@ const ACTOR_ENDPOINTS: Array<{ endpoint: string; scopes: Scope[] }> = [
|
|
|
347
347
|
{ endpoint: "skills:DELETE", scopes: ["settings.write"] },
|
|
348
348
|
{ endpoint: "skills:PATCH", scopes: ["settings.write"] },
|
|
349
349
|
|
|
350
|
+
// Memory items
|
|
351
|
+
{ endpoint: "memory-items:GET", scopes: ["settings.read"] },
|
|
352
|
+
{ endpoint: "memory-items:POST", scopes: ["settings.write"] },
|
|
353
|
+
{ endpoint: "memory-items:PATCH", scopes: ["settings.write"] },
|
|
354
|
+
{ endpoint: "memory-items:DELETE", scopes: ["settings.write"] },
|
|
355
|
+
|
|
350
356
|
// Trust rule CRUD management
|
|
351
357
|
{ endpoint: "trust-rules/manage:GET", scopes: ["settings.read"] },
|
|
352
358
|
{ endpoint: "trust-rules/manage:POST", scopes: ["settings.write"] },
|
|
@@ -378,9 +384,6 @@ const ACTOR_ENDPOINTS: Array<{ endpoint: string; scopes: Scope[] }> = [
|
|
|
378
384
|
// Delivery ack
|
|
379
385
|
{ endpoint: "channels/delivery-ack", scopes: ["internal.write"] },
|
|
380
386
|
|
|
381
|
-
// MCP
|
|
382
|
-
{ endpoint: "mcp/reload", scopes: ["settings.write"] },
|
|
383
|
-
|
|
384
387
|
// Migrations
|
|
385
388
|
{ endpoint: "migrations/validate", scopes: ["settings.write"] },
|
|
386
389
|
{ endpoint: "migrations/export", scopes: ["settings.write"] },
|
|
@@ -4,7 +4,7 @@ import { getChannelInvitePolicy } from "../channels/config.js";
|
|
|
4
4
|
import { loadRawConfig } from "../config/loader.js";
|
|
5
5
|
import { getEmailService } from "../email/service.js";
|
|
6
6
|
import { credentialKey } from "../security/credential-key.js";
|
|
7
|
-
import {
|
|
7
|
+
import { getSecureKeyAsync } from "../security/secure-keys.js";
|
|
8
8
|
import { resolveWhatsAppDisplayNumber } from "./channel-invite-transports/whatsapp.js";
|
|
9
9
|
import type {
|
|
10
10
|
ChannelId,
|
|
@@ -46,13 +46,13 @@ function check(
|
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
/** Check that a secure credential key exists. */
|
|
49
|
-
function checkCredential(
|
|
49
|
+
async function checkCredential(
|
|
50
50
|
name: string,
|
|
51
51
|
service: string,
|
|
52
52
|
field: string,
|
|
53
53
|
label: string,
|
|
54
|
-
): ReadinessCheckResult {
|
|
55
|
-
const exists = !!
|
|
54
|
+
): Promise<ReadinessCheckResult> {
|
|
55
|
+
const exists = !!(await getSecureKeyAsync(credentialKey(service, field)));
|
|
56
56
|
return check(
|
|
57
57
|
name,
|
|
58
58
|
exists,
|
|
@@ -77,7 +77,7 @@ function checkIngress(): ReadinessCheckResult {
|
|
|
77
77
|
const voiceProbe: ChannelProbe = {
|
|
78
78
|
channel: "phone",
|
|
79
79
|
async runLocalChecks(): Promise<ReadinessCheckResult[]> {
|
|
80
|
-
const hasCreds = hasTwilioCredentials();
|
|
80
|
+
const hasCreds = await hasTwilioCredentials();
|
|
81
81
|
const hasPhone = !!resolveTwilioPhoneNumber();
|
|
82
82
|
const ingress = checkIngress();
|
|
83
83
|
|
|
@@ -117,26 +117,33 @@ const voiceProbe: ChannelProbe = {
|
|
|
117
117
|
|
|
118
118
|
const telegramProbe: ChannelProbe = {
|
|
119
119
|
channel: "telegram",
|
|
120
|
-
runLocalChecks
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
120
|
+
async runLocalChecks(): Promise<ReadinessCheckResult[]> {
|
|
121
|
+
return [
|
|
122
|
+
await checkCredential(
|
|
123
|
+
"bot_token",
|
|
124
|
+
"telegram",
|
|
125
|
+
"bot_token",
|
|
126
|
+
"Telegram bot token",
|
|
127
|
+
),
|
|
128
|
+
await checkCredential(
|
|
129
|
+
"webhook_secret",
|
|
130
|
+
"telegram",
|
|
131
|
+
"webhook_secret",
|
|
132
|
+
"Telegram webhook secret",
|
|
133
|
+
),
|
|
134
|
+
checkIngress(),
|
|
135
|
+
];
|
|
136
|
+
},
|
|
130
137
|
};
|
|
131
138
|
|
|
132
139
|
// ── Email Probe ─────────────────────────────────────────────────────────────
|
|
133
140
|
|
|
134
141
|
const emailProbe: ChannelProbe = {
|
|
135
142
|
channel: "email",
|
|
136
|
-
runLocalChecks(): ReadinessCheckResult[] {
|
|
143
|
+
async runLocalChecks(): Promise<ReadinessCheckResult[]> {
|
|
137
144
|
const hasApiKey = !!(
|
|
138
|
-
|
|
139
|
-
|
|
145
|
+
(await getSecureKeyAsync("agentmail")) ||
|
|
146
|
+
(await getSecureKeyAsync(credentialKey("agentmail", "api_key")))
|
|
140
147
|
);
|
|
141
148
|
const invitePolicy = getChannelInvitePolicy("email");
|
|
142
149
|
return [
|
|
@@ -155,12 +162,11 @@ const emailProbe: ChannelProbe = {
|
|
|
155
162
|
checkIngress(),
|
|
156
163
|
];
|
|
157
164
|
},
|
|
158
|
-
// runRemoteChecks UNCHANGED — keep the existing inbox_configured check as-is
|
|
159
165
|
async runRemoteChecks(): Promise<ReadinessCheckResult[]> {
|
|
160
166
|
// Only worth checking if the API key is present
|
|
161
167
|
const hasApiKey = !!(
|
|
162
|
-
|
|
163
|
-
|
|
168
|
+
(await getSecureKeyAsync("agentmail")) ||
|
|
169
|
+
(await getSecureKeyAsync(credentialKey("agentmail", "api_key")))
|
|
164
170
|
);
|
|
165
171
|
if (!hasApiKey) return [];
|
|
166
172
|
|
|
@@ -193,29 +199,29 @@ const emailProbe: ChannelProbe = {
|
|
|
193
199
|
|
|
194
200
|
const whatsappProbe: ChannelProbe = {
|
|
195
201
|
channel: "whatsapp",
|
|
196
|
-
runLocalChecks(): ReadinessCheckResult[] {
|
|
202
|
+
async runLocalChecks(): Promise<ReadinessCheckResult[]> {
|
|
197
203
|
const displayNumber = resolveWhatsAppDisplayNumber();
|
|
198
204
|
const invitePolicy = getChannelInvitePolicy("whatsapp");
|
|
199
205
|
return [
|
|
200
|
-
checkCredential(
|
|
206
|
+
await checkCredential(
|
|
201
207
|
"whatsapp_phone_number_id",
|
|
202
208
|
"whatsapp",
|
|
203
209
|
"phone_number_id",
|
|
204
210
|
"WhatsApp phone number ID",
|
|
205
211
|
),
|
|
206
|
-
checkCredential(
|
|
212
|
+
await checkCredential(
|
|
207
213
|
"whatsapp_access_token",
|
|
208
214
|
"whatsapp",
|
|
209
215
|
"access_token",
|
|
210
216
|
"WhatsApp access token",
|
|
211
217
|
),
|
|
212
|
-
checkCredential(
|
|
218
|
+
await checkCredential(
|
|
213
219
|
"whatsapp_app_secret",
|
|
214
220
|
"whatsapp",
|
|
215
221
|
"app_secret",
|
|
216
222
|
"WhatsApp app secret",
|
|
217
223
|
),
|
|
218
|
-
checkCredential(
|
|
224
|
+
await checkCredential(
|
|
219
225
|
"whatsapp_webhook_verify_token",
|
|
220
226
|
"whatsapp",
|
|
221
227
|
"webhook_verify_token",
|
|
@@ -242,20 +248,22 @@ const whatsappProbe: ChannelProbe = {
|
|
|
242
248
|
|
|
243
249
|
const slackProbe: ChannelProbe = {
|
|
244
250
|
channel: "slack",
|
|
245
|
-
runLocalChecks
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
251
|
+
async runLocalChecks(): Promise<ReadinessCheckResult[]> {
|
|
252
|
+
return [
|
|
253
|
+
await checkCredential(
|
|
254
|
+
"bot_token",
|
|
255
|
+
"slack_channel",
|
|
256
|
+
"bot_token",
|
|
257
|
+
"Slack bot token",
|
|
258
|
+
),
|
|
259
|
+
await checkCredential(
|
|
260
|
+
"app_token",
|
|
261
|
+
"slack_channel",
|
|
262
|
+
"app_token",
|
|
263
|
+
"Slack app token",
|
|
264
|
+
),
|
|
265
|
+
];
|
|
266
|
+
},
|
|
259
267
|
};
|
|
260
268
|
|
|
261
269
|
// ── Service ─────────────────────────────────────────────────────────────────
|
|
@@ -30,6 +30,7 @@ import {
|
|
|
30
30
|
type CanonicalGuardianRequest,
|
|
31
31
|
getCanonicalGuardianRequest,
|
|
32
32
|
getCanonicalGuardianRequestByCode,
|
|
33
|
+
isRequestExpired,
|
|
33
34
|
listCanonicalGuardianRequests,
|
|
34
35
|
} from "../memory/canonical-guardian-store.js";
|
|
35
36
|
import {
|
|
@@ -198,49 +199,50 @@ function findPendingCanonicalRequests(
|
|
|
198
199
|
pendingRequestIds?: string[],
|
|
199
200
|
conversationId?: string,
|
|
200
201
|
): CanonicalGuardianRequest[] {
|
|
202
|
+
let results: CanonicalGuardianRequest[];
|
|
203
|
+
|
|
201
204
|
// When explicit IDs are provided, look them up directly
|
|
202
205
|
if (pendingRequestIds) {
|
|
203
206
|
if (pendingRequestIds.length === 0) {
|
|
204
207
|
return [];
|
|
205
208
|
}
|
|
206
|
-
|
|
209
|
+
results = pendingRequestIds
|
|
207
210
|
.map(getCanonicalGuardianRequest)
|
|
208
211
|
.filter((r): r is CanonicalGuardianRequest => r?.status === "pending");
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
if (actor.actorExternalUserId) {
|
|
213
|
-
return listCanonicalGuardianRequests({
|
|
212
|
+
} else if (actor.actorExternalUserId) {
|
|
213
|
+
// Query by guardian identity when available
|
|
214
|
+
results = listCanonicalGuardianRequests({
|
|
214
215
|
status: "pending",
|
|
215
216
|
guardianExternalUserId: actor.actorExternalUserId,
|
|
216
217
|
});
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
if (conversationId) {
|
|
224
|
-
return listCanonicalGuardianRequests({
|
|
218
|
+
} else if (conversationId) {
|
|
219
|
+
// Actors without an actorExternalUserId: scope by conversationId so the NL
|
|
220
|
+
// path can discover pending requests bound to this conversation.
|
|
221
|
+
// Include guardianPrincipalId filter when available so the guardian only
|
|
222
|
+
// sees requests they are authorized to act on.
|
|
223
|
+
results = listCanonicalGuardianRequests({
|
|
225
224
|
status: "pending",
|
|
226
225
|
conversationId,
|
|
227
226
|
...(actor.guardianPrincipalId
|
|
228
227
|
? { guardianPrincipalId: actor.guardianPrincipalId }
|
|
229
228
|
: {}),
|
|
230
229
|
});
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
if (actor.guardianPrincipalId) {
|
|
237
|
-
return listCanonicalGuardianRequests({
|
|
230
|
+
} else if (actor.guardianPrincipalId) {
|
|
231
|
+
// Actors with a guardianPrincipalId but no actorExternalUserId or
|
|
232
|
+
// conversationId: query by principal so desktop sessions can still
|
|
233
|
+
// discover pending guardian work via their bound principal.
|
|
234
|
+
results = listCanonicalGuardianRequests({
|
|
238
235
|
status: "pending",
|
|
239
236
|
guardianPrincipalId: actor.guardianPrincipalId,
|
|
240
237
|
});
|
|
238
|
+
} else {
|
|
239
|
+
return [];
|
|
241
240
|
}
|
|
242
241
|
|
|
243
|
-
|
|
242
|
+
// Exclude requests that have passed their expiresAt deadline — they can
|
|
243
|
+
// no longer be resolved and should not trigger disambiguation or NL
|
|
244
|
+
// classification.
|
|
245
|
+
return results.filter((r) => !isRequestExpired(r));
|
|
244
246
|
}
|
|
245
247
|
|
|
246
248
|
/** Map an approval action string to the NL engine's allowed actions for guardians. */
|
|
@@ -135,7 +135,7 @@ import { telegramRouteDefinitions } from "./routes/integrations/telegram.js";
|
|
|
135
135
|
import { twilioRouteDefinitions } from "./routes/integrations/twilio.js";
|
|
136
136
|
import { inviteRouteDefinitions } from "./routes/invite-routes.js";
|
|
137
137
|
import { logExportRouteDefinitions } from "./routes/log-export-routes.js";
|
|
138
|
-
import {
|
|
138
|
+
import { memoryItemRouteDefinitions } from "./routes/memory-item-routes.js";
|
|
139
139
|
import { migrationRouteDefinitions } from "./routes/migration-routes.js";
|
|
140
140
|
import type { PairingHandlerContext } from "./routes/pairing-routes.js";
|
|
141
141
|
import {
|
|
@@ -723,9 +723,9 @@ export class RuntimeHttpServer {
|
|
|
723
723
|
...secretRouteDefinitions(),
|
|
724
724
|
...identityRouteDefinitions(),
|
|
725
725
|
...debugRouteDefinitions(),
|
|
726
|
-
...mcpRouteDefinitions(),
|
|
727
726
|
...usageRouteDefinitions(),
|
|
728
727
|
...workspaceRouteDefinitions(),
|
|
728
|
+
...memoryItemRouteDefinitions(),
|
|
729
729
|
...settingsRouteDefinitions(),
|
|
730
730
|
...scheduleRouteDefinitions({
|
|
731
731
|
sendMessageDeps: this.sendMessageDeps,
|