@vellumai/assistant 0.3.15 → 0.3.18
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 +211 -12
- package/Dockerfile +1 -1
- package/README.md +11 -5
- package/docs/architecture/http-token-refresh.md +274 -0
- package/docs/architecture/memory.md +5 -4
- package/docs/architecture/scheduling.md +4 -88
- package/docs/runbook-trusted-contacts.md +283 -0
- package/docs/trusted-contact-access.md +247 -0
- package/package.json +1 -1
- package/scripts/ipc/check-swift-decoder-drift.ts +2 -0
- package/src/__tests__/__snapshots__/ipc-snapshot.test.ts.snap +2 -6
- package/src/__tests__/access-request-decision.test.ts +328 -0
- package/src/__tests__/asset-materialize-tool.test.ts +7 -7
- package/src/__tests__/asset-search-tool.test.ts +15 -15
- package/src/__tests__/attachments-store.test.ts +13 -13
- package/src/__tests__/call-controller.test.ts +150 -4
- package/src/__tests__/call-conversation-messages.test.ts +2 -2
- package/src/__tests__/call-pointer-messages.test.ts +28 -0
- package/src/__tests__/call-start-guardian-guard.test.ts +93 -0
- package/src/__tests__/channel-approval-routes.test.ts +108 -12
- package/src/__tests__/channel-guardian.test.ts +19 -15
- package/src/__tests__/checker.test.ts +103 -48
- package/src/__tests__/computer-use-skill-manifest-regression.test.ts +2 -2
- package/src/__tests__/config-watcher.test.ts +356 -0
- package/src/__tests__/conversation-pairing.test.ts +127 -27
- package/src/__tests__/conversation-store.test.ts +36 -36
- package/src/__tests__/date-context.test.ts +179 -1
- package/src/__tests__/db-migration-rollback.test.ts +4 -7
- package/src/__tests__/deterministic-verification-control-plane.test.ts +5 -5
- package/src/__tests__/emit-signal-routing-intent.test.ts +179 -0
- package/src/__tests__/gateway-only-guard.test.ts +188 -0
- package/src/__tests__/guardian-action-conversation-turn.test.ts +451 -0
- package/src/__tests__/guardian-action-copy-generator.test.ts +197 -0
- package/src/__tests__/guardian-action-followup-executor.test.ts +379 -0
- package/src/__tests__/guardian-action-followup-store.test.ts +376 -0
- package/src/__tests__/guardian-action-late-reply.test.ts +425 -0
- package/src/__tests__/guardian-action-no-hardcoded-copy.test.ts +71 -0
- package/src/__tests__/guardian-action-store.test.ts +182 -0
- package/src/__tests__/guardian-action-sweep.test.ts +9 -9
- package/src/__tests__/guardian-dispatch.test.ts +120 -0
- package/src/__tests__/guardian-outbound-http.test.ts +194 -2
- package/src/__tests__/guardian-verification-intent-routing.test.ts +179 -0
- package/src/__tests__/guardian-verify-setup-skill-regression.test.ts +141 -0
- package/src/__tests__/handlers-telegram-config.test.ts +6 -6
- package/src/__tests__/hooks-runner.test.ts +13 -4
- package/src/__tests__/ingress-routes-http.test.ts +443 -0
- package/src/__tests__/intent-routing.test.ts +14 -0
- package/src/__tests__/ipc-snapshot.test.ts +23 -5
- package/src/__tests__/media-reuse-story.e2e.test.ts +7 -7
- package/src/__tests__/memory-regressions.test.ts +16 -12
- package/src/__tests__/non-member-access-request.test.ts +281 -0
- package/src/__tests__/notification-broadcaster.test.ts +115 -4
- package/src/__tests__/notification-decision-strategy.test.ts +138 -1
- package/src/__tests__/notification-deep-link.test.ts +44 -1
- package/src/__tests__/notification-guardian-path.test.ts +157 -0
- package/src/__tests__/notification-routing-intent.test.ts +11 -1
- package/src/__tests__/notification-thread-candidate-validation.test.ts +215 -0
- package/src/__tests__/notification-thread-candidates.test.ts +166 -0
- package/src/__tests__/recording-intent.test.ts +1 -0
- package/src/__tests__/recording-state-machine.test.ts +328 -17
- package/src/__tests__/registry.test.ts +17 -8
- package/src/__tests__/relay-server.test.ts +105 -0
- package/src/__tests__/reminder.test.ts +13 -0
- package/src/__tests__/runtime-attachment-metadata.test.ts +4 -4
- package/src/__tests__/scheduler-recurrence.test.ts +50 -0
- package/src/__tests__/server-history-render.test.ts +8 -8
- package/src/__tests__/session-agent-loop.test.ts +1 -0
- package/src/__tests__/session-runtime-assembly.test.ts +49 -0
- package/src/__tests__/session-skill-tools.test.ts +1 -0
- package/src/__tests__/skill-projection.benchmark.test.ts +11 -3
- package/src/__tests__/slack-channel-config.test.ts +230 -0
- package/src/__tests__/subagent-manager-notify.test.ts +4 -4
- package/src/__tests__/swarm-session-integration.test.ts +2 -2
- package/src/__tests__/system-prompt.test.ts +43 -0
- package/src/__tests__/task-management-tools.test.ts +3 -3
- package/src/__tests__/task-tools.test.ts +3 -3
- package/src/__tests__/trust-store.test.ts +38 -22
- package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +489 -0
- package/src/__tests__/trusted-contact-multichannel.test.ts +405 -0
- package/src/__tests__/trusted-contact-verification.test.ts +360 -0
- package/src/__tests__/update-bulletin-format.test.ts +119 -0
- package/src/__tests__/update-bulletin-state.test.ts +129 -0
- package/src/__tests__/update-bulletin.test.ts +323 -0
- package/src/__tests__/update-template-contract.test.ts +24 -0
- package/src/__tests__/voice-session-bridge.test.ts +109 -9
- package/src/agent/loop.ts +2 -2
- package/src/amazon/client.ts +2 -3
- package/src/calls/call-controller.ts +241 -39
- package/src/calls/call-conversation-messages.ts +2 -2
- package/src/calls/call-domain.ts +10 -3
- package/src/calls/call-pointer-messages.ts +17 -5
- package/src/calls/guardian-action-sweep.ts +77 -36
- package/src/calls/guardian-dispatch.ts +8 -0
- package/src/calls/relay-server.ts +51 -12
- package/src/calls/twilio-routes.ts +3 -1
- package/src/calls/types.ts +1 -1
- package/src/calls/voice-session-bridge.ts +8 -6
- package/src/cli/core-commands.ts +43 -3
- package/src/cli/map.ts +8 -5
- package/src/config/bundled-skills/phone-calls/SKILL.md +16 -1
- package/src/config/bundled-skills/tasks/SKILL.md +1 -1
- package/src/config/bundled-skills/tasks/TOOLS.json +4 -4
- package/src/config/bundled-skills/time-based-actions/SKILL.md +11 -1
- package/src/config/computer-use-prompt.ts +1 -0
- package/src/config/core-schema.ts +16 -0
- package/src/config/env-registry.ts +1 -0
- package/src/config/env.ts +16 -1
- package/src/config/memory-schema.ts +5 -0
- package/src/config/schema.ts +4 -0
- package/src/config/system-prompt.ts +69 -2
- package/src/config/templates/BOOTSTRAP.md +1 -1
- package/src/config/templates/IDENTITY.md +8 -4
- package/src/config/templates/SOUL.md +14 -0
- package/src/config/templates/UPDATES.md +15 -0
- package/src/config/templates/USER.md +5 -1
- package/src/config/types.ts +1 -0
- package/src/config/update-bulletin-format.ts +54 -0
- package/src/config/update-bulletin-state.ts +49 -0
- package/src/config/update-bulletin-template-path.ts +6 -0
- package/src/config/update-bulletin.ts +97 -0
- package/src/config/vellum-skills/catalog.json +6 -0
- package/src/config/vellum-skills/chatgpt-import/tools/chatgpt-import.ts +1 -1
- package/src/config/vellum-skills/guardian-verify-setup/SKILL.md +44 -10
- package/src/config/vellum-skills/telegram-setup/SKILL.md +4 -4
- package/src/config/vellum-skills/trusted-contacts/SKILL.md +147 -0
- package/src/config/vellum-skills/twilio-setup/SKILL.md +2 -2
- package/src/context/window-manager.ts +43 -3
- package/src/daemon/config-watcher.ts +4 -2
- package/src/daemon/connection-policy.ts +21 -1
- package/src/daemon/daemon-control.ts +219 -8
- package/src/daemon/date-context.ts +174 -1
- package/src/daemon/guardian-action-generators.ts +175 -0
- package/src/daemon/guardian-verification-intent.ts +120 -0
- package/src/daemon/handlers/apps.ts +1 -3
- package/src/daemon/handlers/config-channels.ts +2 -2
- package/src/daemon/handlers/config-heartbeat.ts +1 -1
- package/src/daemon/handlers/config-inbox.ts +55 -159
- package/src/daemon/handlers/config-ingress.ts +1 -1
- package/src/daemon/handlers/config-integrations.ts +1 -1
- package/src/daemon/handlers/config-platform.ts +1 -1
- package/src/daemon/handlers/config-scheduling.ts +2 -2
- package/src/daemon/handlers/config-slack-channel.ts +190 -0
- package/src/daemon/handlers/config-telegram.ts +1 -1
- package/src/daemon/handlers/config-twilio.ts +1 -1
- package/src/daemon/handlers/config-voice.ts +100 -0
- package/src/daemon/handlers/config.ts +3 -0
- package/src/daemon/handlers/identity.ts +45 -25
- package/src/daemon/handlers/misc.ts +83 -5
- package/src/daemon/handlers/navigate-settings.ts +27 -0
- package/src/daemon/handlers/recording.ts +270 -144
- package/src/daemon/handlers/sessions.ts +100 -17
- package/src/daemon/handlers/subagents.ts +3 -3
- package/src/daemon/handlers/work-items.ts +10 -7
- package/src/daemon/ipc-contract/integrations.ts +9 -1
- package/src/daemon/ipc-contract/messages.ts +4 -0
- package/src/daemon/ipc-contract/sessions.ts +1 -1
- package/src/daemon/ipc-contract/settings.ts +26 -0
- package/src/daemon/ipc-contract/shared.ts +2 -0
- package/src/daemon/ipc-contract/work-items.ts +1 -7
- package/src/daemon/ipc-contract/workspace.ts +12 -1
- package/src/daemon/ipc-contract-inventory.json +6 -1
- package/src/daemon/ipc-contract.ts +5 -1
- package/src/daemon/lifecycle.ts +314 -266
- package/src/daemon/recording-intent.ts +0 -41
- package/src/daemon/response-tier.ts +2 -2
- package/src/daemon/server.ts +31 -9
- package/src/daemon/session-agent-loop-handlers.ts +34 -9
- package/src/daemon/session-agent-loop.ts +15 -8
- package/src/daemon/session-history.ts +3 -2
- package/src/daemon/session-media-retry.ts +3 -0
- package/src/daemon/session-messaging.ts +38 -4
- package/src/daemon/session-notifiers.ts +2 -2
- package/src/daemon/session-process.ts +546 -59
- package/src/daemon/session-queue-manager.ts +2 -0
- package/src/daemon/session-runtime-assembly.ts +39 -0
- package/src/daemon/session-skill-tools.ts +13 -4
- package/src/daemon/session-tool-setup.ts +5 -6
- package/src/daemon/session.ts +19 -8
- package/src/daemon/tls-certs.ts +60 -13
- package/src/daemon/tool-side-effects.ts +13 -5
- package/src/gallery/default-gallery.ts +32 -9
- package/src/influencer/client.ts +2 -1
- package/src/memory/channel-delivery-store.ts +35 -567
- package/src/memory/channel-guardian-store.ts +63 -1317
- package/src/memory/conflict-store.ts +4 -4
- package/src/memory/conversation-attention-store.ts +0 -3
- package/src/memory/conversation-crud.ts +668 -0
- package/src/memory/conversation-queries.ts +361 -0
- package/src/memory/conversation-store.ts +44 -983
- package/src/memory/db-connection.ts +3 -0
- package/src/memory/db-init.ts +33 -0
- package/src/memory/delivery-channels.ts +175 -0
- package/src/memory/delivery-crud.ts +211 -0
- package/src/memory/delivery-status.ts +199 -0
- package/src/memory/embedding-backend.ts +70 -4
- package/src/memory/embedding-local.ts +12 -2
- package/src/memory/entity-extractor.ts +3 -8
- package/src/memory/fts-reconciler.ts +136 -0
- package/src/memory/guardian-action-store.ts +418 -5
- package/src/memory/guardian-approvals.ts +569 -0
- package/src/memory/guardian-bindings.ts +130 -0
- package/src/memory/guardian-rate-limits.ts +196 -0
- package/src/memory/guardian-verification.ts +521 -0
- package/src/memory/job-handlers/index-maintenance.ts +2 -1
- package/src/memory/job-utils.ts +8 -5
- package/src/memory/jobs-store.ts +66 -6
- package/src/memory/jobs-worker.ts +23 -1
- package/src/memory/migrations/030-guardian-action-followup.ts +21 -0
- package/src/memory/migrations/030-guardian-verification-purpose.ts +17 -0
- package/src/memory/migrations/031-conversations-thread-type-index.ts +5 -0
- package/src/memory/migrations/032-guardian-delivery-conversation-index.ts +15 -0
- package/src/memory/migrations/032-notification-delivery-thread-decision.ts +20 -0
- package/src/memory/migrations/100-core-tables.ts +1 -1
- package/src/memory/migrations/101-watchers-and-logs.ts +4 -0
- package/src/memory/migrations/108-tasks-and-work-items.ts +1 -1
- package/src/memory/migrations/112-assistant-inbox.ts +1 -1
- package/src/memory/migrations/113-late-migrations.ts +1 -1
- package/src/memory/migrations/116-messages-fts.ts +13 -0
- package/src/memory/migrations/119-schema-indexes-and-columns.ts +37 -0
- package/src/memory/migrations/120-fk-cascade-rebuilds.ts +161 -0
- package/src/memory/migrations/index.ts +10 -3
- package/src/memory/migrations/validate-migration-state.ts +114 -15
- package/src/memory/qdrant-circuit-breaker.ts +105 -0
- package/src/memory/retriever.ts +46 -13
- package/src/memory/schema-migration.ts +4 -0
- package/src/memory/schema.ts +31 -8
- package/src/memory/search/semantic.ts +8 -90
- package/src/notifications/README.md +159 -18
- package/src/notifications/broadcaster.ts +69 -33
- package/src/notifications/conversation-pairing.ts +99 -21
- package/src/notifications/decision-engine.ts +176 -8
- package/src/notifications/deliveries-store.ts +39 -8
- package/src/notifications/emit-signal.ts +1 -0
- package/src/notifications/preferences-store.ts +7 -7
- package/src/notifications/thread-candidates.ts +269 -0
- package/src/notifications/types.ts +19 -0
- package/src/permissions/checker.ts +1 -16
- package/src/permissions/defaults.ts +25 -5
- package/src/permissions/prompter.ts +17 -0
- package/src/permissions/trust-store.ts +2 -0
- package/src/providers/failover.ts +19 -0
- package/src/providers/registry.ts +46 -1
- package/src/runtime/approval-message-composer.ts +1 -1
- package/src/runtime/channel-guardian-service.ts +15 -3
- package/src/runtime/channel-retry-sweep.ts +7 -2
- package/src/runtime/guardian-action-conversation-turn.ts +85 -0
- package/src/runtime/guardian-action-followup-executor.ts +301 -0
- package/src/runtime/guardian-action-message-composer.ts +245 -0
- package/src/runtime/guardian-outbound-actions.ts +26 -6
- package/src/runtime/guardian-verification-templates.ts +15 -9
- package/src/runtime/http-errors.ts +93 -0
- package/src/runtime/http-server.ts +133 -44
- package/src/runtime/http-types.ts +53 -0
- package/src/runtime/ingress-service.ts +237 -0
- package/src/runtime/middleware/error-handler.ts +4 -3
- package/src/runtime/middleware/rate-limiter.ts +160 -0
- package/src/runtime/middleware/request-logger.ts +71 -0
- package/src/runtime/middleware/twilio-validation.ts +7 -6
- package/src/runtime/pending-interactions.ts +12 -0
- package/src/runtime/routes/access-request-decision.ts +215 -0
- package/src/runtime/routes/app-routes.ts +25 -18
- package/src/runtime/routes/approval-routes.ts +18 -47
- package/src/runtime/routes/attachment-routes.ts +15 -41
- package/src/runtime/routes/call-routes.ts +20 -20
- package/src/runtime/routes/channel-delivery-routes.ts +6 -5
- package/src/runtime/routes/contact-routes.ts +4 -9
- package/src/runtime/routes/conversation-attention-routes.ts +2 -1
- package/src/runtime/routes/conversation-routes.ts +26 -57
- package/src/runtime/routes/debug-routes.ts +71 -0
- package/src/runtime/routes/events-routes.ts +3 -2
- package/src/runtime/routes/guardian-approval-interception.ts +221 -0
- package/src/runtime/routes/identity-routes.ts +14 -10
- package/src/runtime/routes/inbound-conversation.ts +3 -2
- package/src/runtime/routes/inbound-message-handler.ts +527 -62
- package/src/runtime/routes/ingress-routes.ts +174 -0
- package/src/runtime/routes/integration-routes.ts +78 -16
- package/src/runtime/routes/pairing-routes.ts +11 -10
- package/src/runtime/routes/secret-routes.ts +10 -18
- package/src/runtime/verification-rate-limiter.ts +83 -0
- package/src/schedule/schedule-store.ts +13 -1
- package/src/schedule/scheduler.ts +1 -1
- package/src/security/secret-ingress.ts +5 -2
- package/src/security/secret-scanner.ts +72 -6
- package/src/subagent/manager.ts +6 -4
- package/src/swarm/plan-validator.ts +4 -1
- package/src/tasks/task-runner.ts +3 -1
- package/src/tools/browser/api-map.ts +9 -6
- package/src/tools/calls/call-start.ts +20 -0
- package/src/tools/executor.ts +50 -568
- package/src/tools/permission-checker.ts +271 -0
- package/src/tools/registry.ts +14 -6
- package/src/tools/reminder/reminder-store.ts +7 -7
- package/src/tools/reminder/reminder.ts +6 -3
- package/src/tools/secret-detection-handler.ts +301 -0
- package/src/tools/subagent/message.ts +1 -1
- package/src/tools/system/voice-config.ts +62 -0
- package/src/tools/tasks/index.ts +3 -3
- package/src/tools/tasks/work-item-list.ts +3 -3
- package/src/tools/tasks/work-item-update.ts +4 -5
- package/src/tools/tool-approval-handler.ts +192 -0
- package/src/tools/tool-manifest.ts +2 -0
- package/src/version.ts +29 -2
- package/src/watcher/watcher-store.ts +9 -9
- package/src/work-items/work-item-runner.ts +9 -6
- /package/src/memory/migrations/{026-embeddings-nullable-vector-json.ts → 026a-embeddings-nullable-vector-json.ts} +0 -0
- /package/src/memory/migrations/{027-guardian-bootstrap-token.ts → 027a-guardian-bootstrap-token.ts} +0 -0
|
@@ -31,6 +31,7 @@ export { handleTelegramConfig, summarizeTelegramError } from './config-telegram.
|
|
|
31
31
|
export { handleEnvVarsRequest, handleToolNamesList,handleToolPermissionSimulate } from './config-tools.js';
|
|
32
32
|
export { handleAcceptStarterBundle,handleAddTrustRule, handleRemoveTrustRule, handleTrustRulesList, handleUpdateTrustRule } from './config-trust.js';
|
|
33
33
|
export { handleTwilioConfig } from './config-twilio.js';
|
|
34
|
+
export { broadcastClientSettingsUpdate, handleVoiceConfigUpdate, normalizeActivationKey } from './config-voice.js';
|
|
34
35
|
|
|
35
36
|
// Assemble the combined dispatch map from domain-specific handler groups
|
|
36
37
|
import { channelHandlers } from './config-channels.js';
|
|
@@ -46,6 +47,7 @@ import { telegramHandlers } from './config-telegram.js';
|
|
|
46
47
|
import { toolHandlers } from './config-tools.js';
|
|
47
48
|
import { trustHandlers } from './config-trust.js';
|
|
48
49
|
import { twilioHandlers } from './config-twilio.js';
|
|
50
|
+
import { voiceHandlers } from './config-voice.js';
|
|
49
51
|
|
|
50
52
|
export const configHandlers = {
|
|
51
53
|
...modelHandlers,
|
|
@@ -61,4 +63,5 @@ export const configHandlers = {
|
|
|
61
63
|
...toolHandlers,
|
|
62
64
|
...parentalControlHandlers,
|
|
63
65
|
...heartbeatHandlers,
|
|
66
|
+
...voiceHandlers,
|
|
64
67
|
};
|
|
@@ -6,6 +6,45 @@ import { fileURLToPath } from 'node:url';
|
|
|
6
6
|
import { getWorkspacePromptPath, readLockfile } from '../../util/platform.js';
|
|
7
7
|
import { defineHandlers, type HandlerContext,log } from './shared.js';
|
|
8
8
|
|
|
9
|
+
export interface IdentityFields {
|
|
10
|
+
name: string;
|
|
11
|
+
role: string;
|
|
12
|
+
personality: string;
|
|
13
|
+
emoji: string;
|
|
14
|
+
home: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** Parse the core identity fields from IDENTITY.md content. */
|
|
18
|
+
export function parseIdentityFields(content: string): IdentityFields {
|
|
19
|
+
const fields: Record<string, string> = {};
|
|
20
|
+
for (const line of content.split('\n')) {
|
|
21
|
+
const trimmed = line.trim();
|
|
22
|
+
const lower = trimmed.toLowerCase();
|
|
23
|
+
const extract = (prefix: string): string | null => {
|
|
24
|
+
if (!lower.startsWith(prefix)) return null;
|
|
25
|
+
return trimmed.split(':**').pop()?.trim() ?? null;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const name = extract('- **name:**');
|
|
29
|
+
if (name) { fields.name = name; continue; }
|
|
30
|
+
const role = extract('- **role:**');
|
|
31
|
+
if (role) { fields.role = role; continue; }
|
|
32
|
+
const personality = extract('- **personality:**') ?? extract('- **vibe:**');
|
|
33
|
+
if (personality) { fields.personality = personality; continue; }
|
|
34
|
+
const emoji = extract('- **emoji:**');
|
|
35
|
+
if (emoji) { fields.emoji = emoji; continue; }
|
|
36
|
+
const home = extract('- **home:**');
|
|
37
|
+
if (home) { fields.home = home; continue; }
|
|
38
|
+
}
|
|
39
|
+
return {
|
|
40
|
+
name: fields.name ?? '',
|
|
41
|
+
role: fields.role ?? '',
|
|
42
|
+
personality: fields.personality ?? '',
|
|
43
|
+
emoji: fields.emoji ?? '',
|
|
44
|
+
home: fields.home ?? '',
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
9
48
|
function handleIdentityGet(socket: net.Socket, ctx: HandlerContext): void {
|
|
10
49
|
const identityPath = getWorkspacePromptPath('IDENTITY.md');
|
|
11
50
|
|
|
@@ -24,26 +63,7 @@ function handleIdentityGet(socket: net.Socket, ctx: HandlerContext): void {
|
|
|
24
63
|
|
|
25
64
|
try {
|
|
26
65
|
const content = readFileSync(identityPath, 'utf-8');
|
|
27
|
-
const fields
|
|
28
|
-
for (const line of content.split('\n')) {
|
|
29
|
-
const trimmed = line.trim();
|
|
30
|
-
const lower = trimmed.toLowerCase();
|
|
31
|
-
const extract = (prefix: string): string | null => {
|
|
32
|
-
if (!lower.startsWith(prefix)) return null;
|
|
33
|
-
return trimmed.split(':**').pop()?.trim() ?? null;
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
const name = extract('- **name:**');
|
|
37
|
-
if (name) { fields.name = name; continue; }
|
|
38
|
-
const role = extract('- **role:**');
|
|
39
|
-
if (role) { fields.role = role; continue; }
|
|
40
|
-
const personality = extract('- **personality:**') ?? extract('- **vibe:**');
|
|
41
|
-
if (personality) { fields.personality = personality; continue; }
|
|
42
|
-
const emoji = extract('- **emoji:**');
|
|
43
|
-
if (emoji) { fields.emoji = emoji; continue; }
|
|
44
|
-
const home = extract('- **home:**');
|
|
45
|
-
if (home) { fields.home = home; continue; }
|
|
46
|
-
}
|
|
66
|
+
const fields = parseIdentityFields(content);
|
|
47
67
|
|
|
48
68
|
// Read version from package.json
|
|
49
69
|
let version: string | undefined;
|
|
@@ -90,11 +110,11 @@ function handleIdentityGet(socket: net.Socket, ctx: HandlerContext): void {
|
|
|
90
110
|
ctx.send(socket, {
|
|
91
111
|
type: 'identity_get_response',
|
|
92
112
|
found: true,
|
|
93
|
-
name: fields.name
|
|
94
|
-
role: fields.role
|
|
95
|
-
personality: fields.personality
|
|
96
|
-
emoji: fields.emoji
|
|
97
|
-
home: fields.home
|
|
113
|
+
name: fields.name,
|
|
114
|
+
role: fields.role,
|
|
115
|
+
personality: fields.personality,
|
|
116
|
+
emoji: fields.emoji,
|
|
117
|
+
home: fields.home,
|
|
98
118
|
version,
|
|
99
119
|
assistantId,
|
|
100
120
|
createdAt,
|
|
@@ -81,13 +81,22 @@ export async function handleTaskSubmit(
|
|
|
81
81
|
const conversation = conversationStore.createConversation(msg.task || 'Screen Recording');
|
|
82
82
|
ctx.socketToSession.set(socket, conversation.id);
|
|
83
83
|
const recordingId = handleRecordingStart(conversation.id, { promptForSource: true }, socket, ctx);
|
|
84
|
+
const responseText = recordingId ? 'Starting screen recording.' : 'A recording is already active.';
|
|
84
85
|
ctx.send(socket, { type: 'task_routed', sessionId: conversation.id, interactionType: 'text_qa' });
|
|
85
86
|
ctx.send(socket, {
|
|
86
87
|
type: 'assistant_text_delta',
|
|
87
|
-
text:
|
|
88
|
+
text: responseText,
|
|
88
89
|
sessionId: conversation.id,
|
|
89
90
|
});
|
|
90
91
|
ctx.send(socket, { type: 'message_complete', sessionId: conversation.id });
|
|
92
|
+
await conversationStore.addMessage(conversation.id, 'user', JSON.stringify([{ type: 'text', text: msg.task || '' }]));
|
|
93
|
+
await conversationStore.addMessage(conversation.id, 'assistant', JSON.stringify([{ type: 'text', text: responseText }]));
|
|
94
|
+
// Sync in-memory session if one exists for this conversation
|
|
95
|
+
const startSession = ctx.sessions.get(conversation.id);
|
|
96
|
+
if (startSession && !startSession.isProcessing()) {
|
|
97
|
+
startSession.messages.push({ role: 'user', content: [{ type: 'text', text: msg.task || '' }] });
|
|
98
|
+
startSession.messages.push({ role: 'assistant', content: [{ type: 'text', text: responseText }] });
|
|
99
|
+
}
|
|
91
100
|
if (!recordingId) ctx.socketToSession.delete(socket);
|
|
92
101
|
return;
|
|
93
102
|
} else if (action === 'stop') {
|
|
@@ -98,13 +107,21 @@ export async function handleTaskSubmit(
|
|
|
98
107
|
ctx.socketToSession.set(socket, activeSessionId);
|
|
99
108
|
}
|
|
100
109
|
const stopped = handleRecordingStop(activeSessionId, ctx) !== undefined;
|
|
110
|
+
const responseText = stopped ? 'Stopping the recording.' : 'No active recording to stop.';
|
|
101
111
|
ctx.send(socket, { type: 'task_routed', sessionId: activeSessionId, interactionType: 'text_qa' });
|
|
102
112
|
ctx.send(socket, {
|
|
103
113
|
type: 'assistant_text_delta',
|
|
104
|
-
text:
|
|
114
|
+
text: responseText,
|
|
105
115
|
sessionId: activeSessionId,
|
|
106
116
|
});
|
|
107
117
|
ctx.send(socket, { type: 'message_complete', sessionId: activeSessionId });
|
|
118
|
+
await conversationStore.addMessage(activeSessionId, 'user', JSON.stringify([{ type: 'text', text: msg.task || '' }]));
|
|
119
|
+
await conversationStore.addMessage(activeSessionId, 'assistant', JSON.stringify([{ type: 'text', text: responseText }]));
|
|
120
|
+
const stopSession = ctx.sessions.get(activeSessionId);
|
|
121
|
+
if (stopSession && !stopSession.isProcessing()) {
|
|
122
|
+
stopSession.messages.push({ role: 'user', content: [{ type: 'text', text: msg.task || '' }] });
|
|
123
|
+
stopSession.messages.push({ role: 'assistant', content: [{ type: 'text', text: responseText }] });
|
|
124
|
+
}
|
|
108
125
|
return;
|
|
109
126
|
} else if (action === 'restart') {
|
|
110
127
|
let activeSessionId = ctx.socketToSession.get(socket);
|
|
@@ -121,6 +138,13 @@ export async function handleTaskSubmit(
|
|
|
121
138
|
sessionId: activeSessionId,
|
|
122
139
|
});
|
|
123
140
|
ctx.send(socket, { type: 'message_complete', sessionId: activeSessionId });
|
|
141
|
+
await conversationStore.addMessage(activeSessionId, 'user', JSON.stringify([{ type: 'text', text: msg.task || '' }]));
|
|
142
|
+
await conversationStore.addMessage(activeSessionId, 'assistant', JSON.stringify([{ type: 'text', text: restartResult.responseText }]));
|
|
143
|
+
const restartSession = ctx.sessions.get(activeSessionId);
|
|
144
|
+
if (restartSession && !restartSession.isProcessing()) {
|
|
145
|
+
restartSession.messages.push({ role: 'user', content: [{ type: 'text', text: msg.task || '' }] });
|
|
146
|
+
restartSession.messages.push({ role: 'assistant', content: [{ type: 'text', text: restartResult.responseText }] });
|
|
147
|
+
}
|
|
124
148
|
return;
|
|
125
149
|
} else if (action === 'pause') {
|
|
126
150
|
let activeSessionId = ctx.socketToSession.get(socket);
|
|
@@ -130,13 +154,21 @@ export async function handleTaskSubmit(
|
|
|
130
154
|
ctx.socketToSession.set(socket, activeSessionId);
|
|
131
155
|
}
|
|
132
156
|
const paused = handleRecordingPause(activeSessionId, ctx) !== undefined;
|
|
157
|
+
const responseText = paused ? 'Pausing the recording.' : 'No active recording to pause.';
|
|
133
158
|
ctx.send(socket, { type: 'task_routed', sessionId: activeSessionId, interactionType: 'text_qa' });
|
|
134
159
|
ctx.send(socket, {
|
|
135
160
|
type: 'assistant_text_delta',
|
|
136
|
-
text:
|
|
161
|
+
text: responseText,
|
|
137
162
|
sessionId: activeSessionId,
|
|
138
163
|
});
|
|
139
164
|
ctx.send(socket, { type: 'message_complete', sessionId: activeSessionId });
|
|
165
|
+
await conversationStore.addMessage(activeSessionId, 'user', JSON.stringify([{ type: 'text', text: msg.task || '' }]));
|
|
166
|
+
await conversationStore.addMessage(activeSessionId, 'assistant', JSON.stringify([{ type: 'text', text: responseText }]));
|
|
167
|
+
const pauseSession = ctx.sessions.get(activeSessionId);
|
|
168
|
+
if (pauseSession && !pauseSession.isProcessing()) {
|
|
169
|
+
pauseSession.messages.push({ role: 'user', content: [{ type: 'text', text: msg.task || '' }] });
|
|
170
|
+
pauseSession.messages.push({ role: 'assistant', content: [{ type: 'text', text: responseText }] });
|
|
171
|
+
}
|
|
140
172
|
return;
|
|
141
173
|
} else if (action === 'resume') {
|
|
142
174
|
let activeSessionId = ctx.socketToSession.get(socket);
|
|
@@ -146,13 +178,21 @@ export async function handleTaskSubmit(
|
|
|
146
178
|
ctx.socketToSession.set(socket, activeSessionId);
|
|
147
179
|
}
|
|
148
180
|
const resumed = handleRecordingResume(activeSessionId, ctx) !== undefined;
|
|
181
|
+
const responseText = resumed ? 'Resuming the recording.' : 'No active recording to resume.';
|
|
149
182
|
ctx.send(socket, { type: 'task_routed', sessionId: activeSessionId, interactionType: 'text_qa' });
|
|
150
183
|
ctx.send(socket, {
|
|
151
184
|
type: 'assistant_text_delta',
|
|
152
|
-
text:
|
|
185
|
+
text: responseText,
|
|
153
186
|
sessionId: activeSessionId,
|
|
154
187
|
});
|
|
155
188
|
ctx.send(socket, { type: 'message_complete', sessionId: activeSessionId });
|
|
189
|
+
await conversationStore.addMessage(activeSessionId, 'user', JSON.stringify([{ type: 'text', text: msg.task || '' }]));
|
|
190
|
+
await conversationStore.addMessage(activeSessionId, 'assistant', JSON.stringify([{ type: 'text', text: responseText }]));
|
|
191
|
+
const resumeSession = ctx.sessions.get(activeSessionId);
|
|
192
|
+
if (resumeSession && !resumeSession.isProcessing()) {
|
|
193
|
+
resumeSession.messages.push({ role: 'user', content: [{ type: 'text', text: msg.task || '' }] });
|
|
194
|
+
resumeSession.messages.push({ role: 'assistant', content: [{ type: 'text', text: responseText }] });
|
|
195
|
+
}
|
|
156
196
|
return;
|
|
157
197
|
} else {
|
|
158
198
|
// Unrecognized action — fall through to normal text handling so the
|
|
@@ -165,6 +205,7 @@ export async function handleTaskSubmit(
|
|
|
165
205
|
let pendingRecordingStart = false;
|
|
166
206
|
let pendingRecordingStop = false;
|
|
167
207
|
let pendingRecordingRestart: 'restart_with_remainder' | 'start_and_stop_with_remainder' | false = false;
|
|
208
|
+
let originalTaskBeforeStrip: string | undefined;
|
|
168
209
|
if (config.daemon.standaloneRecording) {
|
|
169
210
|
const name = getAssistantName();
|
|
170
211
|
const dynamicNames = [name].filter(Boolean) as string[];
|
|
@@ -184,6 +225,13 @@ export async function handleTaskSubmit(
|
|
|
184
225
|
ctx.send(socket, { type: 'task_routed', sessionId: conversation.id, interactionType: 'text_qa' });
|
|
185
226
|
ctx.send(socket, { type: 'assistant_text_delta', text: execResult.responseText!, sessionId: conversation.id });
|
|
186
227
|
ctx.send(socket, { type: 'message_complete', sessionId: conversation.id });
|
|
228
|
+
await conversationStore.addMessage(conversation.id, 'user', JSON.stringify([{ type: 'text', text: msg.task || '' }]));
|
|
229
|
+
await conversationStore.addMessage(conversation.id, 'assistant', JSON.stringify([{ type: 'text', text: execResult.responseText! }]));
|
|
230
|
+
const startOnlySession = ctx.sessions.get(conversation.id);
|
|
231
|
+
if (startOnlySession && !startOnlySession.isProcessing()) {
|
|
232
|
+
startOnlySession.messages.push({ role: 'user', content: [{ type: 'text', text: msg.task || '' }] });
|
|
233
|
+
startOnlySession.messages.push({ role: 'assistant', content: [{ type: 'text', text: execResult.responseText! }] });
|
|
234
|
+
}
|
|
187
235
|
|
|
188
236
|
// If recording rejected, unbind socket
|
|
189
237
|
if (execResult.recordingStarted === false) {
|
|
@@ -212,6 +260,13 @@ export async function handleTaskSubmit(
|
|
|
212
260
|
ctx.send(socket, { type: 'task_routed', sessionId: activeSessionId, interactionType: 'text_qa' });
|
|
213
261
|
ctx.send(socket, { type: 'assistant_text_delta', text: execResult.responseText!, sessionId: activeSessionId });
|
|
214
262
|
ctx.send(socket, { type: 'message_complete', sessionId: activeSessionId });
|
|
263
|
+
await conversationStore.addMessage(activeSessionId, 'user', JSON.stringify([{ type: 'text', text: msg.task || '' }]));
|
|
264
|
+
await conversationStore.addMessage(activeSessionId, 'assistant', JSON.stringify([{ type: 'text', text: execResult.responseText! }]));
|
|
265
|
+
const stopOnlySession = ctx.sessions.get(activeSessionId);
|
|
266
|
+
if (stopOnlySession && !stopOnlySession.isProcessing()) {
|
|
267
|
+
stopOnlySession.messages.push({ role: 'user', content: [{ type: 'text', text: msg.task || '' }] });
|
|
268
|
+
stopOnlySession.messages.push({ role: 'assistant', content: [{ type: 'text', text: execResult.responseText! }] });
|
|
269
|
+
}
|
|
215
270
|
return;
|
|
216
271
|
}
|
|
217
272
|
|
|
@@ -233,6 +288,13 @@ export async function handleTaskSubmit(
|
|
|
233
288
|
ctx.send(socket, { type: 'task_routed', sessionId: activeSessionId, interactionType: 'text_qa' });
|
|
234
289
|
ctx.send(socket, { type: 'assistant_text_delta', text: execResult.responseText!, sessionId: activeSessionId });
|
|
235
290
|
ctx.send(socket, { type: 'message_complete', sessionId: activeSessionId });
|
|
291
|
+
await conversationStore.addMessage(activeSessionId, 'user', JSON.stringify([{ type: 'text', text: msg.task || '' }]));
|
|
292
|
+
await conversationStore.addMessage(activeSessionId, 'assistant', JSON.stringify([{ type: 'text', text: execResult.responseText! }]));
|
|
293
|
+
const startStopOnlySession = ctx.sessions.get(activeSessionId);
|
|
294
|
+
if (startStopOnlySession && !startStopOnlySession.isProcessing()) {
|
|
295
|
+
startStopOnlySession.messages.push({ role: 'user', content: [{ type: 'text', text: msg.task || '' }] });
|
|
296
|
+
startStopOnlySession.messages.push({ role: 'assistant', content: [{ type: 'text', text: execResult.responseText! }] });
|
|
297
|
+
}
|
|
236
298
|
return;
|
|
237
299
|
}
|
|
238
300
|
|
|
@@ -255,6 +317,13 @@ export async function handleTaskSubmit(
|
|
|
255
317
|
ctx.send(socket, { type: 'task_routed', sessionId: activeSessionId, interactionType: 'text_qa' });
|
|
256
318
|
ctx.send(socket, { type: 'assistant_text_delta', text: execResult.responseText!, sessionId: activeSessionId });
|
|
257
319
|
ctx.send(socket, { type: 'message_complete', sessionId: activeSessionId });
|
|
320
|
+
await conversationStore.addMessage(activeSessionId, 'user', JSON.stringify([{ type: 'text', text: msg.task || '' }]));
|
|
321
|
+
await conversationStore.addMessage(activeSessionId, 'assistant', JSON.stringify([{ type: 'text', text: execResult.responseText! }]));
|
|
322
|
+
const handledSession = ctx.sessions.get(activeSessionId);
|
|
323
|
+
if (handledSession && !handledSession.isProcessing()) {
|
|
324
|
+
handledSession.messages.push({ role: 'user', content: [{ type: 'text', text: msg.task || '' }] });
|
|
325
|
+
handledSession.messages.push({ role: 'assistant', content: [{ type: 'text', text: execResult.responseText! }] });
|
|
326
|
+
}
|
|
258
327
|
return;
|
|
259
328
|
}
|
|
260
329
|
|
|
@@ -276,6 +345,8 @@ export async function handleTaskSubmit(
|
|
|
276
345
|
pendingRecordingStart = intentResult.kind === 'start_with_remainder';
|
|
277
346
|
pendingRecordingRestart = intentResult.kind === 'restart_with_remainder' ? 'restart_with_remainder' : false;
|
|
278
347
|
}
|
|
348
|
+
// Preserve the original text so the DB stores the full message
|
|
349
|
+
originalTaskBeforeStrip = msg.task;
|
|
279
350
|
(msg as { task: string }).task = intentResult.remainder;
|
|
280
351
|
rlog.info({ remaining: intentResult.remainder }, 'Recording intent deferred, continuing with remaining text');
|
|
281
352
|
}
|
|
@@ -318,6 +389,13 @@ export async function handleTaskSubmit(
|
|
|
318
389
|
sessionId: activeSessionId,
|
|
319
390
|
});
|
|
320
391
|
ctx.send(socket, { type: 'message_complete', sessionId: activeSessionId });
|
|
392
|
+
await conversationStore.addMessage(activeSessionId, 'user', JSON.stringify([{ type: 'text', text: msg.task || '' }]));
|
|
393
|
+
await conversationStore.addMessage(activeSessionId, 'assistant', JSON.stringify([{ type: 'text', text: execResult.responseText! }]));
|
|
394
|
+
const fallbackSession = ctx.sessions.get(activeSessionId);
|
|
395
|
+
if (fallbackSession && !fallbackSession.isProcessing()) {
|
|
396
|
+
fallbackSession.messages.push({ role: 'user', content: [{ type: 'text', text: msg.task || '' }] });
|
|
397
|
+
fallbackSession.messages.push({ role: 'assistant', content: [{ type: 'text', text: execResult.responseText! }] });
|
|
398
|
+
}
|
|
321
399
|
|
|
322
400
|
// If recording was rejected (e.g. already active), unbind the
|
|
323
401
|
// socket so it doesn't stay bound to an orphaned conversation.
|
|
@@ -409,7 +487,7 @@ export async function handleTaskSubmit(
|
|
|
409
487
|
// Start streaming immediately — client doesn't need to send user_message
|
|
410
488
|
session.processMessage(msg.task, msg.attachments ?? [], (event) => {
|
|
411
489
|
ctx.send(socket, event);
|
|
412
|
-
}, requestId).catch((err) => {
|
|
490
|
+
}, requestId, undefined, undefined, undefined, originalTaskBeforeStrip).catch((err) => {
|
|
413
491
|
const message = err instanceof Error ? err.message : String(err);
|
|
414
492
|
rlog.error({ err }, 'Error processing task_submit text QA');
|
|
415
493
|
ctx.send(socket, { type: 'error', message: `Failed to process message: ${message}` });
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { HandlerContext } from './shared.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Valid settings tab identifiers matching the macOS client's SettingsTab enum.
|
|
5
|
+
* These correspond to the raw values the Swift client expects.
|
|
6
|
+
*/
|
|
7
|
+
export const SETTINGS_TABS = [
|
|
8
|
+
'Connect',
|
|
9
|
+
'Integrations',
|
|
10
|
+
'Trust',
|
|
11
|
+
'Schedules',
|
|
12
|
+
'Heartbeat',
|
|
13
|
+
'Wake Word',
|
|
14
|
+
'Appearance',
|
|
15
|
+
'Advanced',
|
|
16
|
+
'Parental',
|
|
17
|
+
] as const;
|
|
18
|
+
|
|
19
|
+
export type SettingsTabId = (typeof SETTINGS_TABS)[number];
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Broadcast a `navigate_settings` message to all connected clients,
|
|
23
|
+
* opening the settings panel to the specified tab.
|
|
24
|
+
*/
|
|
25
|
+
export function navigateToSettingsTab(ctx: HandlerContext, tab: SettingsTabId): void {
|
|
26
|
+
ctx.broadcast({ type: 'navigate_settings', tab });
|
|
27
|
+
}
|