vellum 0.2.12 → 0.2.14
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 +32 -0
- package/bun.lock +2 -2
- package/docs/skills.md +4 -4
- package/package.json +2 -2
- package/src/__tests__/__snapshots__/ipc-snapshot.test.ts.snap +213 -3
- package/src/__tests__/app-git-history.test.ts +176 -0
- package/src/__tests__/app-git-service.test.ts +169 -0
- package/src/__tests__/assistant-events-sse-hardening.test.ts +315 -0
- package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +8 -8
- package/src/__tests__/browser-skill-endstate.test.ts +6 -6
- package/src/__tests__/call-bridge.test.ts +105 -13
- package/src/__tests__/call-domain.test.ts +163 -0
- package/src/__tests__/call-orchestrator.test.ts +171 -0
- package/src/__tests__/call-routes-http.test.ts +246 -6
- package/src/__tests__/channel-approval-routes.test.ts +438 -0
- package/src/__tests__/channel-approval.test.ts +266 -0
- package/src/__tests__/channel-approvals.test.ts +393 -0
- package/src/__tests__/channel-delivery-store.test.ts +447 -0
- package/src/__tests__/checker.test.ts +607 -1048
- package/src/__tests__/cli.test.ts +1 -56
- package/src/__tests__/config-schema.test.ts +402 -5
- package/src/__tests__/conflict-intent-tokenization.test.ts +141 -0
- package/src/__tests__/conflict-policy.test.ts +121 -0
- package/src/__tests__/conflict-store.test.ts +2 -0
- package/src/__tests__/contacts-tools.test.ts +3 -3
- package/src/__tests__/contradiction-checker.test.ts +99 -1
- package/src/__tests__/credential-security-invariants.test.ts +22 -6
- package/src/__tests__/credential-vault-unit.test.ts +780 -0
- package/src/__tests__/elevenlabs-client.test.ts +271 -0
- package/src/__tests__/ephemeral-permissions.test.ts +73 -23
- package/src/__tests__/filesystem-tools.test.ts +579 -0
- package/src/__tests__/gateway-only-enforcement.test.ts +114 -4
- package/src/__tests__/handlers-add-trust-rule-metadata.test.ts +202 -0
- package/src/__tests__/handlers-cu-observation-blob.test.ts +2 -1
- package/src/__tests__/handlers-ipc-blob-probe.test.ts +2 -1
- package/src/__tests__/handlers-slack-config.test.ts +2 -1
- package/src/__tests__/handlers-telegram-config.test.ts +855 -0
- package/src/__tests__/handlers-twitter-config.test.ts +141 -1
- package/src/__tests__/hooks-runner.test.ts +6 -2
- package/src/__tests__/host-file-edit-tool.test.ts +124 -0
- package/src/__tests__/host-file-read-tool.test.ts +62 -0
- package/src/__tests__/host-file-write-tool.test.ts +59 -0
- package/src/__tests__/host-shell-tool.test.ts +251 -0
- package/src/__tests__/ingress-reconcile.test.ts +581 -0
- package/src/__tests__/ipc-snapshot.test.ts +100 -41
- package/src/__tests__/ipc-validate.test.ts +50 -0
- package/src/__tests__/key-migration.test.ts +23 -0
- package/src/__tests__/memory-regressions.test.ts +99 -0
- package/src/__tests__/memory-retrieval.benchmark.test.ts +1 -1
- package/src/__tests__/oauth-callback-registry.test.ts +11 -4
- package/src/__tests__/playbook-execution.test.ts +502 -0
- package/src/__tests__/playbook-tools.test.ts +4 -6
- package/src/__tests__/public-ingress-urls.test.ts +34 -0
- package/src/__tests__/qdrant-manager.test.ts +267 -0
- package/src/__tests__/recurrence-engine-rruleset.test.ts +97 -0
- package/src/__tests__/recurrence-engine.test.ts +9 -0
- package/src/__tests__/recurrence-types.test.ts +8 -0
- package/src/__tests__/registry.test.ts +1 -1
- package/src/__tests__/runtime-runs.test.ts +1 -25
- package/src/__tests__/schedule-store.test.ts +16 -14
- package/src/__tests__/schedule-tools.test.ts +83 -0
- package/src/__tests__/scheduler-recurrence.test.ts +111 -10
- package/src/__tests__/secret-allowlist.test.ts +18 -17
- package/src/__tests__/secret-ingress-handler.test.ts +11 -0
- package/src/__tests__/secret-scanner.test.ts +43 -0
- package/src/__tests__/session-conflict-gate.test.ts +442 -6
- package/src/__tests__/session-init.benchmark.test.ts +3 -0
- package/src/__tests__/session-process-bridge.test.ts +242 -0
- package/src/__tests__/session-skill-tools.test.ts +1 -1
- package/src/__tests__/shell-identity.test.ts +256 -0
- package/src/__tests__/skill-projection.benchmark.test.ts +11 -1
- package/src/__tests__/subagent-tools.test.ts +637 -54
- package/src/__tests__/task-management-tools.test.ts +936 -0
- package/src/__tests__/task-runner.test.ts +2 -2
- package/src/__tests__/terminal-tools.test.ts +840 -0
- package/src/__tests__/tool-executor-shell-integration.test.ts +301 -0
- package/src/__tests__/tool-executor.test.ts +85 -151
- package/src/__tests__/tool-permission-simulate-handler.test.ts +336 -0
- package/src/__tests__/trust-store.test.ts +28 -453
- package/src/__tests__/twilio-provider.test.ts +153 -3
- package/src/__tests__/twilio-routes-elevenlabs.test.ts +375 -0
- package/src/__tests__/twilio-routes-twiml.test.ts +127 -0
- package/src/__tests__/twilio-routes.test.ts +17 -262
- package/src/__tests__/twitter-auth-handler.test.ts +2 -1
- package/src/__tests__/twitter-cli-error-shaping.test.ts +208 -0
- package/src/__tests__/twitter-cli-routing.test.ts +252 -0
- package/src/__tests__/twitter-oauth-client.test.ts +209 -0
- package/src/__tests__/workspace-policy.test.ts +213 -0
- package/src/calls/call-bridge.ts +92 -19
- package/src/calls/call-domain.ts +157 -5
- package/src/calls/call-orchestrator.ts +96 -8
- package/src/calls/call-store.ts +6 -0
- package/src/calls/elevenlabs-client.ts +97 -0
- package/src/calls/elevenlabs-config.ts +31 -0
- package/src/calls/twilio-provider.ts +91 -0
- package/src/calls/twilio-routes.ts +50 -6
- package/src/calls/types.ts +3 -1
- package/src/calls/voice-quality.ts +114 -0
- package/src/cli/twitter.ts +200 -21
- package/src/cli.ts +1 -20
- package/src/config/bundled-skills/contacts/tools/contact-merge.ts +52 -4
- package/src/config/bundled-skills/contacts/tools/contact-search.ts +55 -4
- package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +61 -4
- package/src/config/bundled-skills/messaging/SKILL.md +17 -2
- package/src/config/bundled-skills/messaging/tools/messaging-reply.ts +4 -1
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +5 -1
- package/src/config/bundled-skills/messaging/tools/shared.ts +5 -0
- package/src/config/bundled-skills/phone-calls/SKILL.md +207 -19
- package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +95 -6
- package/src/config/bundled-skills/playbooks/tools/playbook-delete.ts +51 -6
- package/src/config/bundled-skills/playbooks/tools/playbook-list.ts +73 -6
- package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +110 -6
- package/src/config/bundled-skills/public-ingress/SKILL.md +22 -5
- package/src/config/bundled-skills/twitter/SKILL.md +103 -17
- package/src/config/defaults.ts +26 -2
- package/src/config/schema.ts +178 -9
- package/src/config/types.ts +3 -0
- package/src/config/vellum-skills/telegram-setup/SKILL.md +56 -61
- package/src/daemon/assistant-attachments.ts +4 -2
- package/src/daemon/handlers/apps.ts +69 -0
- package/src/daemon/handlers/config.ts +543 -24
- package/src/daemon/handlers/index.ts +1 -0
- package/src/daemon/handlers/sessions.ts +22 -6
- package/src/daemon/handlers/shared.ts +2 -1
- package/src/daemon/handlers/skills.ts +5 -20
- package/src/daemon/ipc-contract-inventory.json +28 -0
- package/src/daemon/ipc-contract.ts +168 -10
- package/src/daemon/ipc-validate.ts +17 -0
- package/src/daemon/lifecycle.ts +2 -0
- package/src/daemon/server.ts +78 -72
- package/src/daemon/session-attachments.ts +1 -1
- package/src/daemon/session-conflict-gate.ts +62 -6
- package/src/daemon/session-notifiers.ts +1 -1
- package/src/daemon/session-process.ts +62 -3
- package/src/daemon/session-tool-setup.ts +1 -2
- package/src/daemon/tls-certs.ts +189 -0
- package/src/daemon/video-thumbnail.ts +5 -3
- package/src/hooks/manager.ts +5 -9
- package/src/memory/app-git-service.ts +295 -0
- package/src/memory/app-store.ts +21 -0
- package/src/memory/conflict-intent.ts +47 -4
- package/src/memory/conflict-policy.ts +73 -0
- package/src/memory/conflict-store.ts +9 -1
- package/src/memory/contradiction-checker.ts +28 -0
- package/src/memory/conversation-key-store.ts +15 -0
- package/src/memory/db.ts +81 -0
- package/src/memory/embedding-local.ts +3 -13
- package/src/memory/external-conversation-store.ts +234 -0
- package/src/memory/job-handlers/conflict.ts +22 -2
- package/src/memory/jobs-worker.ts +67 -28
- package/src/memory/runs-store.ts +54 -7
- package/src/memory/schema.ts +20 -0
- package/src/messaging/provider.ts +9 -0
- package/src/messaging/providers/telegram-bot/adapter.ts +162 -0
- package/src/messaging/providers/telegram-bot/client.ts +104 -0
- package/src/messaging/providers/telegram-bot/types.ts +15 -0
- package/src/messaging/registry.ts +1 -0
- package/src/permissions/checker.ts +48 -44
- package/src/permissions/defaults.ts +11 -0
- package/src/permissions/prompter.ts +0 -4
- package/src/permissions/shell-identity.ts +227 -0
- package/src/permissions/trust-store.ts +76 -53
- package/src/permissions/types.ts +0 -19
- package/src/permissions/workspace-policy.ts +114 -0
- package/src/providers/retry.ts +12 -37
- package/src/runtime/assistant-event-hub.ts +41 -4
- package/src/runtime/channel-approval-parser.ts +60 -0
- package/src/runtime/channel-approval-types.ts +71 -0
- package/src/runtime/channel-approvals.ts +145 -0
- package/src/runtime/gateway-client.ts +16 -0
- package/src/runtime/http-server.ts +29 -9
- package/src/runtime/routes/call-routes.ts +52 -2
- package/src/runtime/routes/channel-routes.ts +296 -16
- package/src/runtime/routes/conversation-routes.ts +12 -5
- package/src/runtime/routes/events-routes.ts +97 -28
- package/src/runtime/routes/run-routes.ts +2 -7
- package/src/runtime/run-orchestrator.ts +0 -3
- package/src/schedule/recurrence-engine.ts +26 -2
- package/src/schedule/recurrence-types.ts +1 -1
- package/src/schedule/schedule-store.ts +12 -3
- package/src/security/secret-scanner.ts +7 -0
- package/src/tasks/ephemeral-permissions.ts +0 -2
- package/src/tasks/task-scheduler.ts +2 -1
- package/src/tools/calls/call-start.ts +8 -0
- package/src/tools/execution-target.ts +21 -0
- package/src/tools/execution-timeout.ts +49 -0
- package/src/tools/executor.ts +6 -135
- package/src/tools/network/web-search.ts +9 -32
- package/src/tools/policy-context.ts +29 -0
- package/src/tools/schedule/update.ts +8 -1
- package/src/tools/terminal/parser.ts +16 -18
- package/src/tools/types.ts +4 -11
- package/src/twitter/oauth-client.ts +102 -0
- package/src/twitter/router.ts +101 -0
- package/src/util/debounce.ts +88 -0
- package/src/util/network-info.ts +47 -0
- package/src/util/platform.ts +29 -4
- package/src/util/promise-guard.ts +37 -0
- package/src/util/retry.ts +98 -0
- package/src/util/truncate.ts +1 -1
- package/src/workspace/git-service.ts +129 -112
- package/src/tools/contacts/contact-merge.ts +0 -55
- package/src/tools/contacts/contact-search.ts +0 -58
- package/src/tools/contacts/contact-upsert.ts +0 -64
- package/src/tools/playbooks/index.ts +0 -4
- package/src/tools/playbooks/playbook-create.ts +0 -96
- package/src/tools/playbooks/playbook-delete.ts +0 -52
- package/src/tools/playbooks/playbook-list.ts +0 -74
- package/src/tools/playbooks/playbook-update.ts +0 -111
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
import { and, eq } from 'drizzle-orm';
|
|
2
|
-
import { v4 as uuid } from 'uuid';
|
|
3
|
-
import type { ToolContext, ToolExecutionResult } from '../types.js';
|
|
4
|
-
import { getDb } from '../../memory/db.js';
|
|
5
|
-
import { computeMemoryFingerprint } from '../../memory/fingerprint.js';
|
|
6
|
-
import { memoryItems } from '../../memory/schema.js';
|
|
7
|
-
import { enqueueMemoryJob } from '../../memory/jobs-store.js';
|
|
8
|
-
import type { Playbook, PlaybookAutonomyLevel } from '../../playbooks/types.js';
|
|
9
|
-
import { truncate } from '../../util/truncate.js';
|
|
10
|
-
|
|
11
|
-
const VALID_AUTONOMY_LEVELS = new Set<string>(['auto', 'draft', 'notify']);
|
|
12
|
-
|
|
13
|
-
export async function executePlaybookCreate(input: Record<string, unknown>, context: ToolContext): Promise<ToolExecutionResult> {
|
|
14
|
-
const trigger = input.trigger as string;
|
|
15
|
-
const action = input.action as string;
|
|
16
|
-
|
|
17
|
-
if (!trigger || typeof trigger !== 'string') {
|
|
18
|
-
return { content: 'Error: trigger is required and must be a string', isError: true };
|
|
19
|
-
}
|
|
20
|
-
if (!action || typeof action !== 'string') {
|
|
21
|
-
return { content: 'Error: action is required and must be a string', isError: true };
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
const channel = typeof input.channel === 'string' ? input.channel : '*';
|
|
25
|
-
const category = typeof input.category === 'string' ? input.category : 'general';
|
|
26
|
-
const autonomyLevel: PlaybookAutonomyLevel =
|
|
27
|
-
typeof input.autonomy_level === 'string' && VALID_AUTONOMY_LEVELS.has(input.autonomy_level)
|
|
28
|
-
? (input.autonomy_level as PlaybookAutonomyLevel)
|
|
29
|
-
: 'draft';
|
|
30
|
-
const priority = typeof input.priority === 'number' ? input.priority : 0;
|
|
31
|
-
|
|
32
|
-
const playbook: Playbook = { trigger, channel, category, action, autonomyLevel, priority };
|
|
33
|
-
const statement = JSON.stringify(playbook);
|
|
34
|
-
const subject = truncate(`Playbook: ${trigger}`, 80, '');
|
|
35
|
-
const scopeId = context.memoryScopeId ?? 'default';
|
|
36
|
-
|
|
37
|
-
const fingerprint = computeMemoryFingerprint(scopeId, 'playbook', subject, statement);
|
|
38
|
-
|
|
39
|
-
try {
|
|
40
|
-
const db = getDb();
|
|
41
|
-
|
|
42
|
-
const existing = db
|
|
43
|
-
.select()
|
|
44
|
-
.from(memoryItems)
|
|
45
|
-
.where(and(eq(memoryItems.fingerprint, fingerprint), eq(memoryItems.scopeId, scopeId)))
|
|
46
|
-
.get();
|
|
47
|
-
|
|
48
|
-
if (existing) {
|
|
49
|
-
return {
|
|
50
|
-
content: `A playbook with this exact configuration already exists (ID: ${existing.id}).`,
|
|
51
|
-
isError: false,
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
const id = uuid();
|
|
56
|
-
const now = Date.now();
|
|
57
|
-
|
|
58
|
-
db.insert(memoryItems).values({
|
|
59
|
-
id,
|
|
60
|
-
kind: 'playbook',
|
|
61
|
-
subject,
|
|
62
|
-
statement,
|
|
63
|
-
status: 'active',
|
|
64
|
-
confidence: 0.95,
|
|
65
|
-
importance: 0.8,
|
|
66
|
-
fingerprint,
|
|
67
|
-
verificationState: 'user_confirmed',
|
|
68
|
-
scopeId,
|
|
69
|
-
firstSeenAt: now,
|
|
70
|
-
lastSeenAt: now,
|
|
71
|
-
lastUsedAt: null,
|
|
72
|
-
}).run();
|
|
73
|
-
|
|
74
|
-
enqueueMemoryJob('embed_item', { itemId: id });
|
|
75
|
-
|
|
76
|
-
const autonomyLabel = autonomyLevel === 'auto' ? 'execute automatically'
|
|
77
|
-
: autonomyLevel === 'draft' ? 'draft for review' : 'notify only';
|
|
78
|
-
|
|
79
|
-
return {
|
|
80
|
-
content: [
|
|
81
|
-
'Playbook created successfully.',
|
|
82
|
-
` ID: ${id}`,
|
|
83
|
-
` Trigger: ${trigger}`,
|
|
84
|
-
` Channel: ${channel}`,
|
|
85
|
-
` Category: ${category}`,
|
|
86
|
-
` Action: ${action}`,
|
|
87
|
-
` Autonomy: ${autonomyLabel}`,
|
|
88
|
-
` Priority: ${priority}`,
|
|
89
|
-
].join('\n'),
|
|
90
|
-
isError: false,
|
|
91
|
-
};
|
|
92
|
-
} catch (err) {
|
|
93
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
94
|
-
return { content: `Error creating playbook: ${msg}`, isError: true };
|
|
95
|
-
}
|
|
96
|
-
}
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import { and, eq } from 'drizzle-orm';
|
|
2
|
-
import type { ToolContext, ToolExecutionResult } from '../types.js';
|
|
3
|
-
import { getDb } from '../../memory/db.js';
|
|
4
|
-
import { memoryItems } from '../../memory/schema.js';
|
|
5
|
-
import { parsePlaybookStatement } from '../../playbooks/types.js';
|
|
6
|
-
|
|
7
|
-
export async function executePlaybookDelete(input: Record<string, unknown>, context: ToolContext): Promise<ToolExecutionResult> {
|
|
8
|
-
const playbookId = input.playbook_id as string;
|
|
9
|
-
if (!playbookId || typeof playbookId !== 'string') {
|
|
10
|
-
return { content: 'Error: playbook_id is required and must be a string', isError: true };
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
const scopeId = context.memoryScopeId ?? 'default';
|
|
14
|
-
|
|
15
|
-
try {
|
|
16
|
-
const db = getDb();
|
|
17
|
-
|
|
18
|
-
const existing = db
|
|
19
|
-
.select()
|
|
20
|
-
.from(memoryItems)
|
|
21
|
-
.where(and(
|
|
22
|
-
eq(memoryItems.id, playbookId),
|
|
23
|
-
eq(memoryItems.kind, 'playbook'),
|
|
24
|
-
eq(memoryItems.scopeId, scopeId),
|
|
25
|
-
))
|
|
26
|
-
.get();
|
|
27
|
-
|
|
28
|
-
if (!existing) {
|
|
29
|
-
return { content: `Error: Playbook with ID "${playbookId}" not found`, isError: true };
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const playbook = parsePlaybookStatement(existing.statement);
|
|
33
|
-
const triggerLabel = playbook?.trigger ?? existing.subject;
|
|
34
|
-
|
|
35
|
-
// Soft-delete by marking as superseded rather than hard-deleting,
|
|
36
|
-
// consistent with how other memory items are retired.
|
|
37
|
-
// Setting invalidAt so the cleanup job can eventually hard-delete it.
|
|
38
|
-
const now = Date.now();
|
|
39
|
-
db.update(memoryItems)
|
|
40
|
-
.set({ status: 'superseded', invalidAt: now })
|
|
41
|
-
.where(eq(memoryItems.id, existing.id))
|
|
42
|
-
.run();
|
|
43
|
-
|
|
44
|
-
return {
|
|
45
|
-
content: `Playbook deleted (ID: ${existing.id}, trigger: "${triggerLabel}").`,
|
|
46
|
-
isError: false,
|
|
47
|
-
};
|
|
48
|
-
} catch (err) {
|
|
49
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
50
|
-
return { content: `Error deleting playbook: ${msg}`, isError: true };
|
|
51
|
-
}
|
|
52
|
-
}
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
import { and, desc, eq, isNull } from 'drizzle-orm';
|
|
2
|
-
import type { ToolContext, ToolExecutionResult } from '../types.js';
|
|
3
|
-
import { getDb } from '../../memory/db.js';
|
|
4
|
-
import { memoryItems } from '../../memory/schema.js';
|
|
5
|
-
import { parsePlaybookStatement } from '../../playbooks/types.js';
|
|
6
|
-
|
|
7
|
-
export async function executePlaybookList(input: Record<string, unknown>, context: ToolContext): Promise<ToolExecutionResult> {
|
|
8
|
-
const scopeId = context.memoryScopeId ?? 'default';
|
|
9
|
-
const channelFilter = typeof input.channel === 'string' ? input.channel : null;
|
|
10
|
-
const categoryFilter = typeof input.category === 'string' ? input.category : null;
|
|
11
|
-
|
|
12
|
-
try {
|
|
13
|
-
const db = getDb();
|
|
14
|
-
|
|
15
|
-
const rows = db
|
|
16
|
-
.select({
|
|
17
|
-
id: memoryItems.id,
|
|
18
|
-
subject: memoryItems.subject,
|
|
19
|
-
statement: memoryItems.statement,
|
|
20
|
-
importance: memoryItems.importance,
|
|
21
|
-
lastSeenAt: memoryItems.lastSeenAt,
|
|
22
|
-
})
|
|
23
|
-
.from(memoryItems)
|
|
24
|
-
.where(and(
|
|
25
|
-
eq(memoryItems.kind, 'playbook'),
|
|
26
|
-
eq(memoryItems.status, 'active'),
|
|
27
|
-
eq(memoryItems.scopeId, scopeId),
|
|
28
|
-
isNull(memoryItems.invalidAt),
|
|
29
|
-
))
|
|
30
|
-
.orderBy(desc(memoryItems.importance))
|
|
31
|
-
.all();
|
|
32
|
-
|
|
33
|
-
if (rows.length === 0) {
|
|
34
|
-
return { content: 'No playbooks found.', isError: false };
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const entries: Array<{ id: string; subject: string; statement: string; playbook: NonNullable<ReturnType<typeof parsePlaybookStatement>> }> = [];
|
|
38
|
-
for (const row of rows) {
|
|
39
|
-
const playbook = parsePlaybookStatement(row.statement);
|
|
40
|
-
if (!playbook) continue;
|
|
41
|
-
|
|
42
|
-
// Apply filters
|
|
43
|
-
if (channelFilter && playbook.channel !== channelFilter && playbook.channel !== '*') continue;
|
|
44
|
-
if (categoryFilter && playbook.category !== categoryFilter) continue;
|
|
45
|
-
|
|
46
|
-
entries.push({ id: row.id, subject: row.subject, statement: row.statement, playbook });
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
if (entries.length === 0) {
|
|
50
|
-
const filters = [
|
|
51
|
-
channelFilter ? `channel="${channelFilter}"` : null,
|
|
52
|
-
categoryFilter ? `category="${categoryFilter}"` : null,
|
|
53
|
-
].filter(Boolean).join(', ');
|
|
54
|
-
return { content: `No playbooks found matching ${filters}.`, isError: false };
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// Sort by priority descending
|
|
58
|
-
entries.sort((a, b) => b.playbook.priority - a.playbook.priority);
|
|
59
|
-
|
|
60
|
-
const lines: string[] = [`Found ${entries.length} playbook(s):\n`];
|
|
61
|
-
for (const { id, playbook } of entries) {
|
|
62
|
-
const channelLabel = playbook.channel === '*' ? 'all channels' : playbook.channel;
|
|
63
|
-
const autonomyLabel = playbook.autonomyLevel === 'auto' ? 'auto'
|
|
64
|
-
: playbook.autonomyLevel === 'draft' ? 'draft' : 'notify';
|
|
65
|
-
lines.push(`- **${playbook.trigger}** (${channelLabel}) → ${playbook.action}`);
|
|
66
|
-
lines.push(` _ID: ${id} | category: ${playbook.category} | autonomy: ${autonomyLabel} | priority: ${playbook.priority}_`);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
return { content: lines.join('\n'), isError: false };
|
|
70
|
-
} catch (err) {
|
|
71
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
72
|
-
return { content: `Error listing playbooks: ${msg}`, isError: true };
|
|
73
|
-
}
|
|
74
|
-
}
|
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
import { and, eq } from 'drizzle-orm';
|
|
2
|
-
import type { ToolContext, ToolExecutionResult } from '../types.js';
|
|
3
|
-
import { getDb } from '../../memory/db.js';
|
|
4
|
-
import { computeMemoryFingerprint } from '../../memory/fingerprint.js';
|
|
5
|
-
import { memoryItems } from '../../memory/schema.js';
|
|
6
|
-
import { enqueueMemoryJob } from '../../memory/jobs-store.js';
|
|
7
|
-
import { parsePlaybookStatement } from '../../playbooks/types.js';
|
|
8
|
-
import type { Playbook, PlaybookAutonomyLevel } from '../../playbooks/types.js';
|
|
9
|
-
import { truncate } from '../../util/truncate.js';
|
|
10
|
-
|
|
11
|
-
const VALID_AUTONOMY_LEVELS = new Set<string>(['auto', 'draft', 'notify']);
|
|
12
|
-
|
|
13
|
-
export async function executePlaybookUpdate(input: Record<string, unknown>, context: ToolContext): Promise<ToolExecutionResult> {
|
|
14
|
-
const playbookId = input.playbook_id as string;
|
|
15
|
-
if (!playbookId || typeof playbookId !== 'string') {
|
|
16
|
-
return { content: 'Error: playbook_id is required and must be a string', isError: true };
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
const scopeId = context.memoryScopeId ?? 'default';
|
|
20
|
-
|
|
21
|
-
try {
|
|
22
|
-
const db = getDb();
|
|
23
|
-
|
|
24
|
-
const existing = db
|
|
25
|
-
.select()
|
|
26
|
-
.from(memoryItems)
|
|
27
|
-
.where(and(
|
|
28
|
-
eq(memoryItems.id, playbookId),
|
|
29
|
-
eq(memoryItems.kind, 'playbook'),
|
|
30
|
-
eq(memoryItems.scopeId, scopeId),
|
|
31
|
-
))
|
|
32
|
-
.get();
|
|
33
|
-
|
|
34
|
-
if (!existing) {
|
|
35
|
-
return { content: `Error: Playbook with ID "${playbookId}" not found`, isError: true };
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const currentPlaybook = parsePlaybookStatement(existing.statement);
|
|
39
|
-
if (!currentPlaybook) {
|
|
40
|
-
return { content: `Error: Playbook data is corrupted for ID "${playbookId}"`, isError: true };
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// Merge updates onto existing playbook
|
|
44
|
-
const updated: Playbook = {
|
|
45
|
-
trigger: typeof input.trigger === 'string' ? input.trigger : currentPlaybook.trigger,
|
|
46
|
-
channel: typeof input.channel === 'string' ? input.channel : currentPlaybook.channel,
|
|
47
|
-
category: typeof input.category === 'string' ? input.category : currentPlaybook.category,
|
|
48
|
-
action: typeof input.action === 'string' ? input.action : currentPlaybook.action,
|
|
49
|
-
autonomyLevel:
|
|
50
|
-
typeof input.autonomy_level === 'string' && VALID_AUTONOMY_LEVELS.has(input.autonomy_level)
|
|
51
|
-
? (input.autonomy_level as PlaybookAutonomyLevel)
|
|
52
|
-
: currentPlaybook.autonomyLevel,
|
|
53
|
-
priority: typeof input.priority === 'number' ? input.priority : currentPlaybook.priority,
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
const statement = JSON.stringify(updated);
|
|
57
|
-
const subject = truncate(`Playbook: ${updated.trigger}`, 80, '');
|
|
58
|
-
const now = Date.now();
|
|
59
|
-
|
|
60
|
-
const fingerprint = computeMemoryFingerprint(scopeId, 'playbook', subject, statement);
|
|
61
|
-
|
|
62
|
-
// Check if another playbook already has this fingerprint
|
|
63
|
-
const collision = db
|
|
64
|
-
.select({ id: memoryItems.id })
|
|
65
|
-
.from(memoryItems)
|
|
66
|
-
.where(and(
|
|
67
|
-
eq(memoryItems.fingerprint, fingerprint),
|
|
68
|
-
eq(memoryItems.scopeId, scopeId),
|
|
69
|
-
))
|
|
70
|
-
.get();
|
|
71
|
-
if (collision && collision.id !== existing.id) {
|
|
72
|
-
return {
|
|
73
|
-
content: `Error: Another playbook with this exact configuration already exists (ID: ${collision.id}).`,
|
|
74
|
-
isError: true,
|
|
75
|
-
};
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
db.update(memoryItems)
|
|
79
|
-
.set({
|
|
80
|
-
subject,
|
|
81
|
-
statement,
|
|
82
|
-
fingerprint,
|
|
83
|
-
lastSeenAt: now,
|
|
84
|
-
verificationState: 'user_confirmed',
|
|
85
|
-
})
|
|
86
|
-
.where(eq(memoryItems.id, existing.id))
|
|
87
|
-
.run();
|
|
88
|
-
|
|
89
|
-
enqueueMemoryJob('embed_item', { itemId: existing.id });
|
|
90
|
-
|
|
91
|
-
const autonomyLabel = updated.autonomyLevel === 'auto' ? 'execute automatically'
|
|
92
|
-
: updated.autonomyLevel === 'draft' ? 'draft for review' : 'notify only';
|
|
93
|
-
|
|
94
|
-
return {
|
|
95
|
-
content: [
|
|
96
|
-
'Playbook updated successfully.',
|
|
97
|
-
` ID: ${existing.id}`,
|
|
98
|
-
` Trigger: ${updated.trigger}`,
|
|
99
|
-
` Channel: ${updated.channel}`,
|
|
100
|
-
` Category: ${updated.category}`,
|
|
101
|
-
` Action: ${updated.action}`,
|
|
102
|
-
` Autonomy: ${autonomyLabel}`,
|
|
103
|
-
` Priority: ${updated.priority}`,
|
|
104
|
-
].join('\n'),
|
|
105
|
-
isError: false,
|
|
106
|
-
};
|
|
107
|
-
} catch (err) {
|
|
108
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
109
|
-
return { content: `Error updating playbook: ${msg}`, isError: true };
|
|
110
|
-
}
|
|
111
|
-
}
|