@vellumai/assistant 0.3.19 → 0.3.21
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 +151 -15
- package/Dockerfile +1 -0
- package/README.md +40 -4
- package/bun.lock +139 -2
- package/docs/architecture/integrations.md +7 -11
- package/package.json +2 -1
- package/src/__tests__/__snapshots__/ipc-snapshot.test.ts.snap +54 -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 +439 -108
- package/src/__tests__/channel-invite-transport.test.ts +264 -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 +300 -32
- 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 +124 -0
- package/src/__tests__/guardian-grant-minting.test.ts +6 -17
- 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 +57 -0
- package/src/__tests__/notification-decision-fallback.test.ts +88 -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 +6 -6
- package/src/__tests__/scoped-grant-security-matrix.test.ts +5 -4
- 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__/trusted-contact-lifecycle-notifications.test.ts +8 -10
- package/src/__tests__/voice-scoped-grant-consumer.test.ts +46 -84
- 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 +252 -209
- package/src/calls/call-domain.ts +44 -6
- package/src/calls/guardian-dispatch.ts +48 -0
- package/src/calls/types.ts +1 -1
- package/src/calls/voice-session-bridge.ts +46 -30
- package/src/cli/core-commands.ts +0 -4
- package/src/cli/mcp.ts +58 -0
- 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 +1 -1
- 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/mcp-schema.ts +46 -0
- package/src/config/sandbox-schema.ts +0 -39
- package/src/config/schema.ts +18 -2
- package/src/config/skill-state.ts +34 -0
- package/src/config/skills-schema.ts +0 -1
- 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 +6 -5
- package/src/config/vellum-skills/trusted-contacts/SKILL.md +105 -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/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/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-inventory.json +10 -0
- package/src/daemon/ipc-contract.ts +4 -0
- package/src/daemon/lifecycle.ts +14 -2
- package/src/daemon/main.ts +1 -0
- package/src/daemon/providers-setup.ts +26 -1
- 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 +258 -432
- 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/shutdown-handlers.ts +11 -0
- package/src/daemon/tool-side-effects.ts +35 -9
- package/src/index.ts +2 -2
- package/src/mcp/client.ts +152 -0
- package/src/mcp/manager.ts +139 -0
- 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 +5 -1
- package/src/memory/embedding-local.ts +13 -8
- package/src/memory/guardian-action-store.ts +125 -2
- package/src/memory/ingress-invite-store.ts +95 -1
- package/src/memory/migrations/035-guardian-action-supersession.ts +23 -0
- package/src/memory/migrations/index.ts +2 -1
- package/src/memory/schema.ts +5 -1
- package/src/memory/scoped-approval-grants.ts +14 -5
- 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/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 +92 -35
- 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 -190
- package/src/runtime/routes/identity-routes.ts +73 -0
- package/src/runtime/routes/inbound-message-handler.ts +486 -394
- 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 +1 -1
- 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/mcp/mcp-tool-factory.ts +100 -0
- package/src/tools/network/script-proxy/session-manager.ts +1 -5
- package/src/tools/registry.ts +64 -1
- 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 +10 -2
- 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
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
// Guardian invite intent resolution for deterministic first-turn routing.
|
|
2
|
+
// Exports `resolveGuardianInviteIntent` as the single public entry point.
|
|
3
|
+
// When a guardian invite management request is detected, the session pipeline
|
|
4
|
+
// rewrites the message to force immediate entry into the trusted-contacts
|
|
5
|
+
// skill flow, bypassing the normal agent loop's tendency to produce conceptual
|
|
6
|
+
// preambles before loading the skill.
|
|
7
|
+
|
|
8
|
+
export type GuardianInviteIntentResult =
|
|
9
|
+
| { kind: 'none' }
|
|
10
|
+
| { kind: 'invite_management'; rewrittenContent: string; action?: 'create' | 'list' | 'revoke' };
|
|
11
|
+
|
|
12
|
+
// ── Direct invite patterns ────────────────────────────────────────────────
|
|
13
|
+
// These capture imperative requests to manage Telegram invite links.
|
|
14
|
+
|
|
15
|
+
const CREATE_INVITE_PATTERNS: RegExp[] = [
|
|
16
|
+
/\bcreate\s+(?:an?\s+)?(?:telegram\s+)?invite\s*(?:link)?\b/i,
|
|
17
|
+
/\binvite\s+(?:someone|somebody|a\s+friend|a\s+person)\s+(?:on|to|via|through)\s+telegram\b/i,
|
|
18
|
+
/\b(?:make|generate|get)\s+(?:a\s+|an\s+)?(?:telegram\s+)?invite\s*(?:link)?\b/i,
|
|
19
|
+
/\btelegram\s+invite\s*(?:link)?\b/i,
|
|
20
|
+
/\bsend\s+(?:a\s+|an\s+)?invite\s+(?:link\s+)?(?:on|for|via|through)\s+telegram\b/i,
|
|
21
|
+
/\bshare\s+(?:a\s+|an\s+)?(?:telegram\s+)?invite\s*(?:link)?\b/i,
|
|
22
|
+
/\binvite\s+(?:link\s+)?for\s+telegram\b/i,
|
|
23
|
+
];
|
|
24
|
+
|
|
25
|
+
const LIST_INVITE_PATTERNS: RegExp[] = [
|
|
26
|
+
/\b(?:show|list|view|see|display)\s+(?:my\s+)?(?:active\s+)?invite(?:s|\s*links?)\b/i,
|
|
27
|
+
/\b(?:show|list|view|see|display)\s+(?:my\s+)?(?:telegram\s+)?invite(?:s|\s*links?)\b/i,
|
|
28
|
+
/\bwhat\s+invite(?:s|\s*links?)\s+(?:do\s+I\s+have|are\s+active|exist)\b/i,
|
|
29
|
+
/\bhow\s+many\s+invite(?:s|\s*links?)\b/i,
|
|
30
|
+
];
|
|
31
|
+
|
|
32
|
+
const REVOKE_INVITE_PATTERNS: RegExp[] = [
|
|
33
|
+
/\b(?:revoke|cancel|disable|invalidate|delete|remove)\s+(?:the\s+|my\s+|an?\s+)?invite\s*(?:link)?\b/i,
|
|
34
|
+
/\b(?:revoke|cancel|disable|invalidate|delete|remove)\s+(?:the\s+|my\s+|an?\s+)?(?:telegram\s+)?invite\s*(?:link)?\b/i,
|
|
35
|
+
/\binvite\s*(?:link)?\s+(?:revoke|cancel|disable|invalidate|delete|remove)\b/i,
|
|
36
|
+
];
|
|
37
|
+
|
|
38
|
+
// ── Conceptual / question patterns ──────────────────────────────────────
|
|
39
|
+
// These indicate the user is asking *about* invites rather than requesting
|
|
40
|
+
// to manage them. Return passthrough for these.
|
|
41
|
+
|
|
42
|
+
const CONCEPTUAL_PATTERNS: RegExp[] = [
|
|
43
|
+
/^\s*(?:how|what|why|when|where|who|which)\b.*\binvite/i,
|
|
44
|
+
/\bwhat\s+(?:is|are)\s+(?:an?\s+)?invite\s*(?:link)?\b/i,
|
|
45
|
+
/\bhow\s+(?:do|does|can)\s+(?:invite|invitation)s?\s+work\b/i,
|
|
46
|
+
/\bexplain\s+(?:the\s+)?invite\b/i,
|
|
47
|
+
/\btell\s+me\s+about\s+invite\b/i,
|
|
48
|
+
];
|
|
49
|
+
|
|
50
|
+
/** Common polite/filler words stripped before checking intent-only status. */
|
|
51
|
+
const FILLER_PATTERN =
|
|
52
|
+
/\b(please|pls|plz|can\s+you|could\s+you|would\s+you|now|right\s+now|thanks|thank\s+you|thx|ty|for\s+me|ok(ay)?|hey|hi|hello|just|i\s+want\s+to|i'd\s+like\s+to|i\s+need\s+to|let's|let\s+me)\b/gi;
|
|
53
|
+
|
|
54
|
+
// ── Internal helpers ─────────────────────────────────────────────────────
|
|
55
|
+
|
|
56
|
+
function isConceptualQuestion(text: string): boolean {
|
|
57
|
+
const cleaned = text.replace(/^\s*(hey|hi|hello|please|pls|plz)[,\s]+/i, '');
|
|
58
|
+
// Allow actionable requests through even though they start with
|
|
59
|
+
// question-like words — these are imperative invite management requests.
|
|
60
|
+
if (LIST_INVITE_PATTERNS.some((p) => p.test(cleaned))) return false;
|
|
61
|
+
if (CREATE_INVITE_PATTERNS.some((p) => p.test(cleaned))) return false;
|
|
62
|
+
if (REVOKE_INVITE_PATTERNS.some((p) => p.test(cleaned))) return false;
|
|
63
|
+
return CONCEPTUAL_PATTERNS.some((p) => p.test(cleaned));
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function detectAction(text: string): 'create' | 'list' | 'revoke' | undefined {
|
|
67
|
+
// Check revoke and list before create — create patterns include the broad
|
|
68
|
+
// `telegram invite link` matcher that would otherwise swallow revoke/list inputs.
|
|
69
|
+
if (REVOKE_INVITE_PATTERNS.some((p) => p.test(text))) return 'revoke';
|
|
70
|
+
if (LIST_INVITE_PATTERNS.some((p) => p.test(text))) return 'list';
|
|
71
|
+
if (CREATE_INVITE_PATTERNS.some((p) => p.test(text))) return 'create';
|
|
72
|
+
return undefined;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// ── Structured intent resolver ───────────────────────────────────────────
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Resolves guardian invite management intent from user text.
|
|
79
|
+
*
|
|
80
|
+
* Pipeline:
|
|
81
|
+
* 1. Skip slash commands entirely
|
|
82
|
+
* 2. Conceptual question gate -- questions return `none`
|
|
83
|
+
* 3. Detect create/list/revoke invite patterns
|
|
84
|
+
* 4. On match, build a deterministic model instruction to load trusted-contacts
|
|
85
|
+
*/
|
|
86
|
+
export function resolveGuardianInviteIntent(text: string): GuardianInviteIntentResult {
|
|
87
|
+
const trimmed = text.trim();
|
|
88
|
+
|
|
89
|
+
// Never intercept slash commands
|
|
90
|
+
if (trimmed.startsWith('/')) {
|
|
91
|
+
return { kind: 'none' };
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Conceptual questions pass through to normal agent processing
|
|
95
|
+
if (isConceptualQuestion(trimmed)) {
|
|
96
|
+
return { kind: 'none' };
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Strip fillers for pattern matching but keep original for context
|
|
100
|
+
const withoutFillers = trimmed.replace(FILLER_PATTERN, '').replace(/\s{2,}/g, ' ').trim();
|
|
101
|
+
|
|
102
|
+
const action = detectAction(withoutFillers);
|
|
103
|
+
if (!action) {
|
|
104
|
+
return { kind: 'none' };
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Build the rewritten content that deterministically loads the skill
|
|
108
|
+
const actionDescriptions: Record<string, string> = {
|
|
109
|
+
create: 'The user wants to create a Telegram invite link. Create the invite, look up the bot username, and present the shareable deep link with copy-paste instructions.',
|
|
110
|
+
list: 'The user wants to see their invite links. List all invites (especially active ones for Telegram) and present them in a readable format.',
|
|
111
|
+
revoke: 'The user wants to revoke an invite link. List invites to identify the target, confirm with the user, then revoke it.',
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
const rewrittenContent = [
|
|
115
|
+
actionDescriptions[action],
|
|
116
|
+
'Please invoke the "Trusted Contacts" skill (ID: trusted-contacts) immediately using skill_load.',
|
|
117
|
+
].join('\n');
|
|
118
|
+
|
|
119
|
+
return {
|
|
120
|
+
kind: 'invite_management',
|
|
121
|
+
rewrittenContent,
|
|
122
|
+
action,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import * as net from 'node:net';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
|
|
4
|
+
import { setAvatarTool } from '../../tools/system/avatar-generator.js';
|
|
5
|
+
import { getWorkspaceDir } from '../../util/platform.js';
|
|
6
|
+
import type { GenerateAvatarRequest } from '../ipc-contract/settings.js';
|
|
7
|
+
import { defineHandlers, type HandlerContext, log } from './shared.js';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Handle a client request to generate a custom avatar via Gemini.
|
|
11
|
+
* Invokes the set_avatar tool directly, sends a response to the requesting
|
|
12
|
+
* client, and broadcasts avatar_updated to all clients on success.
|
|
13
|
+
*/
|
|
14
|
+
async function handleGenerateAvatar(
|
|
15
|
+
msg: GenerateAvatarRequest,
|
|
16
|
+
socket: net.Socket,
|
|
17
|
+
ctx: HandlerContext,
|
|
18
|
+
): Promise<void> {
|
|
19
|
+
const description = msg.description?.trim();
|
|
20
|
+
if (!description) {
|
|
21
|
+
ctx.send(socket, {
|
|
22
|
+
type: 'generate_avatar_response',
|
|
23
|
+
success: false,
|
|
24
|
+
error: 'Description is required.',
|
|
25
|
+
});
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
log.info({ description }, 'Generating avatar via IPC request');
|
|
30
|
+
|
|
31
|
+
try {
|
|
32
|
+
const result = await setAvatarTool.execute(
|
|
33
|
+
{ description },
|
|
34
|
+
// Minimal tool context — avatar generation needs no session context
|
|
35
|
+
{} as Parameters<typeof setAvatarTool.execute>[1],
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
if (result.isError) {
|
|
39
|
+
ctx.send(socket, {
|
|
40
|
+
type: 'generate_avatar_response',
|
|
41
|
+
success: false,
|
|
42
|
+
error: result.content,
|
|
43
|
+
});
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Broadcast avatar change to all connected clients
|
|
48
|
+
const avatarPath = join(getWorkspaceDir(), 'data', 'avatar', 'custom-avatar.png');
|
|
49
|
+
ctx.broadcast({ type: 'avatar_updated', avatarPath });
|
|
50
|
+
|
|
51
|
+
ctx.send(socket, {
|
|
52
|
+
type: 'generate_avatar_response',
|
|
53
|
+
success: true,
|
|
54
|
+
});
|
|
55
|
+
} catch (err) {
|
|
56
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
57
|
+
log.error({ error: message }, 'Avatar generation failed unexpectedly');
|
|
58
|
+
ctx.send(socket, {
|
|
59
|
+
type: 'generate_avatar_response',
|
|
60
|
+
success: false,
|
|
61
|
+
error: message,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export const avatarHandlers = defineHandlers({
|
|
67
|
+
generate_avatar: handleGenerateAvatar,
|
|
68
|
+
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { browserManager } from '../../tools/browser/browser-manager.js';
|
|
1
|
+
import { browserManager, SCREENCAST_HEIGHT,SCREENCAST_WIDTH } from '../../tools/browser/browser-manager.js';
|
|
2
2
|
import { defineHandlers,log } from './shared.js';
|
|
3
3
|
|
|
4
4
|
export const browserHandlers = defineHandlers({
|
|
@@ -10,7 +10,7 @@ export const browserHandlers = defineHandlers({
|
|
|
10
10
|
try {
|
|
11
11
|
const page = await browserManager.getOrCreateSessionPage(msg.sessionId);
|
|
12
12
|
const viewport = await page.evaluate('(() => ({ vw: window.innerWidth, vh: window.innerHeight }))()') as { vw: number; vh: number };
|
|
13
|
-
const scale = Math.min(
|
|
13
|
+
const scale = Math.min(SCREENCAST_WIDTH / viewport.vw, SCREENCAST_HEIGHT / viewport.vh);
|
|
14
14
|
const pageX = msg.x / scale;
|
|
15
15
|
const pageY = msg.y / scale;
|
|
16
16
|
const options: Record<string, unknown> = {};
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { applyGuardianDecision } from '../../approvals/guardian-decision-primitive.js';
|
|
2
|
+
import { getPendingApprovalForRequest } from '../../memory/channel-guardian-store.js';
|
|
3
|
+
import type { ApprovalAction } from '../../runtime/channel-approval-types.js';
|
|
4
|
+
import { handleChannelDecision } from '../../runtime/channel-approvals.js';
|
|
5
|
+
import * as pendingInteractions from '../../runtime/pending-interactions.js';
|
|
6
|
+
import { handleAccessRequestDecision } from '../../runtime/routes/access-request-decision.js';
|
|
7
|
+
import { listGuardianDecisionPrompts } from '../../runtime/routes/guardian-action-routes.js';
|
|
8
|
+
import type { GuardianActionDecision, GuardianActionsPendingRequest } from '../ipc-protocol.js';
|
|
9
|
+
import { defineHandlers, log } from './shared.js';
|
|
10
|
+
|
|
11
|
+
const VALID_ACTIONS = new Set<string>(['approve_once', 'approve_always', 'reject']);
|
|
12
|
+
|
|
13
|
+
export const guardianActionsHandlers = defineHandlers({
|
|
14
|
+
guardian_actions_pending_request: (msg: GuardianActionsPendingRequest, socket, ctx) => {
|
|
15
|
+
const prompts = listGuardianDecisionPrompts({ conversationId: msg.conversationId });
|
|
16
|
+
ctx.send(socket, { type: 'guardian_actions_pending_response', conversationId: msg.conversationId, prompts });
|
|
17
|
+
},
|
|
18
|
+
|
|
19
|
+
guardian_action_decision: (msg: GuardianActionDecision, socket, ctx) => {
|
|
20
|
+
// Validate the action is one of the known actions
|
|
21
|
+
if (!VALID_ACTIONS.has(msg.action)) {
|
|
22
|
+
log.warn({ requestId: msg.requestId, action: msg.action }, 'Invalid guardian action');
|
|
23
|
+
ctx.send(socket, {
|
|
24
|
+
type: 'guardian_action_decision_response',
|
|
25
|
+
applied: false,
|
|
26
|
+
reason: 'invalid_action',
|
|
27
|
+
requestId: msg.requestId,
|
|
28
|
+
});
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Try the channel guardian approval store first (tool approval prompts)
|
|
33
|
+
const approval = getPendingApprovalForRequest(msg.requestId);
|
|
34
|
+
if (approval) {
|
|
35
|
+
// Enforce conversationId scoping when provided.
|
|
36
|
+
if (msg.conversationId && msg.conversationId !== approval.conversationId) {
|
|
37
|
+
log.warn({ requestId: msg.requestId, expected: approval.conversationId, got: msg.conversationId }, 'conversationId mismatch');
|
|
38
|
+
ctx.send(socket, {
|
|
39
|
+
type: 'guardian_action_decision_response',
|
|
40
|
+
applied: false,
|
|
41
|
+
reason: 'conversation_mismatch',
|
|
42
|
+
requestId: msg.requestId,
|
|
43
|
+
});
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Access request approvals need a separate decision path — they don't have
|
|
48
|
+
// pending interactions and use verification sessions instead.
|
|
49
|
+
if (approval.toolName === 'ingress_access_request') {
|
|
50
|
+
const mappedAction = msg.action === 'reject' ? 'deny' as const : 'approve' as const;
|
|
51
|
+
// Use 'desktop' as the actor identity because this endpoint is
|
|
52
|
+
// unauthenticated — we cannot verify the caller is the assigned
|
|
53
|
+
// guardian, so we record a generic desktop origin instead of
|
|
54
|
+
// falsely attributing the decision to guardianExternalUserId.
|
|
55
|
+
const decisionResult = handleAccessRequestDecision(
|
|
56
|
+
approval,
|
|
57
|
+
mappedAction,
|
|
58
|
+
'desktop',
|
|
59
|
+
);
|
|
60
|
+
ctx.send(socket, {
|
|
61
|
+
type: 'guardian_action_decision_response',
|
|
62
|
+
applied: decisionResult.type !== 'stale',
|
|
63
|
+
requestId: msg.requestId,
|
|
64
|
+
reason: decisionResult.type === 'stale' ? 'stale' : undefined,
|
|
65
|
+
});
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const result = applyGuardianDecision({
|
|
70
|
+
approval,
|
|
71
|
+
decision: { action: msg.action as 'approve_once' | 'approve_always' | 'reject', source: 'plain_text', requestId: msg.requestId },
|
|
72
|
+
actorExternalUserId: undefined,
|
|
73
|
+
actorChannel: 'vellum',
|
|
74
|
+
});
|
|
75
|
+
ctx.send(socket, {
|
|
76
|
+
type: 'guardian_action_decision_response',
|
|
77
|
+
applied: result.applied,
|
|
78
|
+
reason: result.reason,
|
|
79
|
+
requestId: result.requestId ?? msg.requestId,
|
|
80
|
+
});
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Fall back to the pending interactions tracker (direct confirmation requests).
|
|
85
|
+
// Route through handleChannelDecision so approve_always properly persists trust rules.
|
|
86
|
+
const interaction = pendingInteractions.get(msg.requestId);
|
|
87
|
+
if (interaction) {
|
|
88
|
+
// Enforce conversationId scoping when provided.
|
|
89
|
+
if (msg.conversationId && msg.conversationId !== interaction.conversationId) {
|
|
90
|
+
log.warn({ requestId: msg.requestId, expected: interaction.conversationId, got: msg.conversationId }, 'conversationId mismatch');
|
|
91
|
+
ctx.send(socket, {
|
|
92
|
+
type: 'guardian_action_decision_response',
|
|
93
|
+
applied: false,
|
|
94
|
+
reason: 'conversation_mismatch',
|
|
95
|
+
requestId: msg.requestId,
|
|
96
|
+
});
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const result = handleChannelDecision(
|
|
101
|
+
interaction.conversationId,
|
|
102
|
+
{ action: msg.action as ApprovalAction, source: 'plain_text', requestId: msg.requestId },
|
|
103
|
+
);
|
|
104
|
+
ctx.send(socket, {
|
|
105
|
+
type: 'guardian_action_decision_response',
|
|
106
|
+
applied: result.applied,
|
|
107
|
+
requestId: result.requestId ?? msg.requestId,
|
|
108
|
+
});
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
log.warn({ requestId: msg.requestId }, 'No pending guardian action found for requestId');
|
|
113
|
+
ctx.send(socket, {
|
|
114
|
+
type: 'guardian_action_decision_response',
|
|
115
|
+
applied: false,
|
|
116
|
+
reason: 'not_found',
|
|
117
|
+
requestId: msg.requestId,
|
|
118
|
+
});
|
|
119
|
+
},
|
|
120
|
+
});
|
|
@@ -6,6 +6,7 @@ import type { ClientMessage } from '../ipc-protocol.js';
|
|
|
6
6
|
import { handleRideShotgunStart, handleRideShotgunStop } from '../ride-shotgun-handler.js';
|
|
7
7
|
import { handleWatchObservation } from '../watch-handler.js';
|
|
8
8
|
import { appHandlers } from './apps.js';
|
|
9
|
+
import { avatarHandlers } from './avatar.js';
|
|
9
10
|
import { browserHandlers } from './browser.js';
|
|
10
11
|
import { computerUseHandlers } from './computer-use.js';
|
|
11
12
|
import { configHandlers } from './config.js';
|
|
@@ -13,6 +14,7 @@ import { inboxInviteHandlers } from './config-inbox.js';
|
|
|
13
14
|
import { diagnosticsHandlers } from './diagnostics.js';
|
|
14
15
|
import { dictationHandlers } from './dictation.js';
|
|
15
16
|
import { documentHandlers } from './documents.js';
|
|
17
|
+
import { guardianActionsHandlers } from './guardian-actions.js';
|
|
16
18
|
import { homeBaseHandlers } from './home-base.js';
|
|
17
19
|
import { identityHandlers } from './identity.js';
|
|
18
20
|
import { miscHandlers } from './misc.js';
|
|
@@ -140,6 +142,7 @@ const handlers = {
|
|
|
140
142
|
...sessionHandlers,
|
|
141
143
|
...skillHandlers,
|
|
142
144
|
...appHandlers,
|
|
145
|
+
...avatarHandlers,
|
|
143
146
|
...configHandlers,
|
|
144
147
|
...computerUseHandlers,
|
|
145
148
|
...publishHandlers,
|
|
@@ -147,6 +150,7 @@ const handlers = {
|
|
|
147
150
|
...diagnosticsHandlers,
|
|
148
151
|
...miscHandlers,
|
|
149
152
|
...documentHandlers,
|
|
153
|
+
...guardianActionsHandlers,
|
|
150
154
|
...workItemHandlers,
|
|
151
155
|
...subagentHandlers,
|
|
152
156
|
...browserHandlers,
|
|
@@ -24,6 +24,7 @@ import type {
|
|
|
24
24
|
HistoryRequest,
|
|
25
25
|
MessageContentRequest,
|
|
26
26
|
RegenerateRequest,
|
|
27
|
+
ReorderThreadsRequest,
|
|
27
28
|
SandboxSetRequest,
|
|
28
29
|
SecretResponse,
|
|
29
30
|
ServerMessage,
|
|
@@ -547,6 +548,7 @@ export function handleSessionList(socket: net.Socket, ctx: HandlerContext, offse
|
|
|
547
548
|
const conversationIds = conversations.map((c) => c.id);
|
|
548
549
|
const bindings = externalConversationStore.getBindingsForConversations(conversationIds);
|
|
549
550
|
const attentionStates = getAttentionStateByConversationIds(conversationIds);
|
|
551
|
+
const displayMetas = conversationStore.getDisplayMetaForConversations(conversationIds);
|
|
550
552
|
ctx.send(socket, {
|
|
551
553
|
type: 'session_list_response',
|
|
552
554
|
sessions: conversations.map((c) => {
|
|
@@ -554,6 +556,7 @@ export function handleSessionList(socket: net.Socket, ctx: HandlerContext, offse
|
|
|
554
556
|
const originChannel = parseChannelId(c.originChannel);
|
|
555
557
|
const originInterface = parseInterfaceId(c.originInterface);
|
|
556
558
|
const attn = attentionStates.get(c.id);
|
|
559
|
+
const displayMeta = displayMetas.get(c.id);
|
|
557
560
|
const assistantAttention = attn ? {
|
|
558
561
|
hasUnseenLatestAssistantMessage: attn.latestAssistantMessageAt != null &&
|
|
559
562
|
(attn.lastSeenAssistantMessageAt == null || attn.lastSeenAssistantMessageAt < attn.latestAssistantMessageAt),
|
|
@@ -581,6 +584,8 @@ export function handleSessionList(socket: net.Socket, ctx: HandlerContext, offse
|
|
|
581
584
|
...(originChannel ? { conversationOriginChannel: originChannel } : {}),
|
|
582
585
|
...(originInterface ? { conversationOriginInterface: originInterface } : {}),
|
|
583
586
|
...(assistantAttention ? { assistantAttention } : {}),
|
|
587
|
+
...(displayMeta?.displayOrder != null ? { displayOrder: displayMeta.displayOrder } : {}),
|
|
588
|
+
...(displayMeta?.isPinned ? { isPinned: displayMeta.isPinned } : {}),
|
|
584
589
|
};
|
|
585
590
|
}),
|
|
586
591
|
hasMore: offset + conversations.length < totalCount,
|
|
@@ -1145,6 +1150,19 @@ export function handleMessageContentRequest(
|
|
|
1145
1150
|
});
|
|
1146
1151
|
}
|
|
1147
1152
|
|
|
1153
|
+
export function handleReorderThreads(
|
|
1154
|
+
msg: ReorderThreadsRequest,
|
|
1155
|
+
_socket: net.Socket,
|
|
1156
|
+
_ctx: HandlerContext,
|
|
1157
|
+
): void {
|
|
1158
|
+
if (!Array.isArray(msg.updates)) {
|
|
1159
|
+
return;
|
|
1160
|
+
}
|
|
1161
|
+
conversationStore.batchSetDisplayOrders(
|
|
1162
|
+
msg.updates.map((u) => ({ id: u.sessionId, displayOrder: u.displayOrder ?? null, isPinned: u.isPinned ?? false })),
|
|
1163
|
+
);
|
|
1164
|
+
}
|
|
1165
|
+
|
|
1148
1166
|
export const sessionHandlers = defineHandlers({
|
|
1149
1167
|
user_message: handleUserMessage,
|
|
1150
1168
|
confirmation_response: handleConfirmationResponse,
|
|
@@ -1163,4 +1181,5 @@ export const sessionHandlers = defineHandlers({
|
|
|
1163
1181
|
usage_request: handleUsageRequest,
|
|
1164
1182
|
sandbox_set: handleSandboxSet,
|
|
1165
1183
|
conversation_search: handleConversationSearch,
|
|
1184
|
+
reorder_threads: handleReorderThreads,
|
|
1166
1185
|
});
|
|
@@ -177,8 +177,10 @@ export function getScreenDimensions(): { width: number; height: number } {
|
|
|
177
177
|
if (cachedScreenDims) return cachedScreenDims;
|
|
178
178
|
if (process.platform !== 'darwin') return FALLBACK_SCREEN;
|
|
179
179
|
try {
|
|
180
|
+
// Use osascript (JXA) instead of `swift` to avoid the
|
|
181
|
+
// "Install Command Line Developer Tools" popup on fresh macOS installs.
|
|
180
182
|
const out = execSync(
|
|
181
|
-
`
|
|
183
|
+
`osascript -l JavaScript -e 'ObjC.import("AppKit"); var f = $.NSScreen.mainScreen.frame; Math.round(f.size.width) + "x" + Math.round(f.size.height)'`,
|
|
182
184
|
{ timeout: 10_000, encoding: 'utf-8' },
|
|
183
185
|
).trim();
|
|
184
186
|
const [w, h] = out.split('x').map(Number);
|
|
@@ -1,24 +1,30 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Installs standalone CLI launcher scripts in ~/.vellum/bin/ so that
|
|
3
|
-
* integration commands (e.g. `
|
|
4
|
-
*
|
|
3
|
+
* integration commands (e.g. `map`) can be invoked directly without
|
|
4
|
+
* requiring `vellum` on PATH.
|
|
5
5
|
*
|
|
6
6
|
* Each launcher is a shell script that hardcodes absolute paths to `bun`
|
|
7
7
|
* and the CLI entrypoint, forwarding all arguments to the appropriate
|
|
8
8
|
* subcommand.
|
|
9
|
+
*
|
|
10
|
+
* Commands are split into two categories:
|
|
11
|
+
* - CORE_COMMANDS: always installed, dispatched via the main CLI entrypoint
|
|
12
|
+
* - Skill CLI launchers: dynamically discovered from installed skills that
|
|
13
|
+
* declare a `cli` entry in their SKILL.md frontmatter metadata
|
|
9
14
|
*/
|
|
10
15
|
|
|
11
16
|
import { execSync } from 'node:child_process';
|
|
12
|
-
import { chmodSync,existsSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
17
|
+
import { chmodSync, existsSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
13
18
|
import { homedir } from 'node:os';
|
|
14
19
|
import { join } from 'node:path';
|
|
15
20
|
|
|
21
|
+
import { loadSkillCatalog } from '../config/skills.js';
|
|
16
22
|
import { getLogger } from '../util/logger.js';
|
|
17
23
|
|
|
18
24
|
const log = getLogger('install-cli-launchers');
|
|
19
25
|
|
|
20
|
-
/**
|
|
21
|
-
const
|
|
26
|
+
/** Core subcommands dispatched via the main CLI entrypoint (index.ts). */
|
|
27
|
+
const CORE_COMMANDS = ['map'];
|
|
22
28
|
|
|
23
29
|
/**
|
|
24
30
|
* Resolve the absolute path to the bun binary.
|
|
@@ -68,9 +74,13 @@ function hasSystemConflict(name: string, binDir: string): boolean {
|
|
|
68
74
|
* Install standalone CLI launcher scripts in ~/.vellum/bin/.
|
|
69
75
|
*
|
|
70
76
|
* For each integration command, generates a shell script that execs
|
|
71
|
-
* bun with the
|
|
77
|
+
* bun with the appropriate entrypoint.
|
|
72
78
|
* Uses the short name by default (e.g. `doordash`), falling back to
|
|
73
79
|
* `vellum-<name>` if the short name conflicts with an existing system binary.
|
|
80
|
+
*
|
|
81
|
+
* Skill CLI launchers are discovered dynamically: any installed skill whose
|
|
82
|
+
* SKILL.md frontmatter declares `metadata.vellum.cli` will get a launcher
|
|
83
|
+
* pointing to the declared entry file within the skill directory.
|
|
74
84
|
*/
|
|
75
85
|
export function installCliLaunchers(): void {
|
|
76
86
|
const binDir = join(homedir(), '.vellum', 'bin');
|
|
@@ -83,13 +93,13 @@ export function installCliLaunchers(): void {
|
|
|
83
93
|
return;
|
|
84
94
|
}
|
|
85
95
|
|
|
86
|
-
const
|
|
87
|
-
if (!existsSync(
|
|
96
|
+
const mainEntrypoint = resolveCliEntrypoint();
|
|
97
|
+
if (!existsSync(mainEntrypoint)) {
|
|
88
98
|
// In compiled builds (e.g. macOS app via `bun build --compile`), the
|
|
89
99
|
// source tree isn't available. Launcher scripts are a dev-mode
|
|
90
100
|
// convenience; compiled builds use their own command dispatch, so we
|
|
91
101
|
// silently skip installation.
|
|
92
|
-
log.debug({ entrypoint }, 'CLI entrypoint not found (compiled build?) — skipping launcher installation');
|
|
102
|
+
log.debug({ entrypoint: mainEntrypoint }, 'CLI entrypoint not found (compiled build?) — skipping launcher installation');
|
|
93
103
|
return;
|
|
94
104
|
}
|
|
95
105
|
|
|
@@ -97,18 +107,53 @@ export function installCliLaunchers(): void {
|
|
|
97
107
|
mkdirSync(binDir, { recursive: true });
|
|
98
108
|
}
|
|
99
109
|
|
|
100
|
-
|
|
110
|
+
const installed: string[] = [];
|
|
111
|
+
|
|
112
|
+
// Install core command launchers (dispatched via main CLI)
|
|
113
|
+
for (const name of CORE_COMMANDS) {
|
|
101
114
|
const launcherName = hasSystemConflict(name, binDir) ? `vellum-${name}` : name;
|
|
102
115
|
const launcherPath = join(binDir, launcherName);
|
|
103
116
|
|
|
104
117
|
const script = `#!/bin/bash
|
|
105
|
-
exec "${bunPath}" "${
|
|
118
|
+
exec "${bunPath}" "${mainEntrypoint}" ${name} "$@"
|
|
106
119
|
`;
|
|
107
120
|
|
|
108
121
|
writeFileSync(launcherPath, script);
|
|
109
122
|
chmodSync(launcherPath, 0o755);
|
|
110
|
-
|
|
123
|
+
installed.push(launcherName);
|
|
124
|
+
log.debug({ launcherName, launcherPath }, 'Installed core CLI launcher');
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Discover and install skill CLI launchers from the skill catalog
|
|
128
|
+
try {
|
|
129
|
+
const catalog = loadSkillCatalog();
|
|
130
|
+
for (const skill of catalog) {
|
|
131
|
+
const cli = skill.metadata?.cli;
|
|
132
|
+
if (!cli?.command || !cli?.entry) continue;
|
|
133
|
+
|
|
134
|
+
const entrypoint = join(skill.directoryPath, cli.entry);
|
|
135
|
+
if (!existsSync(entrypoint)) {
|
|
136
|
+
log.debug({ skillId: skill.id, entrypoint }, 'Skill CLI entry point not found — skipping');
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const launcherName = hasSystemConflict(cli.command, binDir)
|
|
141
|
+
? `vellum-${cli.command}`
|
|
142
|
+
: cli.command;
|
|
143
|
+
const launcherPath = join(binDir, launcherName);
|
|
144
|
+
|
|
145
|
+
const script = `#!/bin/bash
|
|
146
|
+
exec "${bunPath}" "${entrypoint}" "$@"
|
|
147
|
+
`;
|
|
148
|
+
|
|
149
|
+
writeFileSync(launcherPath, script);
|
|
150
|
+
chmodSync(launcherPath, 0o755);
|
|
151
|
+
installed.push(launcherName);
|
|
152
|
+
log.debug({ launcherName, launcherPath, skillId: skill.id }, 'Installed skill CLI launcher');
|
|
153
|
+
}
|
|
154
|
+
} catch (err) {
|
|
155
|
+
log.warn({ err }, 'Failed to discover skill CLI launchers');
|
|
111
156
|
}
|
|
112
157
|
|
|
113
|
-
log.info({ binDir, commands:
|
|
158
|
+
log.info({ binDir, commands: installed }, 'CLI launchers installed');
|
|
114
159
|
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
// Guardian action decision IPC types.
|
|
2
|
+
// Enables desktop clients to fetch pending guardian prompts and submit
|
|
3
|
+
// button decisions deterministically (without text parsing).
|
|
4
|
+
|
|
5
|
+
// === Client -> Server ===
|
|
6
|
+
|
|
7
|
+
export interface GuardianActionsPendingRequest {
|
|
8
|
+
type: 'guardian_actions_pending_request';
|
|
9
|
+
conversationId: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface GuardianActionDecision {
|
|
13
|
+
type: 'guardian_action_decision';
|
|
14
|
+
requestId: string;
|
|
15
|
+
action: string;
|
|
16
|
+
conversationId?: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// === Server -> Client ===
|
|
20
|
+
|
|
21
|
+
export interface GuardianActionsPendingResponse {
|
|
22
|
+
type: 'guardian_actions_pending_response';
|
|
23
|
+
conversationId: string;
|
|
24
|
+
prompts: Array<{
|
|
25
|
+
requestId: string;
|
|
26
|
+
requestCode: string;
|
|
27
|
+
state: string;
|
|
28
|
+
questionText: string;
|
|
29
|
+
toolName: string | null;
|
|
30
|
+
actions: Array<{ action: string; label: string }>;
|
|
31
|
+
expiresAt: number;
|
|
32
|
+
conversationId: string;
|
|
33
|
+
callSessionId: string | null;
|
|
34
|
+
}>;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface GuardianActionDecisionResponse {
|
|
38
|
+
type: 'guardian_action_decision_response';
|
|
39
|
+
applied: boolean;
|
|
40
|
+
reason?: string;
|
|
41
|
+
requestId?: string;
|
|
42
|
+
userText?: string;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// --- Domain-level union aliases (consumed by the barrel file) ---
|
|
46
|
+
|
|
47
|
+
export type _GuardianActionsClientMessages =
|
|
48
|
+
| GuardianActionsPendingRequest
|
|
49
|
+
| GuardianActionDecision;
|
|
50
|
+
|
|
51
|
+
export type _GuardianActionsServerMessages =
|
|
52
|
+
| GuardianActionsPendingResponse
|
|
53
|
+
| GuardianActionDecisionResponse;
|
|
@@ -156,6 +156,11 @@ export interface ConversationSearchRequest {
|
|
|
156
156
|
maxMessagesPerConversation?: number;
|
|
157
157
|
}
|
|
158
158
|
|
|
159
|
+
export interface ReorderThreadsRequest {
|
|
160
|
+
type: 'reorder_threads';
|
|
161
|
+
updates: Array<{ sessionId: string; displayOrder: number | null; isPinned: boolean }>;
|
|
162
|
+
}
|
|
163
|
+
|
|
159
164
|
// === Server → Client ===
|
|
160
165
|
|
|
161
166
|
export interface ConversationSearchMatchingMessage {
|
|
@@ -213,7 +218,7 @@ export interface AssistantAttention {
|
|
|
213
218
|
|
|
214
219
|
export interface SessionListResponse {
|
|
215
220
|
type: 'session_list_response';
|
|
216
|
-
sessions: Array<{ id: string; title: string; createdAt?: number; updatedAt: number; threadType?: ThreadType; source?: string; channelBinding?: ChannelBinding; conversationOriginChannel?: ChannelId; conversationOriginInterface?: InterfaceId; assistantAttention?: AssistantAttention }>;
|
|
221
|
+
sessions: Array<{ id: string; title: string; createdAt?: number; updatedAt: number; threadType?: ThreadType; source?: string; channelBinding?: ChannelBinding; conversationOriginChannel?: ChannelId; conversationOriginInterface?: InterfaceId; assistantAttention?: AssistantAttention; displayOrder?: number; isPinned?: boolean }>;
|
|
217
222
|
/** Whether more sessions exist beyond the returned page. */
|
|
218
223
|
hasMore?: boolean;
|
|
219
224
|
}
|
|
@@ -392,7 +397,8 @@ export type _SessionsClientMessages =
|
|
|
392
397
|
| SessionRenameRequest
|
|
393
398
|
| SessionsClearRequest
|
|
394
399
|
| ConversationSearchRequest
|
|
395
|
-
| MessageContentRequest
|
|
400
|
+
| MessageContentRequest
|
|
401
|
+
| ReorderThreadsRequest;
|
|
396
402
|
|
|
397
403
|
export type _SessionsServerMessages =
|
|
398
404
|
| AuthResult
|