vellum 0.2.1 → 0.2.7
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/README.md +15 -2
- package/bun.lock +71 -100
- package/package.json +5 -3
- package/scripts/capture-x-graphql.ts +562 -0
- package/scripts/ipc/check-swift-decoder-drift.ts +2 -1
- package/scripts/test.sh +5 -0
- package/src/__tests__/__snapshots__/ipc-snapshot.test.ts.snap +133 -34
- package/src/__tests__/account-registry.test.ts +2 -1
- package/src/__tests__/agent-heartbeat-service.test.ts +250 -0
- package/src/__tests__/asset-materialize-tool.test.ts +16 -15
- package/src/__tests__/asset-search-tool.test.ts +23 -22
- package/src/__tests__/attachments-store.test.ts +56 -127
- package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +5 -4
- package/src/__tests__/browser-skill-endstate.test.ts +4 -3
- package/src/__tests__/call-bridge.test.ts +385 -0
- package/src/__tests__/call-constants.test.ts +40 -0
- package/src/__tests__/call-orchestrator.test.ts +130 -4
- package/src/__tests__/call-recovery.test.ts +518 -0
- package/src/__tests__/call-routes-http.test.ts +459 -0
- package/src/__tests__/call-state-machine.test.ts +143 -0
- package/src/__tests__/call-store.test.ts +216 -1
- package/src/__tests__/cli-discover.test.ts +1 -1
- package/src/__tests__/commit-message-enrichment-service.test.ts +148 -7
- package/src/__tests__/compaction.benchmark.test.ts +176 -0
- package/src/__tests__/computer-use-tools.test.ts +250 -0
- package/src/__tests__/config-schema.test.ts +305 -3
- package/src/__tests__/conflict-store.test.ts +2 -1
- package/src/__tests__/contacts-tools.test.ts +331 -0
- package/src/__tests__/conversation-store.test.ts +30 -32
- package/src/__tests__/credential-security-invariants.test.ts +4 -0
- package/src/__tests__/date-context.test.ts +373 -0
- package/src/__tests__/db-schedule-syntax-migration.test.ts +129 -0
- package/src/__tests__/fixtures/media-reuse-fixtures.ts +3 -3
- package/src/__tests__/followup-tools.test.ts +303 -0
- package/src/__tests__/handlers-twilio-config.test.ts +221 -0
- package/src/__tests__/handlers-twitter-config.test.ts +718 -0
- package/src/__tests__/intent-routing.test.ts +64 -57
- package/src/__tests__/ipc-roundtrip.benchmark.test.ts +237 -0
- package/src/__tests__/ipc-snapshot.test.ts +71 -28
- package/src/__tests__/llm-usage-store.test.ts +3 -8
- package/src/__tests__/media-generate-image.test.ts +1 -1
- package/src/__tests__/media-reuse-story.e2e.test.ts +7 -7
- package/src/__tests__/memory-regressions.test.ts +100 -2
- package/src/__tests__/memory-retrieval.benchmark.test.ts +430 -0
- package/src/__tests__/parallel-tool.benchmark.test.ts +294 -0
- package/src/__tests__/playbook-tools.test.ts +342 -0
- package/src/__tests__/profile-compiler.test.ts +2 -1
- package/src/__tests__/provider-commit-message-generator.test.ts +303 -0
- package/src/__tests__/provider-streaming.benchmark.test.ts +773 -0
- package/src/__tests__/recurrence-engine-rruleset.test.ts +78 -0
- package/src/__tests__/recurrence-engine.test.ts +69 -0
- package/src/__tests__/recurrence-types.test.ts +71 -0
- package/src/__tests__/registry.test.ts +5 -3
- package/src/__tests__/relay-server.test.ts +633 -0
- package/src/__tests__/reminder-store.test.ts +6 -3
- package/src/__tests__/reminder.test.ts +43 -77
- package/src/__tests__/run-orchestrator-assistant-events.test.ts +8 -4
- package/src/__tests__/run-orchestrator.test.ts +4 -4
- package/src/__tests__/runtime-attachment-metadata.test.ts +7 -6
- package/src/__tests__/runtime-runs-http.test.ts +4 -4
- package/src/__tests__/runtime-runs.test.ts +4 -4
- package/src/__tests__/schedule-store.test.ts +482 -0
- package/src/__tests__/schedule-tools.test.ts +700 -0
- package/src/__tests__/scheduler-recurrence.test.ts +329 -0
- package/src/__tests__/server-history-render.test.ts +14 -13
- package/src/__tests__/session-conflict-gate.test.ts +28 -25
- package/src/__tests__/session-error.test.ts +28 -0
- package/src/__tests__/session-init.benchmark.test.ts +462 -0
- package/src/__tests__/session-queue.test.ts +71 -48
- package/src/__tests__/session-runtime-assembly.test.ts +161 -0
- package/src/__tests__/session-surfaces-task-progress.test.ts +104 -0
- package/src/__tests__/signup-e2e.test.ts +2 -1
- package/src/__tests__/skill-projection.benchmark.test.ts +328 -0
- package/src/__tests__/skill-script-runner.test.ts +159 -0
- package/src/__tests__/speaker-identification.test.ts +52 -0
- package/src/__tests__/subagent-manager-notify.test.ts +42 -10
- package/src/__tests__/subagent-tools.test.ts +141 -41
- package/src/__tests__/task-compiler.test.ts +2 -1
- package/src/__tests__/task-runner.test.ts +2 -1
- package/src/__tests__/task-scheduler.test.ts +2 -1
- package/src/__tests__/task-tools.test.ts +49 -56
- package/src/__tests__/tool-audit-listener.test.ts +1 -0
- package/src/__tests__/tool-domain-event-publisher.test.ts +2 -0
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +500 -0
- package/src/__tests__/tool-executor.test.ts +13 -17
- package/src/__tests__/turn-commit.test.ts +218 -3
- package/src/__tests__/twilio-provider.test.ts +143 -0
- package/src/__tests__/twilio-routes.test.ts +789 -0
- package/src/__tests__/twitter-auth-handler.test.ts +581 -0
- package/src/__tests__/view-image-tool.test.ts +217 -0
- package/src/__tests__/workspace-git-service.test.ts +186 -0
- package/src/__tests__/workspace-heartbeat-service.test.ts +13 -3
- package/src/agent-heartbeat/agent-heartbeat-service.ts +155 -0
- package/src/bundler/app-bundler.ts +12 -8
- package/src/calls/__tests__/twilio-webhook-urls.test.ts +162 -0
- package/src/calls/call-bridge.ts +95 -0
- package/src/calls/call-constants.ts +43 -5
- package/src/calls/call-domain.ts +276 -0
- package/src/calls/call-orchestrator.ts +43 -17
- package/src/calls/call-recovery.ts +207 -0
- package/src/calls/call-state-machine.ts +68 -0
- package/src/calls/call-store.ts +192 -5
- package/src/calls/relay-server.ts +41 -4
- package/src/calls/speaker-identification.ts +213 -0
- package/src/calls/twilio-config.ts +8 -8
- package/src/calls/twilio-provider.ts +13 -9
- package/src/calls/twilio-routes.ts +90 -76
- package/src/calls/twilio-webhook-urls.ts +50 -0
- package/src/calls/types.ts +1 -1
- package/src/cli/config-commands.ts +334 -0
- package/src/cli/core-commands.ts +776 -0
- package/src/cli/doordash.ts +251 -1
- package/src/cli/ipc-client.ts +82 -0
- package/src/cli/map.ts +270 -0
- package/src/cli/twitter.ts +575 -0
- package/src/cli.ts +7 -5
- package/src/commands/__tests__/cc-command-registry.test.ts +319 -0
- package/src/commands/cc-command-registry.ts +209 -0
- package/src/config/bundled-skills/contacts/SKILL.md +39 -0
- package/src/config/bundled-skills/contacts/TOOLS.json +122 -0
- package/src/config/bundled-skills/contacts/tools/contact-merge.ts +9 -0
- package/src/config/bundled-skills/contacts/tools/contact-search.ts +9 -0
- package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +9 -0
- package/src/config/bundled-skills/document/SKILL.md +18 -0
- package/src/config/bundled-skills/document/TOOLS.json +53 -0
- package/src/config/bundled-skills/document/tools/document-create.ts +9 -0
- package/src/config/bundled-skills/document/tools/document-update.ts +9 -0
- package/src/config/bundled-skills/doordash/SKILL.md +82 -23
- package/src/config/bundled-skills/followups/SKILL.md +32 -0
- package/src/config/bundled-skills/followups/TOOLS.json +100 -0
- package/src/config/bundled-skills/followups/tools/followup-create.ts +9 -0
- package/src/config/bundled-skills/followups/tools/followup-list.ts +9 -0
- package/src/config/bundled-skills/followups/tools/followup-resolve.ts +9 -0
- package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +1 -23
- package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +2 -1
- package/src/config/bundled-skills/playbooks/SKILL.md +31 -0
- package/src/config/bundled-skills/playbooks/TOOLS.json +126 -0
- package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +9 -0
- package/src/config/bundled-skills/playbooks/tools/playbook-delete.ts +9 -0
- package/src/config/bundled-skills/playbooks/tools/playbook-list.ts +9 -0
- package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +9 -0
- package/src/config/bundled-skills/reminder/SKILL.md +20 -0
- package/src/config/bundled-skills/reminder/TOOLS.json +67 -0
- package/src/config/bundled-skills/reminder/tools/reminder-cancel.ts +9 -0
- package/src/config/bundled-skills/reminder/tools/reminder-create.ts +9 -0
- package/src/config/bundled-skills/reminder/tools/reminder-list.ts +9 -0
- package/src/config/bundled-skills/schedule/SKILL.md +74 -0
- package/src/config/bundled-skills/schedule/TOOLS.json +135 -0
- package/src/config/bundled-skills/schedule/tools/schedule-create.ts +9 -0
- package/src/config/bundled-skills/schedule/tools/schedule-delete.ts +9 -0
- package/src/config/bundled-skills/schedule/tools/schedule-list.ts +9 -0
- package/src/config/bundled-skills/schedule/tools/schedule-update.ts +9 -0
- package/src/config/bundled-skills/subagent/SKILL.md +25 -0
- package/src/config/bundled-skills/subagent/TOOLS.json +107 -0
- package/src/config/bundled-skills/subagent/tools/subagent-abort.ts +9 -0
- package/src/config/bundled-skills/subagent/tools/subagent-message.ts +9 -0
- package/src/config/bundled-skills/subagent/tools/subagent-read.ts +9 -0
- package/src/config/bundled-skills/subagent/tools/subagent-spawn.ts +9 -0
- package/src/config/bundled-skills/subagent/tools/subagent-status.ts +9 -0
- package/src/config/bundled-skills/tasks/SKILL.md +28 -0
- package/src/config/bundled-skills/tasks/TOOLS.json +256 -0
- package/src/config/bundled-skills/tasks/tools/task-delete.ts +9 -0
- package/src/config/bundled-skills/tasks/tools/task-list-add.ts +9 -0
- package/src/config/bundled-skills/tasks/tools/task-list-remove.ts +9 -0
- package/src/config/bundled-skills/tasks/tools/task-list-show.ts +9 -0
- package/src/config/bundled-skills/tasks/tools/task-list-update.ts +9 -0
- package/src/config/bundled-skills/tasks/tools/task-list.ts +9 -0
- package/src/config/bundled-skills/tasks/tools/task-run.ts +9 -0
- package/src/config/bundled-skills/tasks/tools/task-save.ts +9 -0
- package/src/config/bundled-skills/twitter/SKILL.md +134 -0
- package/src/config/bundled-skills/watcher/SKILL.md +27 -0
- package/src/config/bundled-skills/watcher/TOOLS.json +147 -0
- package/src/config/bundled-skills/watcher/tools/watcher-create.ts +9 -0
- package/src/config/bundled-skills/watcher/tools/watcher-delete.ts +9 -0
- package/src/config/bundled-skills/watcher/tools/watcher-digest.ts +9 -0
- package/src/config/bundled-skills/watcher/tools/watcher-list.ts +9 -0
- package/src/config/bundled-skills/watcher/tools/watcher-update.ts +9 -0
- package/src/config/defaults.ts +34 -0
- package/src/config/loader.ts +4 -1
- package/src/config/schema.ts +165 -1
- package/src/config/system-prompt.ts +61 -16
- package/src/config/templates/IDENTITY.md +7 -0
- package/src/config/types.ts +4 -0
- package/src/config/vellum-skills/telegram-setup/SKILL.md +1 -5
- package/src/contacts/contact-store.ts +4 -4
- package/src/daemon/assistant-attachments.ts +10 -0
- package/src/daemon/classifier.ts +3 -1
- package/src/daemon/computer-use-session.ts +3 -1
- package/src/daemon/date-context.ts +136 -0
- package/src/daemon/handlers/apps.ts +16 -1
- package/src/daemon/handlers/browser.ts +54 -0
- package/src/daemon/handlers/computer-use.ts +7 -1
- package/src/daemon/handlers/config.ts +205 -5
- package/src/daemon/handlers/diagnostics.ts +5 -1
- package/src/daemon/handlers/documents.ts +18 -29
- package/src/daemon/handlers/home-base.ts +5 -1
- package/src/daemon/handlers/index.ts +40 -277
- package/src/daemon/handlers/misc.ts +9 -1
- package/src/daemon/handlers/publish.ts +6 -1
- package/src/daemon/handlers/sessions.ts +65 -12
- package/src/daemon/handlers/shared.ts +36 -1
- package/src/daemon/handlers/signing.ts +37 -0
- package/src/daemon/handlers/skills.ts +20 -6
- package/src/daemon/handlers/subagents.ts +8 -3
- package/src/daemon/handlers/twitter-auth.ts +169 -0
- package/src/daemon/handlers/work-items.ts +384 -68
- package/src/daemon/ipc-contract-inventory.json +32 -4
- package/src/daemon/ipc-contract.ts +156 -37
- package/src/daemon/ipc-protocol.ts +7 -2
- package/src/daemon/lifecycle.ts +21 -0
- package/src/daemon/main.ts +10 -4
- package/src/daemon/ride-shotgun-handler.ts +75 -10
- package/src/daemon/server.ts +143 -26
- package/src/daemon/session-agent-loop.ts +922 -0
- package/src/daemon/session-attachments.ts +28 -5
- package/src/daemon/session-conflict-gate.ts +18 -109
- package/src/daemon/session-error.ts +24 -3
- package/src/daemon/session-lifecycle.ts +147 -0
- package/src/daemon/session-media-retry.ts +147 -0
- package/src/daemon/session-messaging.ts +145 -0
- package/src/daemon/session-notifiers.ts +164 -0
- package/src/daemon/session-process.ts +2 -2
- package/src/daemon/session-queue-manager.ts +1 -0
- package/src/daemon/session-runtime-assembly.ts +52 -0
- package/src/daemon/session-skill-tools.ts +124 -5
- package/src/daemon/session-slash.ts +3 -0
- package/src/daemon/session-surfaces.ts +77 -2
- package/src/daemon/session-tool-setup.ts +216 -2
- package/src/daemon/session-usage.ts +0 -2
- package/src/daemon/session.ts +114 -1404
- package/src/daemon/video-thumbnail.ts +60 -0
- package/src/doordash/client.ts +121 -27
- package/src/doordash/queries.ts +1 -2
- package/src/export/formatter.ts +3 -1
- package/src/followups/followup-store.ts +4 -2
- package/src/followups/types.ts +6 -0
- package/src/hooks/templates.ts +1 -1
- package/src/index.ts +32 -1153
- package/src/memory/attachments-store.ts +28 -83
- package/src/memory/channel-delivery-store.ts +7 -21
- package/src/memory/clarification-resolver.ts +6 -5
- package/src/memory/conflict-intent.ts +114 -0
- package/src/memory/contradiction-checker.ts +3 -2
- package/src/memory/conversation-key-store.ts +10 -29
- package/src/memory/conversation-store.ts +2 -1
- package/src/memory/db.ts +96 -2
- package/src/memory/entity-extractor.ts +6 -3
- package/src/memory/items-extractor.ts +5 -4
- package/src/memory/job-handlers/conflict.ts +23 -1
- package/src/memory/jobs-store.ts +3 -2
- package/src/memory/llm-usage-store.ts +1 -2
- package/src/memory/runs-store.ts +1 -2
- package/src/memory/schema.ts +23 -2
- package/src/messaging/style-analyzer.ts +3 -2
- package/src/messaging/thread-summarizer.ts +8 -12
- package/src/messaging/triage-engine.ts +4 -2
- package/src/providers/openrouter/client.ts +20 -0
- package/src/providers/registry.ts +8 -0
- package/src/runtime/gateway-client.ts +36 -0
- package/src/runtime/http-server.ts +166 -22
- package/src/runtime/routes/attachment-routes.ts +2 -3
- package/src/runtime/routes/call-routes.ts +140 -0
- package/src/runtime/routes/channel-routes.ts +125 -88
- package/src/runtime/routes/conversation-routes.ts +5 -5
- package/src/runtime/routes/run-routes.ts +2 -2
- package/src/runtime/run-orchestrator.ts +9 -3
- package/src/schedule/recurrence-engine.ts +138 -0
- package/src/schedule/recurrence-types.ts +67 -0
- package/src/schedule/schedule-store.ts +102 -57
- package/src/schedule/scheduler.ts +9 -6
- package/src/security/oauth2.ts +29 -4
- package/src/security/secret-allowlist.ts +46 -0
- package/src/skills/clawhub.ts +1 -1
- package/src/subagent/manager.ts +40 -8
- package/src/swarm/backend-claude-code.ts +64 -9
- package/src/swarm/worker-prompts.ts +2 -1
- package/src/tasks/SPEC.md +34 -28
- package/src/tasks/ephemeral-permissions.ts +16 -7
- package/src/tasks/task-compiler.ts +5 -4
- package/src/tasks/task-runner.ts +10 -5
- package/src/tasks/task-scheduler.ts +1 -1
- package/src/tasks/tool-sanitizer.ts +36 -0
- package/src/tools/assets/search.ts +4 -4
- package/src/tools/browser/api-map.ts +293 -0
- package/src/tools/browser/auto-navigate.ts +270 -0
- package/src/tools/browser/browser-execution.ts +2 -1
- package/src/tools/browser/browser-manager.ts +2 -2
- package/src/tools/browser/network-recorder.ts +5 -4
- package/src/tools/browser/x-auto-navigate.ts +207 -0
- package/src/tools/calls/call-end.ts +17 -67
- package/src/tools/calls/call-start.ts +24 -85
- package/src/tools/calls/call-status.ts +35 -51
- package/src/tools/claude-code/claude-code.ts +207 -11
- package/src/tools/contacts/contact-merge.ts +46 -78
- package/src/tools/contacts/contact-search.ts +35 -79
- package/src/tools/contacts/contact-upsert.ts +35 -108
- package/src/tools/credentials/vault.ts +20 -4
- package/src/tools/document/document-tool.ts +71 -144
- package/src/tools/executor.ts +129 -10
- package/src/tools/followups/followup_create.ts +46 -88
- package/src/tools/followups/followup_list.ts +34 -74
- package/src/tools/followups/followup_resolve.ts +31 -66
- package/src/tools/host-terminal/cli-discover.ts +2 -1
- package/src/tools/host-terminal/host-shell.ts +10 -0
- package/src/tools/memory/handlers.ts +5 -4
- package/src/tools/network/__tests__/web-search.test.ts +427 -0
- package/src/tools/network/script-proxy/__tests__/logging.test.ts +248 -0
- package/src/tools/network/script-proxy/__tests__/policy.test.ts +234 -0
- package/src/tools/network/script-proxy/__tests__/router.test.ts +76 -0
- package/src/tools/network/web-fetch.ts +18 -6
- package/src/tools/playbooks/index.ts +4 -5
- package/src/tools/playbooks/playbook-create.ts +3 -47
- package/src/tools/playbooks/playbook-delete.ts +1 -25
- package/src/tools/playbooks/playbook-list.ts +1 -28
- package/src/tools/playbooks/playbook-update.ts +3 -51
- package/src/tools/reminder/reminder.ts +5 -78
- package/src/tools/schedule/create.ts +69 -74
- package/src/tools/schedule/delete.ts +21 -47
- package/src/tools/schedule/list.ts +55 -74
- package/src/tools/schedule/update.ts +77 -84
- package/src/tools/subagent/abort.ts +29 -58
- package/src/tools/subagent/message.ts +30 -63
- package/src/tools/subagent/read.ts +53 -84
- package/src/tools/subagent/spawn.ts +43 -82
- package/src/tools/subagent/status.ts +42 -71
- package/src/tools/swarm/delegate.ts +2 -1
- package/src/tools/tasks/index.ts +8 -8
- package/src/tools/tasks/task-delete.ts +60 -88
- package/src/tools/tasks/task-list.ts +31 -52
- package/src/tools/tasks/task-run.ts +72 -108
- package/src/tools/tasks/task-save.ts +33 -65
- package/src/tools/tasks/work-item-enqueue.ts +183 -215
- package/src/tools/tasks/work-item-list.ts +33 -63
- package/src/tools/tasks/work-item-remove.ts +45 -97
- package/src/tools/tasks/work-item-update.ts +91 -163
- package/src/tools/terminal/backends/native.ts +3 -1
- package/src/tools/tool-manifest.ts +0 -62
- package/src/tools/types.ts +6 -0
- package/src/tools/ui-surface/definitions.ts +3 -1
- package/src/tools/watch/screen-watch.ts +3 -1
- package/src/tools/watcher/create.ts +52 -98
- package/src/tools/watcher/delete.ts +20 -46
- package/src/tools/watcher/digest.ts +36 -70
- package/src/tools/watcher/list.ts +49 -79
- package/src/tools/watcher/update.ts +45 -91
- package/src/twitter/client.ts +690 -0
- package/src/twitter/session.ts +91 -0
- package/src/usage/types.ts +0 -1
- package/src/util/truncate.ts +6 -0
- package/src/watcher/providers/slack.ts +2 -1
- package/src/watcher/watcher-store.ts +3 -2
- package/src/work-items/work-item-store.ts +27 -2
- package/src/workspace/commit-message-enrichment-service.ts +31 -7
- package/src/workspace/git-service.ts +87 -22
- package/src/workspace/provider-commit-message-generator.ts +269 -0
- package/src/workspace/turn-commit.ts +62 -3
- package/src/tools/contacts/index.ts +0 -4
- package/src/tools/document/index.ts +0 -5
- package/src/tools/followups/index.ts +0 -3
- package/src/tools/subagent/index.ts +0 -5
- /package/src/__tests__/{memory-context-benchmark.test.ts → memory-context-benchmark.benchmark.test.ts} +0 -0
|
@@ -3,6 +3,7 @@ import type { Tool, ToolContext, ToolExecutionResult } from '../types.js';
|
|
|
3
3
|
import type { ToolDefinition } from '../../providers/types.js';
|
|
4
4
|
import { getConfig } from '../../config/loader.js';
|
|
5
5
|
import { getLogger } from '../../util/logger.js';
|
|
6
|
+
import { truncate } from '../../util/truncate.js';
|
|
6
7
|
import { getProfilePolicy } from '../../swarm/worker-backend.js';
|
|
7
8
|
import type { WorkerProfile } from '../../swarm/worker-backend.js';
|
|
8
9
|
|
|
@@ -22,6 +23,30 @@ const APPROVAL_REQUIRED_TOOLS = new Set([
|
|
|
22
23
|
|
|
23
24
|
const VALID_PROFILES: readonly WorkerProfile[] = ['general', 'researcher', 'coder', 'reviewer'];
|
|
24
25
|
|
|
26
|
+
// Maximum nesting depth for Claude Code subprocesses.
|
|
27
|
+
// Depth 0 = top-level assistant, depth 1 = first subprocess, etc.
|
|
28
|
+
const MAX_CLAUDE_CODE_DEPTH = 1;
|
|
29
|
+
const DEPTH_ENV_VAR = 'VELLUM_CLAUDE_CODE_DEPTH';
|
|
30
|
+
|
|
31
|
+
function summarizeToolInput(toolName: string, input: Record<string, unknown>): string {
|
|
32
|
+
// Extract the most relevant field for each tool type
|
|
33
|
+
const name = toolName.toLowerCase();
|
|
34
|
+
if (name === 'bash') return String(input.command ?? '');
|
|
35
|
+
if (name === 'read' || name === 'file_read') return String(input.file_path ?? input.path ?? '');
|
|
36
|
+
if (name === 'edit' || name === 'file_edit') return String(input.file_path ?? input.path ?? '');
|
|
37
|
+
if (name === 'write' || name === 'file_write') return String(input.file_path ?? input.path ?? '');
|
|
38
|
+
if (name === 'glob') return String(input.pattern ?? '');
|
|
39
|
+
if (name === 'grep') return String(input.pattern ?? '');
|
|
40
|
+
if (name === 'websearch' || name === 'web_search') return String(input.query ?? '');
|
|
41
|
+
if (name === 'webfetch' || name === 'web_fetch') return String(input.url ?? '');
|
|
42
|
+
if (name === 'task') return String(input.description ?? '');
|
|
43
|
+
// Fallback: first string value
|
|
44
|
+
for (const val of Object.values(input)) {
|
|
45
|
+
if (typeof val === 'string' && val.length > 0 && val.length < 200) return val;
|
|
46
|
+
}
|
|
47
|
+
return '';
|
|
48
|
+
}
|
|
49
|
+
|
|
25
50
|
export const claudeCodeTool: Tool = {
|
|
26
51
|
name: 'claude_code',
|
|
27
52
|
description: 'Delegate a coding task to Claude Code, an AI-powered coding agent that can read, write, and edit files, run shell commands, and perform complex multi-step software engineering tasks autonomously.',
|
|
@@ -108,7 +133,10 @@ export const claudeCodeTool: Tool = {
|
|
|
108
133
|
|
|
109
134
|
const { query } = sdkModule;
|
|
110
135
|
|
|
111
|
-
|
|
136
|
+
// Collect stderr output from the Claude Code subprocess for debugging
|
|
137
|
+
const stderrLines: string[] = [];
|
|
138
|
+
|
|
139
|
+
log.info({ prompt: truncate(prompt, 100, ''), workingDir, model, resume: !!resumeSessionId }, 'Starting Claude Code session');
|
|
112
140
|
|
|
113
141
|
// Build the canUseTool callback, enforcing profile-based restrictions
|
|
114
142
|
const canUseTool: import('@anthropic-ai/claude-agent-sdk').CanUseTool = async (toolName, toolInput, _options) => {
|
|
@@ -151,6 +179,26 @@ export const claudeCodeTool: Tool = {
|
|
|
151
179
|
}
|
|
152
180
|
};
|
|
153
181
|
|
|
182
|
+
// Enforce nesting depth limit to prevent infinite recursion.
|
|
183
|
+
const currentDepth = parseInt(process.env[DEPTH_ENV_VAR] ?? '0', 10);
|
|
184
|
+
if (currentDepth >= MAX_CLAUDE_CODE_DEPTH) {
|
|
185
|
+
log.warn({ currentDepth, max: MAX_CLAUDE_CODE_DEPTH }, 'Claude Code nesting depth exceeded');
|
|
186
|
+
return {
|
|
187
|
+
content: `Error: Claude Code nesting depth exceeded (depth ${currentDepth}, max ${MAX_CLAUDE_CODE_DEPTH}). Cannot spawn another Claude Code subprocess.`,
|
|
188
|
+
isError: true,
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Build a clean env for the subprocess. Strip the SDK's own nesting guard
|
|
193
|
+
// (CLAUDECODE) so it can launch, but set our depth counter to enforce our limit.
|
|
194
|
+
const subprocessEnv: Record<string, string | undefined> = {
|
|
195
|
+
...process.env,
|
|
196
|
+
ANTHROPIC_API_KEY: apiKey,
|
|
197
|
+
[DEPTH_ENV_VAR]: String(currentDepth + 1),
|
|
198
|
+
};
|
|
199
|
+
delete subprocessEnv.CLAUDECODE;
|
|
200
|
+
delete subprocessEnv.CLAUDE_CODE_ENTRYPOINT;
|
|
201
|
+
|
|
154
202
|
// Build query options
|
|
155
203
|
const queryOptions: import('@anthropic-ai/claude-agent-sdk').Options = {
|
|
156
204
|
cwd: workingDir,
|
|
@@ -158,27 +206,47 @@ export const claudeCodeTool: Tool = {
|
|
|
158
206
|
canUseTool,
|
|
159
207
|
permissionMode: 'default',
|
|
160
208
|
allowedTools: [...AUTO_APPROVE_TOOLS],
|
|
161
|
-
env:
|
|
162
|
-
...process.env,
|
|
163
|
-
ANTHROPIC_API_KEY: apiKey,
|
|
164
|
-
},
|
|
209
|
+
env: subprocessEnv,
|
|
165
210
|
maxTurns: 50,
|
|
166
211
|
persistSession: true,
|
|
212
|
+
stderr: (data: string) => {
|
|
213
|
+
const trimmed = data.trimEnd();
|
|
214
|
+
if (trimmed) {
|
|
215
|
+
stderrLines.push(trimmed);
|
|
216
|
+
log.debug({ stderr: trimmed }, 'Claude Code subprocess stderr');
|
|
217
|
+
}
|
|
218
|
+
},
|
|
167
219
|
};
|
|
168
220
|
|
|
169
221
|
if (resumeSessionId) {
|
|
170
222
|
queryOptions.resume = resumeSessionId;
|
|
171
223
|
}
|
|
172
224
|
|
|
225
|
+
// Declared outside try so the catch block can emit a final tool_complete on error.
|
|
226
|
+
let lastSubToolName: string | null = null;
|
|
227
|
+
|
|
173
228
|
try {
|
|
174
229
|
const conversation = query({ prompt, options: queryOptions });
|
|
175
230
|
let resultText = '';
|
|
176
231
|
let sessionId = '';
|
|
177
232
|
let hasError = false;
|
|
178
233
|
|
|
234
|
+
// Track tool_use_id → {name, inputSummary} for enriching progress events.
|
|
235
|
+
const toolUseIdInfo = new Map<string, { name: string; inputSummary: string }>();
|
|
236
|
+
// Track tool_use_ids that we've already emitted tool_start for (to avoid duplicates).
|
|
237
|
+
const emittedToolUseIds = new Set<string>();
|
|
238
|
+
// Track the currently active tool_use_id from tool_progress events.
|
|
239
|
+
let activeToolUseId: string | null = null;
|
|
240
|
+
|
|
179
241
|
for await (const message of conversation) {
|
|
180
242
|
switch (message.type) {
|
|
181
243
|
case 'assistant': {
|
|
244
|
+
// Check for SDK-level errors on the assistant message
|
|
245
|
+
if (message.error) {
|
|
246
|
+
log.error({ error: message.error, sessionId: message.session_id }, 'Claude Code assistant message error');
|
|
247
|
+
hasError = true;
|
|
248
|
+
resultText += `\n\n[Claude Code error: ${message.error}]`;
|
|
249
|
+
}
|
|
182
250
|
// Extract text from assistant messages
|
|
183
251
|
if (message.message?.content) {
|
|
184
252
|
for (const block of message.message.content) {
|
|
@@ -186,29 +254,141 @@ export const claudeCodeTool: Tool = {
|
|
|
186
254
|
context.onOutput?.(block.text);
|
|
187
255
|
resultText += block.text;
|
|
188
256
|
}
|
|
257
|
+
if (block.type === 'tool_use') {
|
|
258
|
+
// Capture info keyed by tool_use_id for enriching tool_progress events.
|
|
259
|
+
const inputSummary = summarizeToolInput(block.name, block.input as Record<string, unknown>);
|
|
260
|
+
toolUseIdInfo.set(block.id, { name: block.name, inputSummary });
|
|
261
|
+
|
|
262
|
+
// Emit tool_start if we haven't already (tool_progress may have fired first).
|
|
263
|
+
// NOTE: Do NOT emit tool_complete for the previous tool here. An assistant
|
|
264
|
+
// message may contain multiple tool_use blocks (parallel tool use) and none
|
|
265
|
+
// of them have executed yet at this point. Completions are handled by
|
|
266
|
+
// tool_use_summary and tool_progress events.
|
|
267
|
+
if (!emittedToolUseIds.has(block.id)) {
|
|
268
|
+
context.onOutput?.(JSON.stringify({
|
|
269
|
+
subType: 'tool_start',
|
|
270
|
+
subToolName: block.name,
|
|
271
|
+
subToolInput: inputSummary,
|
|
272
|
+
subToolId: block.id,
|
|
273
|
+
}));
|
|
274
|
+
emittedToolUseIds.add(block.id);
|
|
275
|
+
lastSubToolName = block.name;
|
|
276
|
+
activeToolUseId = block.id;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
189
279
|
}
|
|
190
280
|
}
|
|
191
281
|
sessionId = message.session_id;
|
|
192
282
|
break;
|
|
193
283
|
}
|
|
284
|
+
case 'tool_progress': {
|
|
285
|
+
// The SDK fires tool_progress periodically DURING tool execution.
|
|
286
|
+
// This is our primary signal for live sub-tool progress.
|
|
287
|
+
const toolUseId = message.tool_use_id;
|
|
288
|
+
const toolName = message.tool_name;
|
|
289
|
+
sessionId = message.session_id;
|
|
290
|
+
|
|
291
|
+
// Record tool name if we don't have it yet (tool_progress fires before assistant sometimes).
|
|
292
|
+
if (!toolUseIdInfo.has(toolUseId)) {
|
|
293
|
+
toolUseIdInfo.set(toolUseId, { name: toolName, inputSummary: '' });
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
if (!emittedToolUseIds.has(toolUseId)) {
|
|
297
|
+
// New tool — mark previous as complete and emit tool_start.
|
|
298
|
+
if (lastSubToolName && activeToolUseId !== toolUseId) {
|
|
299
|
+
context.onOutput?.(JSON.stringify({
|
|
300
|
+
subType: 'tool_complete',
|
|
301
|
+
subToolName: lastSubToolName,
|
|
302
|
+
subToolId: activeToolUseId,
|
|
303
|
+
}));
|
|
304
|
+
}
|
|
305
|
+
const inputSummary = toolUseIdInfo.get(toolUseId)?.inputSummary ?? '';
|
|
306
|
+
context.onOutput?.(JSON.stringify({
|
|
307
|
+
subType: 'tool_start',
|
|
308
|
+
subToolName: toolName,
|
|
309
|
+
subToolInput: inputSummary,
|
|
310
|
+
subToolId: toolUseId,
|
|
311
|
+
}));
|
|
312
|
+
emittedToolUseIds.add(toolUseId);
|
|
313
|
+
lastSubToolName = toolName;
|
|
314
|
+
}
|
|
315
|
+
activeToolUseId = toolUseId;
|
|
316
|
+
break;
|
|
317
|
+
}
|
|
318
|
+
case 'tool_use_summary': {
|
|
319
|
+
// The SDK fires tool_use_summary after tool execution with a summary
|
|
320
|
+
// and the IDs of tools that were executed.
|
|
321
|
+
sessionId = message.session_id;
|
|
322
|
+
for (const completedId of message.preceding_tool_use_ids) {
|
|
323
|
+
const info = toolUseIdInfo.get(completedId);
|
|
324
|
+
const completedName: string | null = info?.name ?? lastSubToolName;
|
|
325
|
+
if (completedName && emittedToolUseIds.has(completedId)) {
|
|
326
|
+
context.onOutput?.(JSON.stringify({
|
|
327
|
+
subType: 'tool_complete',
|
|
328
|
+
subToolName: completedName,
|
|
329
|
+
subToolId: completedId,
|
|
330
|
+
}));
|
|
331
|
+
if (lastSubToolName === completedName) {
|
|
332
|
+
lastSubToolName = null;
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
// Prune completed entries to keep memory flat across long sessions.
|
|
336
|
+
toolUseIdInfo.delete(completedId);
|
|
337
|
+
emittedToolUseIds.delete(completedId);
|
|
338
|
+
}
|
|
339
|
+
activeToolUseId = null;
|
|
340
|
+
break;
|
|
341
|
+
}
|
|
194
342
|
case 'result': {
|
|
343
|
+
// Mark the final sub-tool as complete (flag error if the session failed).
|
|
344
|
+
if (lastSubToolName) {
|
|
345
|
+
const isFailure = message.subtype !== 'success';
|
|
346
|
+
context.onOutput?.(JSON.stringify({
|
|
347
|
+
subType: 'tool_complete',
|
|
348
|
+
subToolName: lastSubToolName,
|
|
349
|
+
subToolId: activeToolUseId,
|
|
350
|
+
...(isFailure && { subToolIsError: true }),
|
|
351
|
+
}));
|
|
352
|
+
lastSubToolName = null;
|
|
353
|
+
}
|
|
195
354
|
sessionId = message.session_id;
|
|
355
|
+
const resultMeta = {
|
|
356
|
+
subtype: message.subtype,
|
|
357
|
+
numTurns: message.num_turns,
|
|
358
|
+
durationMs: message.duration_ms,
|
|
359
|
+
costUsd: message.total_cost_usd,
|
|
360
|
+
stopReason: message.stop_reason,
|
|
361
|
+
};
|
|
362
|
+
|
|
196
363
|
if (message.subtype === 'success') {
|
|
364
|
+
log.info(resultMeta, 'Claude Code session completed successfully');
|
|
197
365
|
if (message.result && !resultText) {
|
|
198
366
|
resultText = message.result;
|
|
199
367
|
}
|
|
200
368
|
} else {
|
|
201
|
-
// Error result
|
|
369
|
+
// Error result — surface the subtype and details
|
|
202
370
|
hasError = true;
|
|
203
371
|
const errors = message.errors ?? [];
|
|
372
|
+
const denials = message.permission_denials ?? [];
|
|
373
|
+
|
|
374
|
+
log.error({ ...resultMeta, errors, permissionDenials: denials.length }, 'Claude Code session failed');
|
|
375
|
+
|
|
376
|
+
const parts: string[] = [];
|
|
377
|
+
parts.push(`[${message.subtype}] (${message.num_turns} turns, ${(message.duration_ms / 1000).toFixed(1)}s)`);
|
|
204
378
|
if (errors.length > 0) {
|
|
205
|
-
|
|
379
|
+
parts.push(`Errors: ${errors.join('; ')}`);
|
|
380
|
+
}
|
|
381
|
+
if (denials.length > 0) {
|
|
382
|
+
const denialSummary = denials.map(d => `${d.tool_name}`).join(', ');
|
|
383
|
+
parts.push(`Permission denied: ${denialSummary}`);
|
|
206
384
|
}
|
|
385
|
+
resultText += `\n\n${parts.join('\n')}`;
|
|
207
386
|
}
|
|
208
387
|
break;
|
|
209
388
|
}
|
|
210
389
|
default:
|
|
211
|
-
//
|
|
390
|
+
// Log unhandled message types at debug level for diagnostics
|
|
391
|
+
log.debug({ messageType: message.type }, 'Claude Code unhandled message type');
|
|
212
392
|
break;
|
|
213
393
|
}
|
|
214
394
|
}
|
|
@@ -221,10 +401,26 @@ export const claudeCodeTool: Tool = {
|
|
|
221
401
|
isError: hasError,
|
|
222
402
|
};
|
|
223
403
|
} catch (err) {
|
|
224
|
-
|
|
225
|
-
|
|
404
|
+
// Mark the last sub-tool as failed so the UI shows an error icon.
|
|
405
|
+
if (lastSubToolName) {
|
|
406
|
+
context.onOutput?.(JSON.stringify({
|
|
407
|
+
subType: 'tool_complete',
|
|
408
|
+
subToolName: lastSubToolName,
|
|
409
|
+
subToolIsError: true,
|
|
410
|
+
}));
|
|
411
|
+
lastSubToolName = null;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
const errMessage = err instanceof Error ? err.message : String(err);
|
|
415
|
+
const recentStderr = stderrLines.slice(-20);
|
|
416
|
+
log.error({ err, stderrTail: recentStderr }, 'Claude Code execution failed');
|
|
417
|
+
|
|
418
|
+
const parts = [`Claude Code error: ${errMessage}`];
|
|
419
|
+
if (recentStderr.length > 0) {
|
|
420
|
+
parts.push(`\nSubprocess stderr (last ${recentStderr.length} lines):\n${recentStderr.join('\n')}`);
|
|
421
|
+
}
|
|
226
422
|
return {
|
|
227
|
-
content:
|
|
423
|
+
content: parts.join(''),
|
|
228
424
|
isError: true,
|
|
229
425
|
};
|
|
230
426
|
}
|
|
@@ -1,87 +1,55 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type { Tool, ToolContext, ToolExecutionResult } from '../types.js';
|
|
3
|
-
import type { ToolDefinition } from '../../providers/types.js';
|
|
4
|
-
import { registerTool } from '../registry.js';
|
|
1
|
+
import type { ToolContext, ToolExecutionResult } from '../types.js';
|
|
5
2
|
import { mergeContacts, getContact } from '../../contacts/contact-store.js';
|
|
6
3
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
keep_id: {
|
|
14
|
-
type: 'string',
|
|
15
|
-
description: 'ID of the contact to keep (the surviving contact)',
|
|
16
|
-
},
|
|
17
|
-
merge_id: {
|
|
18
|
-
type: 'string',
|
|
19
|
-
description: 'ID of the contact to merge into the kept contact (will be deleted)',
|
|
20
|
-
},
|
|
21
|
-
},
|
|
22
|
-
required: ['keep_id', 'merge_id'],
|
|
23
|
-
},
|
|
24
|
-
};
|
|
4
|
+
export async function executeContactMerge(
|
|
5
|
+
input: Record<string, unknown>,
|
|
6
|
+
_context: ToolContext,
|
|
7
|
+
): Promise<ToolExecutionResult> {
|
|
8
|
+
const keepId = input.keep_id as string | undefined;
|
|
9
|
+
const mergeId = input.merge_id as string | undefined;
|
|
25
10
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
getDefinition(): ToolDefinition {
|
|
33
|
-
return definition;
|
|
11
|
+
if (!keepId || typeof keepId !== 'string') {
|
|
12
|
+
return { content: 'Error: keep_id is required', isError: true };
|
|
13
|
+
}
|
|
14
|
+
if (!mergeId || typeof mergeId !== 'string') {
|
|
15
|
+
return { content: 'Error: merge_id is required', isError: true };
|
|
34
16
|
}
|
|
35
17
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
if (!keepId || typeof keepId !== 'string') {
|
|
41
|
-
return { content: 'Error: keep_id is required', isError: true };
|
|
42
|
-
}
|
|
43
|
-
if (!mergeId || typeof mergeId !== 'string') {
|
|
44
|
-
return { content: 'Error: merge_id is required', isError: true };
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// Show what will be merged for clarity
|
|
48
|
-
const keepContact = getContact(keepId);
|
|
49
|
-
const mergeContact = getContact(mergeId);
|
|
50
|
-
|
|
51
|
-
if (!keepContact) {
|
|
52
|
-
return { content: `Error: Contact "${keepId}" not found`, isError: true };
|
|
53
|
-
}
|
|
54
|
-
if (!mergeContact) {
|
|
55
|
-
return { content: `Error: Contact "${mergeId}" not found`, isError: true };
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
try {
|
|
59
|
-
const merged = mergeContacts(keepId, mergeId);
|
|
18
|
+
// Show what will be merged for clarity
|
|
19
|
+
const keepContact = getContact(keepId);
|
|
20
|
+
const mergeContact = getContact(mergeId);
|
|
60
21
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
22
|
+
if (!keepContact) {
|
|
23
|
+
return { content: `Error: Contact "${keepId}" not found`, isError: true };
|
|
24
|
+
}
|
|
25
|
+
if (!mergeContact) {
|
|
26
|
+
return { content: `Error: Contact "${mergeId}" not found`, isError: true };
|
|
27
|
+
}
|
|
64
28
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
29
|
+
try {
|
|
30
|
+
const merged = mergeContacts(keepId, mergeId);
|
|
31
|
+
|
|
32
|
+
const channelList = merged.channels
|
|
33
|
+
.map((ch) => ` - ${ch.type}: ${ch.address}${ch.isPrimary ? ' (primary)' : ''}`)
|
|
34
|
+
.join('\n');
|
|
35
|
+
|
|
36
|
+
return {
|
|
37
|
+
content: [
|
|
38
|
+
`Merged "${mergeContact.displayName}" into "${keepContact.displayName}".`,
|
|
39
|
+
``,
|
|
40
|
+
`Surviving contact (${merged.id}):`,
|
|
41
|
+
` Name: ${merged.displayName}`,
|
|
42
|
+
` Importance: ${merged.importance.toFixed(2)}`,
|
|
43
|
+
` Interactions: ${merged.interactionCount}`,
|
|
44
|
+
merged.relationship ? ` Relationship: ${merged.relationship}` : null,
|
|
45
|
+
merged.channels.length > 0 ? ` Channels:\n${channelList}` : null,
|
|
46
|
+
``,
|
|
47
|
+
`Deleted contact: ${mergeContact.displayName} (${mergeId})`,
|
|
48
|
+
].filter(Boolean).join('\n'),
|
|
49
|
+
isError: false,
|
|
50
|
+
};
|
|
51
|
+
} catch (err) {
|
|
52
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
53
|
+
return { content: `Error: ${msg}`, isError: true };
|
|
84
54
|
}
|
|
85
55
|
}
|
|
86
|
-
|
|
87
|
-
registerTool(new ContactMergeTool());
|
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type { Tool, ToolContext, ToolExecutionResult } from '../types.js';
|
|
3
|
-
import type { ToolDefinition } from '../../providers/types.js';
|
|
4
|
-
import { registerTool } from '../registry.js';
|
|
1
|
+
import type { ToolContext, ToolExecutionResult } from '../types.js';
|
|
5
2
|
import { searchContacts } from '../../contacts/contact-store.js';
|
|
6
3
|
import type { ContactWithChannels } from '../../contacts/types.js';
|
|
7
4
|
|
|
@@ -18,85 +15,44 @@ function formatContactSummary(c: ContactWithChannels): string {
|
|
|
18
15
|
return parts.join('\n');
|
|
19
16
|
}
|
|
20
17
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
type: 'string',
|
|
37
|
-
description: 'Filter by channel type when searching by address (email, slack, whatsapp, phone, etc.)',
|
|
38
|
-
},
|
|
39
|
-
relationship: {
|
|
40
|
-
type: 'string',
|
|
41
|
-
description: 'Filter by relationship type (exact match)',
|
|
42
|
-
},
|
|
43
|
-
limit: {
|
|
44
|
-
type: 'number',
|
|
45
|
-
description: 'Maximum results to return (default 20, max 100)',
|
|
46
|
-
},
|
|
47
|
-
},
|
|
48
|
-
required: [],
|
|
49
|
-
},
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
class ContactSearchTool implements Tool {
|
|
53
|
-
name = 'contact_search';
|
|
54
|
-
description = definition.description;
|
|
55
|
-
category = 'contacts';
|
|
56
|
-
defaultRiskLevel = RiskLevel.Low;
|
|
57
|
-
|
|
58
|
-
getDefinition(): ToolDefinition {
|
|
59
|
-
return definition;
|
|
18
|
+
export async function executeContactSearch(
|
|
19
|
+
input: Record<string, unknown>,
|
|
20
|
+
_context: ToolContext,
|
|
21
|
+
): Promise<ToolExecutionResult> {
|
|
22
|
+
const query = input.query as string | undefined;
|
|
23
|
+
const channelAddress = input.channel_address as string | undefined;
|
|
24
|
+
const channelType = input.channel_type as string | undefined;
|
|
25
|
+
const relationship = input.relationship as string | undefined;
|
|
26
|
+
const limit = input.limit as number | undefined;
|
|
27
|
+
|
|
28
|
+
if (!query && !channelAddress && !relationship) {
|
|
29
|
+
return {
|
|
30
|
+
content: 'Error: At least one search criterion is required (query, channel_address, or relationship)',
|
|
31
|
+
isError: true,
|
|
32
|
+
};
|
|
60
33
|
}
|
|
61
34
|
|
|
62
|
-
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
};
|
|
35
|
+
try {
|
|
36
|
+
const results = searchContacts({
|
|
37
|
+
query,
|
|
38
|
+
channelAddress,
|
|
39
|
+
channelType,
|
|
40
|
+
relationship,
|
|
41
|
+
limit,
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
if (results.length === 0) {
|
|
45
|
+
return { content: 'No contacts found matching the search criteria.', isError: false };
|
|
74
46
|
}
|
|
75
47
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
channelAddress,
|
|
80
|
-
channelType,
|
|
81
|
-
relationship,
|
|
82
|
-
limit,
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
if (results.length === 0) {
|
|
86
|
-
return { content: 'No contacts found matching the search criteria.', isError: false };
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
const lines = [`Found ${results.length} contact(s):\n`];
|
|
90
|
-
for (const contact of results) {
|
|
91
|
-
lines.push(formatContactSummary(contact));
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
return { content: lines.join('\n'), isError: false };
|
|
95
|
-
} catch (err) {
|
|
96
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
97
|
-
return { content: `Error: ${msg}`, isError: true };
|
|
48
|
+
const lines = [`Found ${results.length} contact(s):\n`];
|
|
49
|
+
for (const contact of results) {
|
|
50
|
+
lines.push(formatContactSummary(contact));
|
|
98
51
|
}
|
|
52
|
+
|
|
53
|
+
return { content: lines.join('\n'), isError: false };
|
|
54
|
+
} catch (err) {
|
|
55
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
56
|
+
return { content: `Error: ${msg}`, isError: true };
|
|
99
57
|
}
|
|
100
58
|
}
|
|
101
|
-
|
|
102
|
-
registerTool(new ContactSearchTool());
|