@vellumai/assistant 0.3.18 → 0.3.20
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 +155 -15
- package/Dockerfile +1 -0
- package/README.md +40 -4
- package/docs/architecture/integrations.md +7 -11
- package/docs/architecture/security.md +80 -0
- package/package.json +1 -1
- package/src/__tests__/__snapshots__/ipc-snapshot.test.ts.snap +58 -0
- package/src/__tests__/approval-primitive.test.ts +540 -0
- package/src/__tests__/assistant-feature-flag-guard.test.ts +206 -0
- package/src/__tests__/assistant-feature-flag-guardrails.test.ts +198 -0
- package/src/__tests__/assistant-feature-flags-integration.test.ts +272 -0
- package/src/__tests__/call-controller.test.ts +605 -104
- package/src/__tests__/channel-invite-transport.test.ts +264 -0
- package/src/__tests__/checker.test.ts +60 -0
- package/src/__tests__/cli.test.ts +42 -1
- package/src/__tests__/config-schema.test.ts +11 -127
- package/src/__tests__/config-watcher.test.ts +0 -8
- package/src/__tests__/daemon-lifecycle.test.ts +1 -0
- package/src/__tests__/daemon-server-session-init.test.ts +8 -2
- package/src/__tests__/diff.test.ts +22 -0
- package/src/__tests__/guardian-action-copy-generator.test.ts +5 -0
- package/src/__tests__/guardian-action-grant-mint-consume.test.ts +779 -0
- package/src/__tests__/guardian-action-late-reply.test.ts +546 -1
- package/src/__tests__/guardian-actions-endpoint.test.ts +774 -0
- package/src/__tests__/guardian-control-plane-policy.test.ts +36 -3
- package/src/__tests__/guardian-dispatch.test.ts +185 -1
- package/src/__tests__/guardian-grant-minting.test.ts +532 -0
- package/src/__tests__/inbound-invite-redemption.test.ts +367 -0
- package/src/__tests__/invite-redemption-service.test.ts +306 -0
- package/src/__tests__/ipc-snapshot.test.ts +58 -0
- package/src/__tests__/notification-decision-fallback.test.ts +88 -0
- package/src/__tests__/remote-skill-policy.test.ts +215 -0
- package/src/__tests__/sandbox-diagnostics.test.ts +6 -249
- package/src/__tests__/sandbox-host-parity.test.ts +6 -13
- package/src/__tests__/scoped-approval-grants.test.ts +521 -0
- package/src/__tests__/scoped-grant-security-matrix.test.ts +444 -0
- package/src/__tests__/script-proxy-session-manager.test.ts +1 -19
- package/src/__tests__/session-load-history-repair.test.ts +169 -2
- package/src/__tests__/session-runtime-assembly.test.ts +33 -5
- package/src/__tests__/skill-feature-flags-integration.test.ts +171 -0
- package/src/__tests__/skill-feature-flags.test.ts +188 -0
- package/src/__tests__/skill-load-feature-flag.test.ts +141 -0
- package/src/__tests__/skill-mirror-parity.test.ts +1 -0
- package/src/__tests__/skill-projection-feature-flag.test.ts +363 -0
- package/src/__tests__/system-prompt.test.ts +1 -1
- package/src/__tests__/terminal-sandbox.test.ts +142 -9
- package/src/__tests__/terminal-tools.test.ts +2 -93
- package/src/__tests__/thread-seed-composer.test.ts +18 -0
- package/src/__tests__/tool-approval-handler.test.ts +350 -0
- package/src/__tests__/trust-store.test.ts +2 -0
- package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +8 -10
- package/src/__tests__/voice-scoped-grant-consumer.test.ts +533 -0
- package/src/agent/loop.ts +36 -1
- package/src/approvals/approval-primitive.ts +381 -0
- package/src/approvals/guardian-decision-primitive.ts +191 -0
- package/src/calls/call-controller.ts +276 -212
- package/src/calls/call-domain.ts +56 -6
- package/src/calls/guardian-dispatch.ts +56 -0
- package/src/calls/relay-server.ts +13 -0
- package/src/calls/types.ts +1 -1
- package/src/calls/voice-session-bridge.ts +59 -4
- package/src/cli/core-commands.ts +0 -4
- package/src/cli.ts +76 -34
- package/src/config/__tests__/feature-flag-registry-guard.test.ts +179 -0
- package/src/config/assistant-feature-flags.ts +162 -0
- package/src/config/bundled-skills/api-mapping/icon.svg +18 -0
- package/src/config/bundled-skills/messaging/TOOLS.json +30 -0
- package/src/config/bundled-skills/messaging/tools/slack-delete-message.ts +24 -0
- package/src/config/bundled-skills/notifications/SKILL.md +18 -0
- package/src/config/bundled-skills/reminder/SKILL.md +49 -2
- package/src/config/bundled-skills/time-based-actions/SKILL.md +49 -2
- package/src/config/bundled-skills/voice-setup/SKILL.md +122 -0
- package/src/config/core-schema.ts +1 -1
- package/src/config/env-registry.ts +10 -0
- package/src/config/feature-flag-registry.json +61 -0
- package/src/config/loader.ts +22 -1
- package/src/config/sandbox-schema.ts +0 -39
- package/src/config/schema.ts +12 -2
- package/src/config/skill-state.ts +34 -0
- package/src/config/skills-schema.ts +26 -0
- package/src/config/skills.ts +9 -0
- package/src/config/system-prompt.ts +110 -46
- package/src/config/templates/SOUL.md +1 -1
- package/src/config/types.ts +19 -1
- package/src/config/vellum-skills/catalog.json +1 -1
- package/src/config/vellum-skills/guardian-verify-setup/SKILL.md +1 -0
- package/src/config/vellum-skills/sms-setup/SKILL.md +1 -1
- package/src/config/vellum-skills/telegram-setup/SKILL.md +1 -1
- package/src/config/vellum-skills/trusted-contacts/SKILL.md +104 -3
- package/src/config/vellum-skills/twilio-setup/SKILL.md +1 -1
- package/src/daemon/config-watcher.ts +0 -1
- package/src/daemon/daemon-control.ts +1 -1
- package/src/daemon/guardian-invite-intent.ts +124 -0
- package/src/daemon/handlers/avatar.ts +68 -0
- package/src/daemon/handlers/browser.ts +2 -2
- package/src/daemon/handlers/config-channels.ts +18 -0
- package/src/daemon/handlers/guardian-actions.ts +120 -0
- package/src/daemon/handlers/index.ts +4 -0
- package/src/daemon/handlers/sessions.ts +19 -0
- package/src/daemon/handlers/shared.ts +3 -1
- package/src/daemon/handlers/skills.ts +45 -2
- package/src/daemon/install-cli-launchers.ts +58 -13
- package/src/daemon/ipc-contract/guardian-actions.ts +53 -0
- package/src/daemon/ipc-contract/sessions.ts +8 -2
- package/src/daemon/ipc-contract/settings.ts +25 -2
- package/src/daemon/ipc-contract/skills.ts +1 -0
- package/src/daemon/ipc-contract-inventory.json +10 -0
- package/src/daemon/ipc-contract.ts +4 -0
- package/src/daemon/lifecycle.ts +6 -2
- package/src/daemon/main.ts +1 -0
- package/src/daemon/server.ts +1 -0
- package/src/daemon/session-lifecycle.ts +52 -7
- package/src/daemon/session-memory.ts +45 -0
- package/src/daemon/session-process.ts +260 -422
- package/src/daemon/session-runtime-assembly.ts +12 -0
- package/src/daemon/session-skill-tools.ts +14 -1
- package/src/daemon/session-tool-setup.ts +5 -0
- package/src/daemon/session.ts +11 -0
- package/src/daemon/tool-side-effects.ts +35 -9
- package/src/index.ts +0 -2
- package/src/memory/conversation-display-order-migration.ts +44 -0
- package/src/memory/conversation-queries.ts +2 -0
- package/src/memory/conversation-store.ts +91 -0
- package/src/memory/db-init.ts +13 -1
- package/src/memory/embedding-local.ts +22 -8
- package/src/memory/guardian-action-store.ts +133 -2
- package/src/memory/guardian-verification.ts +1 -1
- package/src/memory/ingress-invite-store.ts +95 -1
- package/src/memory/migrations/033-scoped-approval-grants.ts +51 -0
- package/src/memory/migrations/034-guardian-action-tool-metadata.ts +12 -0
- package/src/memory/migrations/035-guardian-action-supersession.ts +23 -0
- package/src/memory/migrations/index.ts +3 -0
- package/src/memory/schema.ts +35 -1
- package/src/memory/scoped-approval-grants.ts +518 -0
- package/src/messaging/providers/slack/client.ts +12 -0
- package/src/messaging/providers/slack/types.ts +5 -0
- package/src/notifications/decision-engine.ts +49 -12
- package/src/notifications/emit-signal.ts +7 -0
- package/src/notifications/signal.ts +7 -0
- package/src/notifications/thread-seed-composer.ts +2 -1
- package/src/permissions/checker.ts +27 -0
- package/src/runtime/channel-approval-types.ts +16 -6
- package/src/runtime/channel-approvals.ts +19 -15
- package/src/runtime/channel-invite-transport.ts +85 -0
- package/src/runtime/channel-invite-transports/telegram.ts +105 -0
- package/src/runtime/guardian-action-grant-minter.ts +154 -0
- package/src/runtime/guardian-action-message-composer.ts +30 -0
- package/src/runtime/guardian-decision-types.ts +91 -0
- package/src/runtime/http-server.ts +23 -1
- package/src/runtime/ingress-service.ts +22 -0
- package/src/runtime/invite-redemption-service.ts +181 -0
- package/src/runtime/invite-redemption-templates.ts +39 -0
- package/src/runtime/routes/call-routes.ts +2 -1
- package/src/runtime/routes/guardian-action-routes.ts +206 -0
- package/src/runtime/routes/guardian-approval-interception.ts +66 -74
- package/src/runtime/routes/inbound-message-handler.ts +568 -409
- package/src/runtime/routes/pairing-routes.ts +4 -0
- package/src/security/encrypted-store.ts +31 -17
- package/src/security/keychain.ts +176 -2
- package/src/security/secure-keys.ts +97 -0
- package/src/security/tool-approval-digest.ts +67 -0
- package/src/skills/remote-skill-policy.ts +131 -0
- package/src/tools/browser/browser-execution.ts +2 -2
- package/src/tools/browser/browser-manager.ts +46 -32
- package/src/tools/browser/browser-screencast.ts +2 -2
- package/src/tools/calls/call-start.ts +1 -1
- package/src/tools/executor.ts +22 -17
- package/src/tools/network/script-proxy/session-manager.ts +1 -5
- package/src/tools/skills/load.ts +22 -8
- package/src/tools/system/avatar-generator.ts +119 -0
- package/src/tools/system/navigate-settings.ts +65 -0
- package/src/tools/system/open-system-settings.ts +75 -0
- package/src/tools/system/voice-config.ts +121 -32
- package/src/tools/terminal/backends/native.ts +40 -19
- package/src/tools/terminal/backends/types.ts +3 -3
- package/src/tools/terminal/parser.ts +1 -1
- package/src/tools/terminal/sandbox-diagnostics.ts +6 -87
- package/src/tools/terminal/sandbox.ts +1 -12
- package/src/tools/terminal/shell.ts +3 -31
- package/src/tools/tool-approval-handler.ts +141 -3
- package/src/tools/tool-manifest.ts +6 -0
- package/src/tools/types.ts +6 -0
- package/src/util/diff.ts +36 -13
- package/Dockerfile.sandbox +0 -5
- package/src/__tests__/doordash-client.test.ts +0 -187
- package/src/__tests__/doordash-session.test.ts +0 -154
- package/src/__tests__/signup-e2e.test.ts +0 -354
- package/src/__tests__/terminal-sandbox-docker.test.ts +0 -1065
- package/src/__tests__/terminal-sandbox.integration.test.ts +0 -180
- package/src/cli/doordash.ts +0 -1057
- package/src/config/bundled-skills/doordash/SKILL.md +0 -163
- package/src/config/templates/LOOKS.md +0 -25
- package/src/doordash/cart-queries.ts +0 -787
- package/src/doordash/client.ts +0 -1016
- package/src/doordash/order-queries.ts +0 -85
- package/src/doordash/queries.ts +0 -13
- package/src/doordash/query-extractor.ts +0 -94
- package/src/doordash/search-queries.ts +0 -203
- package/src/doordash/session.ts +0 -84
- package/src/doordash/store-queries.ts +0 -246
- package/src/doordash/types.ts +0 -367
- package/src/tools/terminal/backends/docker.ts +0 -379
|
@@ -66,7 +66,7 @@ const DEFAULT_EXPIRY_MS = 7 * 24 * 60 * 60 * 1000; // 7 days
|
|
|
66
66
|
// Helpers
|
|
67
67
|
// ---------------------------------------------------------------------------
|
|
68
68
|
|
|
69
|
-
function hashToken(rawToken: string): string {
|
|
69
|
+
export function hashToken(rawToken: string): string {
|
|
70
70
|
return createHash('sha256').update(rawToken).digest('hex');
|
|
71
71
|
}
|
|
72
72
|
|
|
@@ -268,6 +268,12 @@ export function redeemInvite(params: {
|
|
|
268
268
|
return { error: 'invite_max_uses_reached' };
|
|
269
269
|
}
|
|
270
270
|
|
|
271
|
+
// Enforce channel-scoped redemption: when the caller specifies a channel, it
|
|
272
|
+
// must match the channel the invite was created for.
|
|
273
|
+
if (params.sourceChannel && params.sourceChannel !== invite.sourceChannel) {
|
|
274
|
+
return { error: 'invite_channel_mismatch' };
|
|
275
|
+
}
|
|
276
|
+
|
|
271
277
|
const newUseCount = invite.useCount + 1;
|
|
272
278
|
const newStatus = newUseCount >= invite.maxUses ? 'redeemed' : 'active';
|
|
273
279
|
|
|
@@ -323,6 +329,94 @@ export function redeemInvite(params: {
|
|
|
323
329
|
return { invite: updatedInvite, member: rowToMember(memberRow) };
|
|
324
330
|
}
|
|
325
331
|
|
|
332
|
+
// ---------------------------------------------------------------------------
|
|
333
|
+
// recordInviteUse — consume one use without creating a member row
|
|
334
|
+
// ---------------------------------------------------------------------------
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* Increment an invite's use count and record redemption metadata without
|
|
338
|
+
* inserting a new member row. Used when reactivating an existing inactive
|
|
339
|
+
* member via invite — the member row already exists and just needs an
|
|
340
|
+
* update, so the transactional INSERT in `redeemInvite` would hit a
|
|
341
|
+
* unique-key constraint.
|
|
342
|
+
*
|
|
343
|
+
* Returns `true` if the use was recorded, or `false` if the invite was
|
|
344
|
+
* concurrently revoked/expired (the WHERE clause constrains to
|
|
345
|
+
* `status = 'active'` so a stale write is impossible).
|
|
346
|
+
*/
|
|
347
|
+
export function recordInviteUse(params: {
|
|
348
|
+
inviteId: string;
|
|
349
|
+
externalUserId?: string;
|
|
350
|
+
externalChatId?: string;
|
|
351
|
+
}): boolean {
|
|
352
|
+
const db = getDb();
|
|
353
|
+
const now = Date.now();
|
|
354
|
+
|
|
355
|
+
const invite = db
|
|
356
|
+
.select()
|
|
357
|
+
.from(assistantIngressInvites)
|
|
358
|
+
.where(eq(assistantIngressInvites.id, params.inviteId))
|
|
359
|
+
.get();
|
|
360
|
+
|
|
361
|
+
if (!invite) return false;
|
|
362
|
+
|
|
363
|
+
const newUseCount = invite.useCount + 1;
|
|
364
|
+
const newStatus = newUseCount >= invite.maxUses ? 'redeemed' : 'active';
|
|
365
|
+
|
|
366
|
+
// Constrain the update to active invites so a concurrent revoke/expire
|
|
367
|
+
// prevents this write rather than silently overwriting the new status.
|
|
368
|
+
db.update(assistantIngressInvites)
|
|
369
|
+
.set({
|
|
370
|
+
useCount: newUseCount,
|
|
371
|
+
status: newStatus,
|
|
372
|
+
redeemedByExternalUserId: params.externalUserId ?? null,
|
|
373
|
+
redeemedByExternalChatId: params.externalChatId ?? null,
|
|
374
|
+
redeemedAt: now,
|
|
375
|
+
updatedAt: now,
|
|
376
|
+
})
|
|
377
|
+
.where(
|
|
378
|
+
and(
|
|
379
|
+
eq(assistantIngressInvites.id, invite.id),
|
|
380
|
+
eq(assistantIngressInvites.status, 'active'),
|
|
381
|
+
),
|
|
382
|
+
)
|
|
383
|
+
.run();
|
|
384
|
+
|
|
385
|
+
// Re-read to confirm the update took effect (the WHERE clause constrains
|
|
386
|
+
// to status = 'active', so a concurrent revoke/expire would prevent it).
|
|
387
|
+
const updated = db
|
|
388
|
+
.select({ useCount: assistantIngressInvites.useCount })
|
|
389
|
+
.from(assistantIngressInvites)
|
|
390
|
+
.where(eq(assistantIngressInvites.id, invite.id))
|
|
391
|
+
.get();
|
|
392
|
+
|
|
393
|
+
return !!updated && updated.useCount === newUseCount;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
// ---------------------------------------------------------------------------
|
|
397
|
+
// markInviteExpired
|
|
398
|
+
// ---------------------------------------------------------------------------
|
|
399
|
+
|
|
400
|
+
/**
|
|
401
|
+
* Transition an invite's status to 'expired' in storage. This is safe to call
|
|
402
|
+
* even if the invite is already expired — the WHERE clause scopes the update
|
|
403
|
+
* to 'active' rows so it becomes a no-op in that case.
|
|
404
|
+
*/
|
|
405
|
+
export function markInviteExpired(inviteId: string): void {
|
|
406
|
+
const db = getDb();
|
|
407
|
+
const now = Date.now();
|
|
408
|
+
|
|
409
|
+
db.update(assistantIngressInvites)
|
|
410
|
+
.set({ status: 'expired', updatedAt: now })
|
|
411
|
+
.where(
|
|
412
|
+
and(
|
|
413
|
+
eq(assistantIngressInvites.id, inviteId),
|
|
414
|
+
eq(assistantIngressInvites.status, 'active'),
|
|
415
|
+
),
|
|
416
|
+
)
|
|
417
|
+
.run();
|
|
418
|
+
}
|
|
419
|
+
|
|
326
420
|
// ---------------------------------------------------------------------------
|
|
327
421
|
// findByTokenHash
|
|
328
422
|
// ---------------------------------------------------------------------------
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { DrizzleDb } from '../db-connection.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Create the scoped_approval_grants table for channel-agnostic scoped
|
|
5
|
+
* approval grants. Supports two scope modes:
|
|
6
|
+
* - request_id: grant is scoped to a specific request
|
|
7
|
+
* - tool_signature: grant is scoped to a tool name + input digest
|
|
8
|
+
*
|
|
9
|
+
* Grants are one-time-use (active -> consumed via CAS) and carry a
|
|
10
|
+
* mandatory TTL (expires_at).
|
|
11
|
+
*/
|
|
12
|
+
export function createScopedApprovalGrantsTable(database: DrizzleDb): void {
|
|
13
|
+
database.run(/*sql*/ `
|
|
14
|
+
CREATE TABLE IF NOT EXISTS scoped_approval_grants (
|
|
15
|
+
id TEXT PRIMARY KEY,
|
|
16
|
+
assistant_id TEXT NOT NULL,
|
|
17
|
+
scope_mode TEXT NOT NULL,
|
|
18
|
+
request_id TEXT,
|
|
19
|
+
tool_name TEXT,
|
|
20
|
+
input_digest TEXT,
|
|
21
|
+
request_channel TEXT NOT NULL,
|
|
22
|
+
decision_channel TEXT NOT NULL,
|
|
23
|
+
execution_channel TEXT,
|
|
24
|
+
conversation_id TEXT,
|
|
25
|
+
call_session_id TEXT,
|
|
26
|
+
requester_external_user_id TEXT,
|
|
27
|
+
guardian_external_user_id TEXT,
|
|
28
|
+
status TEXT NOT NULL,
|
|
29
|
+
expires_at TEXT NOT NULL,
|
|
30
|
+
consumed_at TEXT,
|
|
31
|
+
consumed_by_request_id TEXT,
|
|
32
|
+
created_at TEXT NOT NULL,
|
|
33
|
+
updated_at TEXT NOT NULL
|
|
34
|
+
)
|
|
35
|
+
`);
|
|
36
|
+
|
|
37
|
+
// Index for request_id-based lookups (scope_mode = 'request_id')
|
|
38
|
+
database.run(
|
|
39
|
+
/*sql*/ `CREATE INDEX IF NOT EXISTS idx_scoped_grants_request_id ON scoped_approval_grants(request_id) WHERE request_id IS NOT NULL`,
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
// Index for tool_signature-based lookups (scope_mode = 'tool_signature')
|
|
43
|
+
database.run(
|
|
44
|
+
/*sql*/ `CREATE INDEX IF NOT EXISTS idx_scoped_grants_tool_sig ON scoped_approval_grants(tool_name, input_digest) WHERE tool_name IS NOT NULL`,
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
// Index for expiry sweeps
|
|
48
|
+
database.run(
|
|
49
|
+
/*sql*/ `CREATE INDEX IF NOT EXISTS idx_scoped_grants_status_expires ON scoped_approval_grants(status, expires_at)`,
|
|
50
|
+
);
|
|
51
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { DrizzleDb } from '../db-connection.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Add tool_name and input_digest columns to guardian_action_requests for
|
|
5
|
+
* structured tool-approval tracking. These are nullable — informational
|
|
6
|
+
* ASK_GUARDIAN requests leave them NULL while tool-approval requests
|
|
7
|
+
* carry the tool identity and canonical input digest.
|
|
8
|
+
*/
|
|
9
|
+
export function migrateGuardianActionToolMetadata(database: DrizzleDb): void {
|
|
10
|
+
try { database.run(/*sql*/ `ALTER TABLE guardian_action_requests ADD COLUMN tool_name TEXT`); } catch { /* already exists */ }
|
|
11
|
+
try { database.run(/*sql*/ `ALTER TABLE guardian_action_requests ADD COLUMN input_digest TEXT`); } catch { /* already exists */ }
|
|
12
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { DrizzleDb } from '../db-connection.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Add supersession metadata columns to guardian_action_requests and
|
|
5
|
+
* create an index for efficient pending-request lookups by call session.
|
|
6
|
+
*
|
|
7
|
+
* - superseded_by_request_id: links to the request that replaced this one
|
|
8
|
+
* - superseded_at: timestamp when supersession occurred
|
|
9
|
+
* - Index (call_session_id, status, created_at DESC) for fast lookups of
|
|
10
|
+
* the most recent pending request per call session
|
|
11
|
+
*
|
|
12
|
+
* The existing expired_reason column already supports 'superseded' as a
|
|
13
|
+
* value — this migration adds the structural metadata to track the
|
|
14
|
+
* supersession chain.
|
|
15
|
+
*/
|
|
16
|
+
export function migrateGuardianActionSupersession(database: DrizzleDb): void {
|
|
17
|
+
try { database.run(/*sql*/ `ALTER TABLE guardian_action_requests ADD COLUMN superseded_by_request_id TEXT`); } catch { /* already exists */ }
|
|
18
|
+
try { database.run(/*sql*/ `ALTER TABLE guardian_action_requests ADD COLUMN superseded_at INTEGER`); } catch { /* already exists */ }
|
|
19
|
+
|
|
20
|
+
database.run(
|
|
21
|
+
/*sql*/ `CREATE INDEX IF NOT EXISTS idx_guardian_action_requests_session_status_created ON guardian_action_requests(call_session_id, status, created_at DESC)`,
|
|
22
|
+
);
|
|
23
|
+
}
|
|
@@ -34,6 +34,9 @@ export { migrateGuardianVerificationPurpose } from './030-guardian-verification-
|
|
|
34
34
|
export { migrateConversationsThreadTypeIndex } from './031-conversations-thread-type-index.js';
|
|
35
35
|
export { migrateGuardianDeliveryConversationIndex } from './032-guardian-delivery-conversation-index.js';
|
|
36
36
|
export { migrateNotificationDeliveryThreadDecision } from './032-notification-delivery-thread-decision.js';
|
|
37
|
+
export { createScopedApprovalGrantsTable } from './033-scoped-approval-grants.js';
|
|
38
|
+
export { migrateGuardianActionToolMetadata } from './034-guardian-action-tool-metadata.js';
|
|
39
|
+
export { migrateGuardianActionSupersession } from './035-guardian-action-supersession.js';
|
|
37
40
|
export { createCoreTables } from './100-core-tables.js';
|
|
38
41
|
export { createWatchersAndLogsTables } from './101-watchers-and-logs.js';
|
|
39
42
|
export { addCoreColumns } from './102-alter-table-columns.js';
|
package/src/memory/schema.ts
CHANGED
|
@@ -843,9 +843,15 @@ export const guardianActionRequests = sqliteTable('guardian_action_requests', {
|
|
|
843
843
|
lateAnsweredAt: integer('late_answered_at'),
|
|
844
844
|
followupAction: text('followup_action'), // call_back | message_back | decline
|
|
845
845
|
followupCompletedAt: integer('followup_completed_at'),
|
|
846
|
+
toolName: text('tool_name'), // tool identity for tool-approval requests
|
|
847
|
+
inputDigest: text('input_digest'), // canonical SHA-256 digest of tool input
|
|
848
|
+
supersededByRequestId: text('superseded_by_request_id'), // links to the request that replaced this one
|
|
849
|
+
supersededAt: integer('superseded_at'), // epoch ms when supersession occurred
|
|
846
850
|
createdAt: integer('created_at').notNull(),
|
|
847
851
|
updatedAt: integer('updated_at').notNull(),
|
|
848
|
-
})
|
|
852
|
+
}, (table) => [
|
|
853
|
+
index('idx_guardian_action_requests_session_status_created').on(table.callSessionId, table.status, table.createdAt),
|
|
854
|
+
]);
|
|
849
855
|
|
|
850
856
|
// ── Guardian Action Deliveries (per-channel delivery tracking) ───────
|
|
851
857
|
|
|
@@ -1075,3 +1081,31 @@ export const conversationAssistantAttentionState = sqliteTable('conversation_ass
|
|
|
1075
1081
|
index('idx_conv_attn_state_assistant_latest_msg').on(table.assistantId, table.latestAssistantMessageAt),
|
|
1076
1082
|
index('idx_conv_attn_state_assistant_last_seen').on(table.assistantId, table.lastSeenAssistantMessageAt),
|
|
1077
1083
|
]);
|
|
1084
|
+
|
|
1085
|
+
// ── Scoped Approval Grants ──────────────────────────────────────────
|
|
1086
|
+
|
|
1087
|
+
export const scopedApprovalGrants = sqliteTable('scoped_approval_grants', {
|
|
1088
|
+
id: text('id').primaryKey(),
|
|
1089
|
+
assistantId: text('assistant_id').notNull(),
|
|
1090
|
+
scopeMode: text('scope_mode').notNull(), // 'request_id' | 'tool_signature'
|
|
1091
|
+
requestId: text('request_id'),
|
|
1092
|
+
toolName: text('tool_name'),
|
|
1093
|
+
inputDigest: text('input_digest'),
|
|
1094
|
+
requestChannel: text('request_channel').notNull(),
|
|
1095
|
+
decisionChannel: text('decision_channel').notNull(),
|
|
1096
|
+
executionChannel: text('execution_channel'), // null = any channel
|
|
1097
|
+
conversationId: text('conversation_id'),
|
|
1098
|
+
callSessionId: text('call_session_id'),
|
|
1099
|
+
requesterExternalUserId: text('requester_external_user_id'),
|
|
1100
|
+
guardianExternalUserId: text('guardian_external_user_id'),
|
|
1101
|
+
status: text('status').notNull(), // 'active' | 'consumed' | 'expired' | 'revoked'
|
|
1102
|
+
expiresAt: text('expires_at').notNull(),
|
|
1103
|
+
consumedAt: text('consumed_at'),
|
|
1104
|
+
consumedByRequestId: text('consumed_by_request_id'),
|
|
1105
|
+
createdAt: text('created_at').notNull(),
|
|
1106
|
+
updatedAt: text('updated_at').notNull(),
|
|
1107
|
+
}, (table) => [
|
|
1108
|
+
index('idx_scoped_grants_request_id').on(table.requestId),
|
|
1109
|
+
index('idx_scoped_grants_tool_sig').on(table.toolName, table.inputDigest),
|
|
1110
|
+
index('idx_scoped_grants_status_expires').on(table.status, table.expiresAt),
|
|
1111
|
+
]);
|