@vellumai/assistant 0.3.2 → 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 +82 -21
- package/package.json +1 -1
- package/src/__tests__/__snapshots__/ipc-snapshot.test.ts.snap +16 -0
- package/src/__tests__/app-git-history.test.ts +22 -27
- package/src/__tests__/app-git-service.test.ts +44 -78
- package/src/__tests__/call-orchestrator.test.ts +321 -0
- package/src/__tests__/channel-approval-routes.test.ts +1267 -93
- package/src/__tests__/channel-approval.test.ts +2 -0
- package/src/__tests__/channel-approvals.test.ts +51 -2
- package/src/__tests__/channel-delivery-store.test.ts +130 -1
- package/src/__tests__/channel-guardian.test.ts +371 -1
- package/src/__tests__/config-schema.test.ts +1 -1
- package/src/__tests__/credential-security-invariants.test.ts +1 -0
- package/src/__tests__/daemon-lifecycle.test.ts +635 -0
- package/src/__tests__/daemon-server-session-init.test.ts +5 -0
- package/src/__tests__/gateway-only-enforcement.test.ts +106 -21
- package/src/__tests__/handlers-telegram-config.test.ts +82 -0
- package/src/__tests__/handlers-twilio-config.test.ts +738 -5
- package/src/__tests__/ingress-url-consistency.test.ts +64 -0
- package/src/__tests__/ipc-snapshot.test.ts +10 -0
- package/src/__tests__/run-orchestrator.test.ts +1 -1
- package/src/__tests__/secret-scanner.test.ts +223 -0
- package/src/__tests__/session-process-bridge.test.ts +2 -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__/tool-permission-simulate-handler.test.ts +2 -2
- package/src/__tests__/user-reference.test.ts +68 -0
- package/src/calls/call-orchestrator.ts +63 -11
- package/src/calls/twilio-config.ts +10 -1
- package/src/calls/twilio-rest.ts +70 -0
- 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/email-setup/SKILL.md +56 -0
- package/src/config/bundled-skills/messaging/SKILL.md +4 -0
- package/src/config/bundled-skills/subagent/SKILL.md +4 -0
- package/src/config/bundled-skills/subagent/TOOLS.json +4 -0
- package/src/config/defaults.ts +1 -1
- package/src/config/schema.ts +6 -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 +49 -4
- 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 +193 -17
- package/src/daemon/handlers/sessions.ts +5 -3
- package/src/daemon/handlers/skills.ts +60 -17
- package/src/daemon/ipc-contract-inventory.json +4 -0
- package/src/daemon/ipc-contract.ts +16 -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 +9 -14
- package/src/daemon/session-process.ts +20 -3
- package/src/daemon/session-runtime-assembly.ts +60 -44
- package/src/daemon/session-slash.ts +50 -2
- package/src/daemon/session-surfaces.ts +17 -1
- package/src/daemon/session.ts +8 -1
- package/src/inbound/public-ingress-urls.ts +20 -3
- package/src/index.ts +1 -23
- package/src/memory/app-git-service.ts +24 -0
- package/src/memory/app-store.ts +0 -21
- package/src/memory/channel-delivery-store.ts +74 -3
- package/src/memory/channel-guardian-store.ts +54 -26
- package/src/memory/conversation-key-store.ts +20 -0
- package/src/memory/conversation-store.ts +14 -2
- package/src/memory/db-connection.ts +28 -0
- package/src/memory/db-init.ts +1019 -0
- package/src/memory/db.ts +2 -1995
- 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 +6 -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 +28 -9
- package/src/runtime/routes/channel-routes.ts +279 -100
- 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/clawhub.ts +6 -2
- 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/subagent/manager.ts +4 -1
- package/src/subagent/types.ts +2 -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 +75 -127
- package/src/tools/subagent/spawn.ts +2 -0
- package/src/tools/terminal/parser.ts +21 -5
- package/src/util/platform.ts +8 -1
- package/src/util/retry.ts +4 -4
package/src/memory/schema.ts
CHANGED
|
@@ -129,6 +129,7 @@ export const memoryEmbeddings = sqliteTable('memory_embeddings', {
|
|
|
129
129
|
model: text('model').notNull(),
|
|
130
130
|
dimensions: integer('dimensions').notNull(),
|
|
131
131
|
vectorJson: text('vector_json').notNull(),
|
|
132
|
+
contentHash: text('content_hash'),
|
|
132
133
|
createdAt: integer('created_at').notNull(),
|
|
133
134
|
updatedAt: integer('updated_at').notNull(),
|
|
134
135
|
});
|
|
@@ -646,6 +647,7 @@ export const channelGuardianApprovalRequests = sqliteTable('channel_guardian_app
|
|
|
646
647
|
id: text('id').primaryKey(),
|
|
647
648
|
runId: text('run_id').notNull(),
|
|
648
649
|
conversationId: text('conversation_id').notNull(),
|
|
650
|
+
assistantId: text('assistant_id').notNull().default('self'),
|
|
649
651
|
channel: text('channel').notNull(),
|
|
650
652
|
requesterExternalUserId: text('requester_external_user_id').notNull(),
|
|
651
653
|
requesterChatId: text('requester_chat_id').notNull(),
|
|
@@ -669,6 +671,10 @@ export const channelGuardianRateLimits = sqliteTable('channel_guardian_rate_limi
|
|
|
669
671
|
channel: text('channel').notNull(),
|
|
670
672
|
actorExternalUserId: text('actor_external_user_id').notNull(),
|
|
671
673
|
actorChatId: text('actor_chat_id').notNull(),
|
|
674
|
+
// Legacy columns kept with defaults for backward compatibility with upgraded databases
|
|
675
|
+
// that still have the old NOT NULL columns without DEFAULT. Not read by app logic.
|
|
676
|
+
invalidAttempts: integer('invalid_attempts').notNull().default(0),
|
|
677
|
+
windowStartedAt: integer('window_started_at').notNull().default(0),
|
|
672
678
|
attemptTimestampsJson: text('attempt_timestamps_json').notNull().default('[]'),
|
|
673
679
|
lockedUntil: integer('locked_until'),
|
|
674
680
|
createdAt: integer('created_at').notNull(),
|
|
@@ -94,6 +94,8 @@ export interface CollectedCandidates {
|
|
|
94
94
|
relationNeighborEntityCount: number;
|
|
95
95
|
relationExpandedItemCount: number;
|
|
96
96
|
earlyTerminated: boolean;
|
|
97
|
+
/** True when semantic search was attempted but threw an error. */
|
|
98
|
+
semanticSearchFailed: boolean;
|
|
97
99
|
merged: Candidate[];
|
|
98
100
|
}
|
|
99
101
|
|
|
@@ -10,7 +10,12 @@ import { redactSensitiveFields } from '../security/redaction.js';
|
|
|
10
10
|
const log = getLogger('permission-prompter');
|
|
11
11
|
|
|
12
12
|
interface PendingPrompt {
|
|
13
|
-
resolve: (value: {
|
|
13
|
+
resolve: (value: {
|
|
14
|
+
decision: UserDecision;
|
|
15
|
+
selectedPattern?: string;
|
|
16
|
+
selectedScope?: string;
|
|
17
|
+
decisionContext?: string;
|
|
18
|
+
}) => void;
|
|
14
19
|
reject: (reason: Error) => void;
|
|
15
20
|
timer: ReturnType<typeof setTimeout>;
|
|
16
21
|
}
|
|
@@ -38,7 +43,12 @@ export class PermissionPrompter {
|
|
|
38
43
|
sessionId?: string,
|
|
39
44
|
executionTarget?: ExecutionTarget,
|
|
40
45
|
persistentDecisionsAllowed?: boolean,
|
|
41
|
-
): Promise<{
|
|
46
|
+
): Promise<{
|
|
47
|
+
decision: UserDecision;
|
|
48
|
+
selectedPattern?: string;
|
|
49
|
+
selectedScope?: string;
|
|
50
|
+
decisionContext?: string;
|
|
51
|
+
}> {
|
|
42
52
|
const requestId = uuid();
|
|
43
53
|
|
|
44
54
|
return new Promise((resolve, reject) => {
|
|
@@ -77,6 +87,7 @@ export class PermissionPrompter {
|
|
|
77
87
|
decision: UserDecision,
|
|
78
88
|
selectedPattern?: string,
|
|
79
89
|
selectedScope?: string,
|
|
90
|
+
decisionContext?: string,
|
|
80
91
|
): void {
|
|
81
92
|
const pending = this.pending.get(requestId);
|
|
82
93
|
if (!pending) {
|
|
@@ -85,7 +96,7 @@ export class PermissionPrompter {
|
|
|
85
96
|
}
|
|
86
97
|
clearTimeout(pending.timer);
|
|
87
98
|
this.pending.delete(requestId);
|
|
88
|
-
pending.resolve({ decision, selectedPattern, selectedScope });
|
|
99
|
+
pending.resolve({ decision, selectedPattern, selectedScope, decisionContext });
|
|
89
100
|
}
|
|
90
101
|
|
|
91
102
|
dispose(): void {
|
|
@@ -27,13 +27,17 @@ let cachedStarterBundleAccepted: boolean | null = null;
|
|
|
27
27
|
* on every tool-call permission check.
|
|
28
28
|
*/
|
|
29
29
|
const compiledPatterns = new Map<string, Minimatch>();
|
|
30
|
+
/** Patterns that failed compilation — cached to avoid repeated attempts and log spam. */
|
|
31
|
+
const invalidPatterns = new Set<string>();
|
|
30
32
|
|
|
31
33
|
/** Get or compile a Minimatch object for the given pattern. Returns null if the pattern is invalid. */
|
|
32
34
|
function getCompiledPattern(pattern: string): Minimatch | null {
|
|
35
|
+
if (invalidPatterns.has(pattern)) return null;
|
|
33
36
|
let compiled = compiledPatterns.get(pattern);
|
|
34
37
|
if (!compiled) {
|
|
35
38
|
if (typeof pattern !== 'string') {
|
|
36
39
|
log.warn({ pattern }, 'Cannot compile non-string pattern');
|
|
40
|
+
invalidPatterns.add(pattern as string);
|
|
37
41
|
return null;
|
|
38
42
|
}
|
|
39
43
|
try {
|
|
@@ -41,6 +45,7 @@ function getCompiledPattern(pattern: string): Minimatch | null {
|
|
|
41
45
|
compiledPatterns.set(pattern, compiled);
|
|
42
46
|
} catch (err) {
|
|
43
47
|
log.warn({ pattern, err }, 'Failed to compile pattern');
|
|
48
|
+
invalidPatterns.add(pattern);
|
|
44
49
|
return null;
|
|
45
50
|
}
|
|
46
51
|
}
|
|
@@ -50,6 +55,7 @@ function getCompiledPattern(pattern: string): Minimatch | null {
|
|
|
50
55
|
/** Rebuild the compiled pattern cache from the current rule set. */
|
|
51
56
|
function rebuildPatternCache(rules: TrustRule[]): void {
|
|
52
57
|
compiledPatterns.clear();
|
|
58
|
+
invalidPatterns.clear();
|
|
53
59
|
for (const rule of rules) {
|
|
54
60
|
if (typeof rule.pattern !== 'string') {
|
|
55
61
|
log.warn({ ruleId: rule.id, pattern: rule.pattern }, 'Skipping rule with non-string pattern during cache rebuild');
|
|
@@ -509,6 +515,7 @@ export function clearCache(): void {
|
|
|
509
515
|
cachedRules = null;
|
|
510
516
|
cachedStarterBundleAccepted = null;
|
|
511
517
|
compiledPatterns.clear();
|
|
518
|
+
invalidPatterns.clear();
|
|
512
519
|
}
|
|
513
520
|
|
|
514
521
|
// ─── Starter approval bundle ────────────────────────────────────────────────
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
import { getPendingConfirmationsByConversation, getRun } from '../memory/runs-store.js';
|
|
14
14
|
import type { PendingRunInfo } from '../memory/runs-store.js';
|
|
15
15
|
import { addRule } from '../permissions/trust-store.js';
|
|
16
|
+
import { getTool } from '../tools/registry.js';
|
|
16
17
|
import type { RunOrchestrator } from './run-orchestrator.js';
|
|
17
18
|
import { DEFAULT_APPROVAL_ACTIONS } from './channel-approval-types.js';
|
|
18
19
|
import type {
|
|
@@ -101,11 +102,17 @@ export function handleChannelDecision(
|
|
|
101
102
|
conversationId: string,
|
|
102
103
|
decision: ApprovalDecisionResult,
|
|
103
104
|
orchestrator: RunOrchestrator,
|
|
105
|
+
decisionContext?: string,
|
|
104
106
|
): HandleDecisionResult {
|
|
105
107
|
const pending = getPendingConfirmationsByConversation(conversationId);
|
|
106
108
|
if (pending.length === 0) return { applied: false };
|
|
107
109
|
|
|
108
|
-
|
|
110
|
+
// Callback-based decisions include a run ID and must resolve to that exact
|
|
111
|
+
// pending confirmation. Plain-text decisions still apply to the first prompt.
|
|
112
|
+
const info = decision.runId
|
|
113
|
+
? pending.find((candidate) => candidate.runId === decision.runId)
|
|
114
|
+
: pending[0];
|
|
115
|
+
if (!info) return { applied: false };
|
|
109
116
|
|
|
110
117
|
if (decision.action === 'approve_always') {
|
|
111
118
|
// Only persist a trust rule when the confirmation explicitly allows persistence
|
|
@@ -121,8 +128,13 @@ export function handleChannelDecision(
|
|
|
121
128
|
) {
|
|
122
129
|
const pattern = confirmation.allowlistOptions[0].pattern;
|
|
123
130
|
const scope = confirmation.scopeOptions[0].scope;
|
|
131
|
+
// Only persist executionTarget for skill-origin tools — core tools don't
|
|
132
|
+
// set it in their PolicyContext, so a persisted value would prevent the
|
|
133
|
+
// rule from ever matching on subsequent permission checks.
|
|
134
|
+
const tool = getTool(confirmation.toolName);
|
|
135
|
+
const executionTarget = tool?.origin === 'skill' ? confirmation.executionTarget : undefined;
|
|
124
136
|
addRule(confirmation.toolName, pattern, scope, 'allow', 100, {
|
|
125
|
-
executionTarget
|
|
137
|
+
executionTarget,
|
|
126
138
|
});
|
|
127
139
|
}
|
|
128
140
|
// When persistence is not allowed or options are missing, the decision
|
|
@@ -131,7 +143,9 @@ export function handleChannelDecision(
|
|
|
131
143
|
|
|
132
144
|
// Map channel-level action to the permission system's UserDecision type.
|
|
133
145
|
const userDecision = decision.action === 'reject' ? 'deny' as const : 'allow' as const;
|
|
134
|
-
const result =
|
|
146
|
+
const result = decisionContext === undefined
|
|
147
|
+
? orchestrator.submitDecision(info.runId, userDecision)
|
|
148
|
+
: orchestrator.submitDecision(info.runId, userDecision, decisionContext);
|
|
135
149
|
|
|
136
150
|
return {
|
|
137
151
|
applied: result === 'applied',
|
|
@@ -52,7 +52,8 @@ export async function deliverApprovalPrompt(
|
|
|
52
52
|
chatId: string,
|
|
53
53
|
text: string,
|
|
54
54
|
approval: ApprovalUIMetadata,
|
|
55
|
+
assistantId?: string,
|
|
55
56
|
bearerToken?: string,
|
|
56
57
|
): Promise<void> {
|
|
57
|
-
await deliverChannelReply(callbackUrl, { chatId, text, approval }, bearerToken);
|
|
58
|
+
await deliverChannelReply(callbackUrl, { chatId, text, approval, assistantId }, bearerToken);
|
|
58
59
|
}
|
|
@@ -41,7 +41,6 @@ import {
|
|
|
41
41
|
handleChannelDeliveryAck,
|
|
42
42
|
handleListDeadLetters,
|
|
43
43
|
handleReplayDeadLetters,
|
|
44
|
-
isChannelApprovalsEnabled,
|
|
45
44
|
startGuardianExpirySweep,
|
|
46
45
|
stopGuardianExpirySweep,
|
|
47
46
|
} from './routes/channel-routes.js';
|
|
@@ -154,13 +153,16 @@ const GATEWAY_SUBPATH_MAP: Record<string, string> = {
|
|
|
154
153
|
voice: 'voice-webhook',
|
|
155
154
|
status: 'status',
|
|
156
155
|
'connect-action': 'connect-action',
|
|
156
|
+
sms: 'sms',
|
|
157
157
|
};
|
|
158
158
|
|
|
159
159
|
/**
|
|
160
160
|
* Direct Twilio webhook subpaths that are blocked in gateway_only mode.
|
|
161
|
+
* Includes all public-facing webhook paths (voice, status, connect-action, SMS)
|
|
162
|
+
* because the runtime must never serve as a direct ingress for external webhooks.
|
|
161
163
|
* Internal forwarding endpoints (gateway→runtime) are unaffected.
|
|
162
164
|
*/
|
|
163
|
-
const GATEWAY_ONLY_BLOCKED_SUBPATHS = new Set(['voice-webhook', 'status', 'connect-action']);
|
|
165
|
+
const GATEWAY_ONLY_BLOCKED_SUBPATHS = new Set(['voice-webhook', 'status', 'connect-action', 'sms']);
|
|
164
166
|
|
|
165
167
|
/**
|
|
166
168
|
* Check if a request origin is from a private/internal network address.
|
|
@@ -411,8 +413,10 @@ export class RuntimeHttpServer {
|
|
|
411
413
|
}, 30_000);
|
|
412
414
|
}
|
|
413
415
|
|
|
414
|
-
// Start proactive guardian approval expiry sweep
|
|
415
|
-
|
|
416
|
+
// Start proactive guardian approval expiry sweep whenever orchestrator
|
|
417
|
+
// support is available. Guardian approvals can be created even when the
|
|
418
|
+
// generic channel-approval UX flag is disabled.
|
|
419
|
+
if (this.runOrchestrator) {
|
|
416
420
|
startGuardianExpirySweep(this.runOrchestrator, getGatewayBaseUrl(), this.bearerToken);
|
|
417
421
|
log.info('Guardian approval expiry sweep started');
|
|
418
422
|
}
|
|
@@ -616,7 +620,7 @@ export class RuntimeHttpServer {
|
|
|
616
620
|
const assistantId = match[1];
|
|
617
621
|
const endpoint = match[2];
|
|
618
622
|
log.warn({ endpoint, assistantId }, '[deprecated] /v1/assistants/:assistantId/... route used; migrate to /v1/...');
|
|
619
|
-
return this.dispatchEndpoint(endpoint, req, url);
|
|
623
|
+
return this.dispatchEndpoint(endpoint, req, url, assistantId);
|
|
620
624
|
}
|
|
621
625
|
|
|
622
626
|
/**
|
|
@@ -628,6 +632,7 @@ export class RuntimeHttpServer {
|
|
|
628
632
|
endpoint: string,
|
|
629
633
|
req: Request,
|
|
630
634
|
url: URL,
|
|
635
|
+
assistantId: string = 'self',
|
|
631
636
|
): Promise<Response> {
|
|
632
637
|
try {
|
|
633
638
|
if (endpoint === 'health' && req.method === 'GET') {
|
|
@@ -636,7 +641,9 @@ export class RuntimeHttpServer {
|
|
|
636
641
|
|
|
637
642
|
if (endpoint === 'conversations' && req.method === 'GET') {
|
|
638
643
|
const limit = Number(url.searchParams.get('limit') ?? 50);
|
|
639
|
-
const
|
|
644
|
+
const offset = Number(url.searchParams.get('offset') ?? 0);
|
|
645
|
+
const conversations = conversationStore.listConversations(limit, false, offset);
|
|
646
|
+
const totalCount = conversationStore.countConversations();
|
|
640
647
|
const bindings = externalConversationStore.getBindingsForConversations(
|
|
641
648
|
conversations.map((c) => c.id),
|
|
642
649
|
);
|
|
@@ -659,6 +666,7 @@ export class RuntimeHttpServer {
|
|
|
659
666
|
} : {}),
|
|
660
667
|
};
|
|
661
668
|
}),
|
|
669
|
+
hasMore: offset + conversations.length < totalCount,
|
|
662
670
|
});
|
|
663
671
|
}
|
|
664
672
|
|
|
@@ -732,11 +740,12 @@ export class RuntimeHttpServer {
|
|
|
732
740
|
}
|
|
733
741
|
|
|
734
742
|
if (endpoint === 'channels/conversation' && req.method === 'DELETE') {
|
|
735
|
-
return await handleDeleteConversation(req);
|
|
743
|
+
return await handleDeleteConversation(req, assistantId);
|
|
736
744
|
}
|
|
737
745
|
|
|
738
746
|
if (endpoint === 'channels/inbound' && req.method === 'POST') {
|
|
739
|
-
|
|
747
|
+
const gatewayOriginSecret = process.env.RUNTIME_GATEWAY_ORIGIN_SECRET || undefined;
|
|
748
|
+
return await handleChannelInbound(req, this.processMessage, this.bearerToken, this.runOrchestrator, assistantId, gatewayOriginSecret);
|
|
740
749
|
}
|
|
741
750
|
|
|
742
751
|
if (endpoint === 'channels/delivery-ack' && req.method === 'POST') {
|
|
@@ -931,8 +940,16 @@ export class RuntimeHttpServer {
|
|
|
931
940
|
const externalChatId = typeof payload.externalChatId === 'string'
|
|
932
941
|
? payload.externalChatId
|
|
933
942
|
: undefined;
|
|
943
|
+
const assistantId = typeof payload.assistantId === 'string'
|
|
944
|
+
? payload.assistantId
|
|
945
|
+
: undefined;
|
|
934
946
|
if (externalChatId) {
|
|
935
|
-
await this.deliverReplyViaCallback(
|
|
947
|
+
await this.deliverReplyViaCallback(
|
|
948
|
+
event.conversationId,
|
|
949
|
+
externalChatId,
|
|
950
|
+
replyCallbackUrl,
|
|
951
|
+
assistantId,
|
|
952
|
+
);
|
|
936
953
|
}
|
|
937
954
|
}
|
|
938
955
|
} catch (err) {
|
|
@@ -946,6 +963,7 @@ export class RuntimeHttpServer {
|
|
|
946
963
|
conversationId: string,
|
|
947
964
|
externalChatId: string,
|
|
948
965
|
callbackUrl: string,
|
|
966
|
+
assistantId?: string,
|
|
949
967
|
): Promise<void> {
|
|
950
968
|
const msgs = conversationStore.getMessages(conversationId);
|
|
951
969
|
for (let i = msgs.length - 1; i >= 0; i--) {
|
|
@@ -968,6 +986,7 @@ export class RuntimeHttpServer {
|
|
|
968
986
|
chatId: externalChatId,
|
|
969
987
|
text: rendered.text || undefined,
|
|
970
988
|
attachments: replyAttachments.length > 0 ? replyAttachments : undefined,
|
|
989
|
+
assistantId,
|
|
971
990
|
}, this.bearerToken);
|
|
972
991
|
}
|
|
973
992
|
break;
|