@vellumai/assistant 0.3.3 → 0.3.4
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 +8 -16
- package/package.json +1 -1
- package/src/__tests__/call-orchestrator.test.ts +321 -0
- package/src/__tests__/channel-approval-routes.test.ts +382 -124
- package/src/__tests__/channel-approvals.test.ts +51 -2
- package/src/__tests__/channel-delivery-store.test.ts +30 -4
- package/src/__tests__/channel-guardian.test.ts +187 -0
- package/src/__tests__/config-schema.test.ts +1 -1
- package/src/__tests__/daemon-lifecycle.test.ts +635 -0
- package/src/__tests__/gateway-only-enforcement.test.ts +19 -13
- package/src/__tests__/handlers-twilio-config.test.ts +73 -0
- package/src/__tests__/secret-scanner.test.ts +223 -0
- package/src/__tests__/shell-parser-property.test.ts +357 -2
- package/src/__tests__/system-prompt.test.ts +25 -1
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +34 -1
- package/src/__tests__/user-reference.test.ts +68 -0
- package/src/calls/call-orchestrator.ts +63 -11
- package/src/cli/map.ts +6 -0
- package/src/commands/__tests__/cc-command-registry.test.ts +67 -0
- package/src/commands/cc-command-registry.ts +14 -1
- package/src/config/bundled-skills/claude-code/TOOLS.json +10 -3
- package/src/config/bundled-skills/messaging/SKILL.md +4 -0
- package/src/config/defaults.ts +1 -1
- package/src/config/schema.ts +3 -3
- package/src/config/skills.ts +5 -32
- package/src/config/system-prompt.ts +16 -0
- package/src/config/user-reference.ts +29 -0
- package/src/config/vellum-skills/catalog.json +52 -0
- package/src/config/vellum-skills/telegram-setup/SKILL.md +6 -1
- package/src/config/vellum-skills/twilio-setup/SKILL.md +38 -0
- package/src/daemon/auth-manager.ts +103 -0
- package/src/daemon/computer-use-session.ts +8 -1
- package/src/daemon/config-watcher.ts +253 -0
- package/src/daemon/handlers/config.ts +36 -13
- package/src/daemon/handlers/skills.ts +6 -7
- package/src/daemon/ipc-contract.ts +6 -0
- package/src/daemon/ipc-handler.ts +87 -0
- package/src/daemon/lifecycle.ts +16 -4
- package/src/daemon/ride-shotgun-handler.ts +11 -1
- package/src/daemon/server.ts +105 -502
- package/src/daemon/session-agent-loop.ts +5 -14
- package/src/daemon/session-runtime-assembly.ts +60 -44
- package/src/daemon/session.ts +8 -1
- package/src/memory/db-connection.ts +28 -0
- package/src/memory/db-init.ts +1019 -0
- package/src/memory/db.ts +2 -2007
- package/src/memory/embedding-backend.ts +79 -11
- package/src/memory/indexer.ts +2 -0
- package/src/memory/job-utils.ts +64 -4
- package/src/memory/jobs-worker.ts +7 -1
- package/src/memory/recall-cache.ts +107 -0
- package/src/memory/retriever.ts +30 -1
- package/src/memory/schema-migration.ts +984 -0
- package/src/memory/schema.ts +1 -0
- package/src/memory/search/types.ts +2 -0
- package/src/permissions/prompter.ts +14 -3
- package/src/permissions/trust-store.ts +7 -0
- package/src/runtime/channel-approvals.ts +17 -3
- package/src/runtime/gateway-client.ts +2 -1
- package/src/runtime/http-server.ts +15 -4
- package/src/runtime/routes/channel-routes.ts +172 -84
- package/src/runtime/routes/run-routes.ts +7 -1
- package/src/runtime/run-orchestrator.ts +8 -1
- package/src/security/secret-scanner.ts +218 -0
- package/src/skills/frontmatter.ts +63 -0
- package/src/skills/slash-commands.ts +23 -0
- package/src/skills/vellum-catalog-remote.ts +107 -0
- package/src/tools/browser/auto-navigate.ts +132 -24
- package/src/tools/browser/browser-manager.ts +67 -61
- package/src/tools/claude-code/claude-code.ts +55 -3
- package/src/tools/executor.ts +10 -2
- package/src/tools/skills/vellum-catalog.ts +61 -156
- package/src/tools/terminal/parser.ts +21 -5
- package/src/util/platform.ts +8 -1
- package/src/util/retry.ts +4 -4
|
@@ -31,10 +31,7 @@ import type { MessageQueue } from './session-queue-manager.js';
|
|
|
31
31
|
import type { QueueDrainReason } from './session-queue-manager.js';
|
|
32
32
|
import {
|
|
33
33
|
applyRuntimeInjections,
|
|
34
|
-
|
|
35
|
-
stripWorkspaceTopLevelContext,
|
|
36
|
-
stripChannelCapabilityContext,
|
|
37
|
-
stripTemporalContext,
|
|
34
|
+
stripInjectedContext,
|
|
38
35
|
} from './session-runtime-assembly.js';
|
|
39
36
|
import { buildTemporalContext } from './date-context.js';
|
|
40
37
|
import type { ActiveSurfaceContext, ChannelCapabilities } from './session-runtime-assembly.js';
|
|
@@ -740,16 +737,10 @@ export async function runAgentLoopImpl(
|
|
|
740
737
|
}
|
|
741
738
|
|
|
742
739
|
const restoredHistory = [...preRepairMessages, ...newMessages];
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
stripActiveSurfaceContext(
|
|
748
|
-
stripDynamicProfileMessages(recallStripped, dynamicProfile.text),
|
|
749
|
-
),
|
|
750
|
-
),
|
|
751
|
-
),
|
|
752
|
-
);
|
|
740
|
+
ctx.messages = stripInjectedContext(restoredHistory, {
|
|
741
|
+
stripRecall: (msgs) => stripMemoryRecallMessages(msgs, recall.injectedText, recallInjectionStrategy),
|
|
742
|
+
stripDynamicProfile: (msgs) => stripDynamicProfileMessages(msgs, dynamicProfile.text),
|
|
743
|
+
});
|
|
753
744
|
|
|
754
745
|
emitUsage(ctx, exchangeInputTokens, exchangeOutputTokens, model, onEvent, 'main_agent', reqId);
|
|
755
746
|
|
|
@@ -264,16 +264,24 @@ export function injectChannelCapabilityContext(message: Message, caps: ChannelCa
|
|
|
264
264
|
};
|
|
265
265
|
}
|
|
266
266
|
|
|
267
|
+
// ---------------------------------------------------------------------------
|
|
268
|
+
// Prefix-based stripping primitive
|
|
269
|
+
// ---------------------------------------------------------------------------
|
|
270
|
+
|
|
267
271
|
/**
|
|
268
|
-
*
|
|
269
|
-
*
|
|
272
|
+
* Remove text blocks from user messages whose text starts with any of the
|
|
273
|
+
* given prefixes. If stripping removes all content blocks from a message,
|
|
274
|
+
* the message itself is dropped.
|
|
275
|
+
*
|
|
276
|
+
* This is the shared primitive behind the individual strip* functions and
|
|
277
|
+
* the `stripInjectedContext` pipeline.
|
|
270
278
|
*/
|
|
271
|
-
export function
|
|
279
|
+
export function stripUserTextBlocksByPrefix(messages: Message[], prefixes: string[]): Message[] {
|
|
272
280
|
return messages.map((message) => {
|
|
273
281
|
if (message.role !== 'user') return message;
|
|
274
282
|
const nextContent = message.content.filter((block) => {
|
|
275
283
|
if (block.type !== 'text') return true;
|
|
276
|
-
return !block.text.startsWith(
|
|
284
|
+
return !prefixes.some((p) => block.text.startsWith(p));
|
|
277
285
|
});
|
|
278
286
|
if (nextContent.length === message.content.length) return message;
|
|
279
287
|
if (nextContent.length === 0) return null;
|
|
@@ -281,6 +289,15 @@ export function stripChannelCapabilityContext(messages: Message[]): Message[] {
|
|
|
281
289
|
}).filter((message): message is NonNullable<typeof message> => message !== null);
|
|
282
290
|
}
|
|
283
291
|
|
|
292
|
+
// ---------------------------------------------------------------------------
|
|
293
|
+
// Individual strip functions (thin wrappers around the primitive)
|
|
294
|
+
// ---------------------------------------------------------------------------
|
|
295
|
+
|
|
296
|
+
/** Strip `<channel_capabilities>` blocks injected by `injectChannelCapabilityContext`. */
|
|
297
|
+
export function stripChannelCapabilityContext(messages: Message[]): Message[] {
|
|
298
|
+
return stripUserTextBlocksByPrefix(messages, ['<channel_capabilities>']);
|
|
299
|
+
}
|
|
300
|
+
|
|
284
301
|
/**
|
|
285
302
|
* Prepend workspace top-level directory context to a user message.
|
|
286
303
|
*/
|
|
@@ -294,22 +311,9 @@ export function injectWorkspaceTopLevelContext(message: Message, contextText: st
|
|
|
294
311
|
};
|
|
295
312
|
}
|
|
296
313
|
|
|
297
|
-
/**
|
|
298
|
-
* Strip `<workspace_top_level>` blocks injected by
|
|
299
|
-
* `injectWorkspaceTopLevelContext`. Called after the agent run to prevent
|
|
300
|
-
* workspace context from persisting in session history.
|
|
301
|
-
*/
|
|
314
|
+
/** Strip `<workspace_top_level>` blocks injected by `injectWorkspaceTopLevelContext`. */
|
|
302
315
|
export function stripWorkspaceTopLevelContext(messages: Message[]): Message[] {
|
|
303
|
-
return messages
|
|
304
|
-
if (message.role !== 'user') return message;
|
|
305
|
-
const nextContent = message.content.filter((block) => {
|
|
306
|
-
if (block.type !== 'text') return true;
|
|
307
|
-
return !block.text.startsWith('<workspace_top_level>');
|
|
308
|
-
});
|
|
309
|
-
if (nextContent.length === message.content.length) return message;
|
|
310
|
-
if (nextContent.length === 0) return null;
|
|
311
|
-
return { ...message, content: nextContent };
|
|
312
|
-
}).filter((message): message is NonNullable<typeof message> => message !== null);
|
|
316
|
+
return stripUserTextBlocksByPrefix(messages, ['<workspace_top_level>']);
|
|
313
317
|
}
|
|
314
318
|
|
|
315
319
|
/**
|
|
@@ -328,8 +332,6 @@ export function injectTemporalContext(message: Message, temporalContext: string)
|
|
|
328
332
|
|
|
329
333
|
/**
|
|
330
334
|
* Strip `<temporal_context>` blocks injected by `injectTemporalContext`.
|
|
331
|
-
* Called after the agent run to prevent temporal context from persisting
|
|
332
|
-
* in session history.
|
|
333
335
|
*
|
|
334
336
|
* Uses a specific prefix (`<temporal_context>\nToday:`) so that
|
|
335
337
|
* user-authored text that happens to start with `<temporal_context>`
|
|
@@ -338,35 +340,49 @@ export function injectTemporalContext(message: Message, temporalContext: string)
|
|
|
338
340
|
const TEMPORAL_INJECTED_PREFIX = '<temporal_context>\nToday:';
|
|
339
341
|
|
|
340
342
|
export function stripTemporalContext(messages: Message[]): Message[] {
|
|
341
|
-
return messages
|
|
342
|
-
if (message.role !== 'user') return message;
|
|
343
|
-
const nextContent = message.content.filter((block) => {
|
|
344
|
-
if (block.type !== 'text') return true;
|
|
345
|
-
return !block.text.startsWith(TEMPORAL_INJECTED_PREFIX);
|
|
346
|
-
});
|
|
347
|
-
if (nextContent.length === message.content.length) return message;
|
|
348
|
-
if (nextContent.length === 0) return null;
|
|
349
|
-
return { ...message, content: nextContent };
|
|
350
|
-
}).filter((message): message is NonNullable<typeof message> => message !== null);
|
|
343
|
+
return stripUserTextBlocksByPrefix(messages, [TEMPORAL_INJECTED_PREFIX]);
|
|
351
344
|
}
|
|
352
345
|
|
|
353
346
|
/**
|
|
354
347
|
* Strip `<active_workspace>` (and legacy `<active_dynamic_page>`) blocks
|
|
355
|
-
* injected by `injectActiveSurfaceContext`.
|
|
356
|
-
* prevent the (potentially 100 KB) surface HTML from persisting in session
|
|
357
|
-
* history.
|
|
348
|
+
* injected by `injectActiveSurfaceContext`.
|
|
358
349
|
*/
|
|
359
350
|
export function stripActiveSurfaceContext(messages: Message[]): Message[] {
|
|
360
|
-
return messages
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
351
|
+
return stripUserTextBlocksByPrefix(messages, ['<active_workspace>', '<active_dynamic_page>']);
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
// ---------------------------------------------------------------------------
|
|
355
|
+
// Declarative strip pipeline
|
|
356
|
+
// ---------------------------------------------------------------------------
|
|
357
|
+
|
|
358
|
+
/** Prefixes stripped by the pipeline (order doesn't matter — single pass). */
|
|
359
|
+
const RUNTIME_INJECTION_PREFIXES = [
|
|
360
|
+
'<channel_capabilities>',
|
|
361
|
+
'<workspace_top_level>',
|
|
362
|
+
TEMPORAL_INJECTED_PREFIX,
|
|
363
|
+
'<active_workspace>',
|
|
364
|
+
'<active_dynamic_page>',
|
|
365
|
+
];
|
|
366
|
+
|
|
367
|
+
/**
|
|
368
|
+
* Strip all runtime-injected context from message history in a single pass.
|
|
369
|
+
*
|
|
370
|
+
* Composes:
|
|
371
|
+
* 1. `stripMemoryRecallMessages` (caller-supplied, handles its own logic)
|
|
372
|
+
* 2. `stripDynamicProfileMessages` (caller-supplied, handles its own logic)
|
|
373
|
+
* 3. Prefix-based stripping for channel capabilities, workspace top-level,
|
|
374
|
+
* temporal context, and active surface context (single pass).
|
|
375
|
+
*/
|
|
376
|
+
export function stripInjectedContext(
|
|
377
|
+
messages: Message[],
|
|
378
|
+
options: {
|
|
379
|
+
stripRecall: (msgs: Message[]) => Message[];
|
|
380
|
+
stripDynamicProfile: (msgs: Message[]) => Message[];
|
|
381
|
+
},
|
|
382
|
+
): Message[] {
|
|
383
|
+
const afterRecall = options.stripRecall(messages);
|
|
384
|
+
const afterProfile = options.stripDynamicProfile(afterRecall);
|
|
385
|
+
return stripUserTextBlocksByPrefix(afterProfile, RUNTIME_INJECTION_PREFIXES);
|
|
370
386
|
}
|
|
371
387
|
|
|
372
388
|
/**
|
package/src/daemon/session.ts
CHANGED
|
@@ -308,8 +308,15 @@ export class Session {
|
|
|
308
308
|
decision: UserDecision,
|
|
309
309
|
selectedPattern?: string,
|
|
310
310
|
selectedScope?: string,
|
|
311
|
+
decisionContext?: string,
|
|
311
312
|
): void {
|
|
312
|
-
this.prompter.resolveConfirmation(
|
|
313
|
+
this.prompter.resolveConfirmation(
|
|
314
|
+
requestId,
|
|
315
|
+
decision,
|
|
316
|
+
selectedPattern,
|
|
317
|
+
selectedScope,
|
|
318
|
+
decisionContext,
|
|
319
|
+
);
|
|
313
320
|
}
|
|
314
321
|
|
|
315
322
|
handleSecretResponse(requestId: string, value?: string, delivery?: 'store' | 'transient_send'): void {
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Database } from 'bun:sqlite';
|
|
2
|
+
import { drizzle } from 'drizzle-orm/bun-sqlite';
|
|
3
|
+
import * as schema from './schema.js';
|
|
4
|
+
import { getDbPath, ensureDataDir, migrateToDataLayout, migrateToWorkspaceLayout } from '../util/platform.js';
|
|
5
|
+
|
|
6
|
+
let db: ReturnType<typeof drizzle<typeof schema>> | null = null;
|
|
7
|
+
|
|
8
|
+
export function getDb() {
|
|
9
|
+
if (!db) {
|
|
10
|
+
migrateToDataLayout();
|
|
11
|
+
migrateToWorkspaceLayout();
|
|
12
|
+
ensureDataDir();
|
|
13
|
+
const sqlite = new Database(getDbPath());
|
|
14
|
+
sqlite.exec('PRAGMA journal_mode=WAL');
|
|
15
|
+
sqlite.exec('PRAGMA foreign_keys = ON');
|
|
16
|
+
db = drizzle(sqlite, { schema });
|
|
17
|
+
}
|
|
18
|
+
return db;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** Reset the db singleton. Used by tests to ensure isolation between test files. */
|
|
22
|
+
export function resetDb(): void {
|
|
23
|
+
if (db) {
|
|
24
|
+
const raw = (db as unknown as { $client: Database }).$client;
|
|
25
|
+
raw.close();
|
|
26
|
+
db = null;
|
|
27
|
+
}
|
|
28
|
+
}
|