@vellumai/cli 0.3.8 → 0.3.10
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/package.json +1 -1
- package/src/components/DefaultMainScreen.tsx +86 -164
package/package.json
CHANGED
|
@@ -61,24 +61,6 @@ interface PendingConfirmation {
|
|
|
61
61
|
persistentDecisionsAllowed?: boolean;
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
interface CreateRunResponse {
|
|
65
|
-
id: string;
|
|
66
|
-
status: string;
|
|
67
|
-
messageId: string | null;
|
|
68
|
-
createdAt: string;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
interface GetRunResponse {
|
|
72
|
-
id: string;
|
|
73
|
-
status: string;
|
|
74
|
-
messageId: string | null;
|
|
75
|
-
pendingConfirmation: PendingConfirmation | null;
|
|
76
|
-
pendingSecret: PendingSecret | null;
|
|
77
|
-
error: string | null;
|
|
78
|
-
createdAt: string;
|
|
79
|
-
updatedAt: string;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
64
|
interface SubmitDecisionResponse {
|
|
83
65
|
accepted: boolean;
|
|
84
66
|
}
|
|
@@ -87,6 +69,11 @@ interface AddTrustRuleResponse {
|
|
|
87
69
|
accepted: boolean;
|
|
88
70
|
}
|
|
89
71
|
|
|
72
|
+
interface PendingInteractionsResponse {
|
|
73
|
+
pendingConfirmation: (PendingConfirmation & { requestId: string }) | null;
|
|
74
|
+
pendingSecret: (PendingSecret & { requestId?: string }) | null;
|
|
75
|
+
}
|
|
76
|
+
|
|
90
77
|
type TrustDecision = "always_allow" | "always_allow_high_risk" | "always_deny";
|
|
91
78
|
|
|
92
79
|
interface HealthResponse {
|
|
@@ -177,55 +164,20 @@ async function sendMessage(
|
|
|
177
164
|
);
|
|
178
165
|
}
|
|
179
166
|
|
|
180
|
-
async function createRun(
|
|
181
|
-
baseUrl: string,
|
|
182
|
-
assistantId: string,
|
|
183
|
-
content: string,
|
|
184
|
-
signal?: AbortSignal,
|
|
185
|
-
bearerToken?: string,
|
|
186
|
-
): Promise<CreateRunResponse> {
|
|
187
|
-
return runtimeRequest<CreateRunResponse>(
|
|
188
|
-
baseUrl,
|
|
189
|
-
assistantId,
|
|
190
|
-
"/runs",
|
|
191
|
-
{
|
|
192
|
-
method: "POST",
|
|
193
|
-
body: JSON.stringify({ conversationKey: assistantId, content }),
|
|
194
|
-
signal,
|
|
195
|
-
},
|
|
196
|
-
bearerToken,
|
|
197
|
-
);
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
async function getRun(
|
|
201
|
-
baseUrl: string,
|
|
202
|
-
assistantId: string,
|
|
203
|
-
runId: string,
|
|
204
|
-
bearerToken?: string,
|
|
205
|
-
): Promise<GetRunResponse> {
|
|
206
|
-
return runtimeRequest<GetRunResponse>(
|
|
207
|
-
baseUrl,
|
|
208
|
-
assistantId,
|
|
209
|
-
`/runs/${runId}`,
|
|
210
|
-
undefined,
|
|
211
|
-
bearerToken,
|
|
212
|
-
);
|
|
213
|
-
}
|
|
214
|
-
|
|
215
167
|
async function submitDecision(
|
|
216
168
|
baseUrl: string,
|
|
217
169
|
assistantId: string,
|
|
218
|
-
|
|
170
|
+
requestId: string,
|
|
219
171
|
decision: "allow" | "deny",
|
|
220
172
|
bearerToken?: string,
|
|
221
173
|
): Promise<SubmitDecisionResponse> {
|
|
222
174
|
return runtimeRequest<SubmitDecisionResponse>(
|
|
223
175
|
baseUrl,
|
|
224
176
|
assistantId,
|
|
225
|
-
|
|
177
|
+
"/confirm",
|
|
226
178
|
{
|
|
227
179
|
method: "POST",
|
|
228
|
-
body: JSON.stringify({ decision }),
|
|
180
|
+
body: JSON.stringify({ requestId, decision }),
|
|
229
181
|
},
|
|
230
182
|
bearerToken,
|
|
231
183
|
);
|
|
@@ -234,7 +186,7 @@ async function submitDecision(
|
|
|
234
186
|
async function addTrustRule(
|
|
235
187
|
baseUrl: string,
|
|
236
188
|
assistantId: string,
|
|
237
|
-
|
|
189
|
+
requestId: string,
|
|
238
190
|
pattern: string,
|
|
239
191
|
scope: string,
|
|
240
192
|
decision: "allow" | "deny",
|
|
@@ -243,15 +195,30 @@ async function addTrustRule(
|
|
|
243
195
|
return runtimeRequest<AddTrustRuleResponse>(
|
|
244
196
|
baseUrl,
|
|
245
197
|
assistantId,
|
|
246
|
-
|
|
198
|
+
"/trust-rules",
|
|
247
199
|
{
|
|
248
200
|
method: "POST",
|
|
249
|
-
body: JSON.stringify({ pattern, scope, decision }),
|
|
201
|
+
body: JSON.stringify({ requestId, pattern, scope, decision }),
|
|
250
202
|
},
|
|
251
203
|
bearerToken,
|
|
252
204
|
);
|
|
253
205
|
}
|
|
254
206
|
|
|
207
|
+
async function pollPendingInteractions(
|
|
208
|
+
baseUrl: string,
|
|
209
|
+
assistantId: string,
|
|
210
|
+
bearerToken?: string,
|
|
211
|
+
): Promise<PendingInteractionsResponse> {
|
|
212
|
+
const params = new URLSearchParams({ conversationKey: assistantId });
|
|
213
|
+
return runtimeRequest<PendingInteractionsResponse>(
|
|
214
|
+
baseUrl,
|
|
215
|
+
assistantId,
|
|
216
|
+
`/pending-interactions?${params.toString()}`,
|
|
217
|
+
undefined,
|
|
218
|
+
bearerToken,
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
|
|
255
222
|
function formatConfirmationPreview(toolName: string, input: Record<string, unknown>): string {
|
|
256
223
|
switch (toolName) {
|
|
257
224
|
case "bash":
|
|
@@ -282,7 +249,7 @@ function formatConfirmationPreview(toolName: string, input: Record<string, unkno
|
|
|
282
249
|
async function handleConfirmationPrompt(
|
|
283
250
|
baseUrl: string,
|
|
284
251
|
assistantId: string,
|
|
285
|
-
|
|
252
|
+
requestId: string,
|
|
286
253
|
confirmation: PendingConfirmation,
|
|
287
254
|
chatApp: ChatAppHandle,
|
|
288
255
|
bearerToken?: string,
|
|
@@ -305,7 +272,7 @@ async function handleConfirmationPrompt(
|
|
|
305
272
|
const index = await chatApp.showSelection("Tool Approval", options);
|
|
306
273
|
|
|
307
274
|
if (index === 0) {
|
|
308
|
-
await submitDecision(baseUrl, assistantId,
|
|
275
|
+
await submitDecision(baseUrl, assistantId, requestId, "allow", bearerToken);
|
|
309
276
|
chatApp.addStatus("\u2714 Allowed", "green");
|
|
310
277
|
return;
|
|
311
278
|
}
|
|
@@ -313,7 +280,7 @@ async function handleConfirmationPrompt(
|
|
|
313
280
|
await handlePatternSelection(
|
|
314
281
|
baseUrl,
|
|
315
282
|
assistantId,
|
|
316
|
-
|
|
283
|
+
requestId,
|
|
317
284
|
confirmation,
|
|
318
285
|
chatApp,
|
|
319
286
|
"always_allow",
|
|
@@ -325,7 +292,7 @@ async function handleConfirmationPrompt(
|
|
|
325
292
|
await handlePatternSelection(
|
|
326
293
|
baseUrl,
|
|
327
294
|
assistantId,
|
|
328
|
-
|
|
295
|
+
requestId,
|
|
329
296
|
confirmation,
|
|
330
297
|
chatApp,
|
|
331
298
|
"always_deny",
|
|
@@ -334,14 +301,14 @@ async function handleConfirmationPrompt(
|
|
|
334
301
|
return;
|
|
335
302
|
}
|
|
336
303
|
|
|
337
|
-
await submitDecision(baseUrl, assistantId,
|
|
304
|
+
await submitDecision(baseUrl, assistantId, requestId, "deny", bearerToken);
|
|
338
305
|
chatApp.addStatus("\u2718 Denied", "yellow");
|
|
339
306
|
}
|
|
340
307
|
|
|
341
308
|
async function handlePatternSelection(
|
|
342
309
|
baseUrl: string,
|
|
343
310
|
assistantId: string,
|
|
344
|
-
|
|
311
|
+
requestId: string,
|
|
345
312
|
confirmation: PendingConfirmation,
|
|
346
313
|
chatApp: ChatAppHandle,
|
|
347
314
|
trustDecision: TrustDecision,
|
|
@@ -358,7 +325,7 @@ async function handlePatternSelection(
|
|
|
358
325
|
await handleScopeSelection(
|
|
359
326
|
baseUrl,
|
|
360
327
|
assistantId,
|
|
361
|
-
|
|
328
|
+
requestId,
|
|
362
329
|
confirmation,
|
|
363
330
|
chatApp,
|
|
364
331
|
selectedPattern,
|
|
@@ -368,14 +335,14 @@ async function handlePatternSelection(
|
|
|
368
335
|
return;
|
|
369
336
|
}
|
|
370
337
|
|
|
371
|
-
await submitDecision(baseUrl, assistantId,
|
|
338
|
+
await submitDecision(baseUrl, assistantId, requestId, "deny", bearerToken);
|
|
372
339
|
chatApp.addStatus("\u2718 Denied", "yellow");
|
|
373
340
|
}
|
|
374
341
|
|
|
375
342
|
async function handleScopeSelection(
|
|
376
343
|
baseUrl: string,
|
|
377
344
|
assistantId: string,
|
|
378
|
-
|
|
345
|
+
requestId: string,
|
|
379
346
|
confirmation: PendingConfirmation,
|
|
380
347
|
chatApp: ChatAppHandle,
|
|
381
348
|
selectedPattern: string,
|
|
@@ -393,7 +360,7 @@ async function handleScopeSelection(
|
|
|
393
360
|
await addTrustRule(
|
|
394
361
|
baseUrl,
|
|
395
362
|
assistantId,
|
|
396
|
-
|
|
363
|
+
requestId,
|
|
397
364
|
selectedPattern,
|
|
398
365
|
scopeOptions[index].scope,
|
|
399
366
|
ruleDecision,
|
|
@@ -402,7 +369,7 @@ async function handleScopeSelection(
|
|
|
402
369
|
await submitDecision(
|
|
403
370
|
baseUrl,
|
|
404
371
|
assistantId,
|
|
405
|
-
|
|
372
|
+
requestId,
|
|
406
373
|
ruleDecision === "deny" ? "deny" : "allow",
|
|
407
374
|
bearerToken,
|
|
408
375
|
);
|
|
@@ -415,7 +382,7 @@ async function handleScopeSelection(
|
|
|
415
382
|
return;
|
|
416
383
|
}
|
|
417
384
|
|
|
418
|
-
await submitDecision(baseUrl, assistantId,
|
|
385
|
+
await submitDecision(baseUrl, assistantId, requestId, "deny", bearerToken);
|
|
419
386
|
chatApp.addStatus("\u2718 Denied", "yellow");
|
|
420
387
|
}
|
|
421
388
|
|
|
@@ -1474,9 +1441,8 @@ function ChatApp({
|
|
|
1474
1441
|
const controller = new AbortController();
|
|
1475
1442
|
const timeoutId = setTimeout(() => controller.abort(), SEND_TIMEOUT_MS);
|
|
1476
1443
|
|
|
1477
|
-
let runId: string | undefined;
|
|
1478
1444
|
try {
|
|
1479
|
-
const
|
|
1445
|
+
const sendResult = await sendMessage(
|
|
1480
1446
|
runtimeUrl,
|
|
1481
1447
|
assistantId,
|
|
1482
1448
|
trimmed,
|
|
@@ -1484,29 +1450,20 @@ function ChatApp({
|
|
|
1484
1450
|
bearerToken,
|
|
1485
1451
|
);
|
|
1486
1452
|
clearTimeout(timeoutId);
|
|
1487
|
-
runId = runResult.id;
|
|
1488
|
-
} catch (createErr) {
|
|
1489
|
-
clearTimeout(timeoutId);
|
|
1490
|
-
const is409 = createErr instanceof Error && createErr.message.includes("HTTP 409");
|
|
1491
|
-
if (is409) {
|
|
1492
|
-
h.setBusy(false);
|
|
1493
|
-
h.hideSpinner();
|
|
1494
|
-
h.showError("Assistant is still working. Please wait and try again.");
|
|
1495
|
-
return;
|
|
1496
|
-
}
|
|
1497
|
-
const sendResult = await sendMessage(
|
|
1498
|
-
runtimeUrl,
|
|
1499
|
-
assistantId,
|
|
1500
|
-
trimmed,
|
|
1501
|
-
undefined,
|
|
1502
|
-
bearerToken,
|
|
1503
|
-
);
|
|
1504
1453
|
if (!sendResult.accepted) {
|
|
1505
1454
|
h.setBusy(false);
|
|
1506
1455
|
h.hideSpinner();
|
|
1507
1456
|
h.showError("Message was not accepted by the assistant");
|
|
1508
1457
|
return;
|
|
1509
1458
|
}
|
|
1459
|
+
} catch (sendErr) {
|
|
1460
|
+
clearTimeout(timeoutId);
|
|
1461
|
+
h.setBusy(false);
|
|
1462
|
+
h.hideSpinner();
|
|
1463
|
+
const errorMsg = `Failed to send: ${sendErr instanceof Error ? sendErr.message : sendErr}`;
|
|
1464
|
+
h.showError(errorMsg);
|
|
1465
|
+
chatLogRef.current.push({ role: "error", content: errorMsg });
|
|
1466
|
+
return;
|
|
1510
1467
|
}
|
|
1511
1468
|
|
|
1512
1469
|
h.showSpinner("Working...");
|
|
@@ -1514,75 +1471,47 @@ function ChatApp({
|
|
|
1514
1471
|
while (true) {
|
|
1515
1472
|
await new Promise((resolve) => setTimeout(resolve, RESPONSE_POLL_INTERVAL_MS));
|
|
1516
1473
|
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1474
|
+
// Check for pending confirmations/secrets
|
|
1475
|
+
try {
|
|
1476
|
+
const pending = await pollPendingInteractions(runtimeUrl, assistantId, bearerToken);
|
|
1477
|
+
|
|
1478
|
+
if (pending.pendingConfirmation) {
|
|
1479
|
+
h.hideSpinner();
|
|
1480
|
+
await handleConfirmationPrompt(
|
|
1481
|
+
runtimeUrl,
|
|
1482
|
+
assistantId,
|
|
1483
|
+
pending.pendingConfirmation.requestId,
|
|
1484
|
+
pending.pendingConfirmation,
|
|
1485
|
+
h,
|
|
1486
|
+
bearerToken,
|
|
1487
|
+
);
|
|
1488
|
+
h.showSpinner("Working...");
|
|
1489
|
+
continue;
|
|
1490
|
+
}
|
|
1520
1491
|
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1492
|
+
if (pending.pendingSecret) {
|
|
1493
|
+
const secretRequestId = pending.pendingSecret.requestId ?? "";
|
|
1494
|
+
h.hideSpinner();
|
|
1495
|
+
await h.handleSecretPrompt(pending.pendingSecret, async (value, delivery) => {
|
|
1496
|
+
await runtimeRequest(
|
|
1524
1497
|
runtimeUrl,
|
|
1525
1498
|
assistantId,
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1499
|
+
"/secret",
|
|
1500
|
+
{
|
|
1501
|
+
method: "POST",
|
|
1502
|
+
body: JSON.stringify({ requestId: secretRequestId, value, delivery }),
|
|
1503
|
+
},
|
|
1529
1504
|
bearerToken,
|
|
1530
1505
|
);
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
if (runStatus.status === "needs_secret" && runStatus.pendingSecret) {
|
|
1536
|
-
h.hideSpinner();
|
|
1537
|
-
await h.handleSecretPrompt(runStatus.pendingSecret, async (value, delivery) => {
|
|
1538
|
-
await runtimeRequest(
|
|
1539
|
-
runtimeUrl,
|
|
1540
|
-
assistantId,
|
|
1541
|
-
`/runs/${runId}/secret`,
|
|
1542
|
-
{
|
|
1543
|
-
method: "POST",
|
|
1544
|
-
body: JSON.stringify({ value, delivery }),
|
|
1545
|
-
},
|
|
1546
|
-
bearerToken,
|
|
1547
|
-
);
|
|
1548
|
-
});
|
|
1549
|
-
h.showSpinner("Working...");
|
|
1550
|
-
continue;
|
|
1551
|
-
}
|
|
1552
|
-
|
|
1553
|
-
if (runStatus.status === "completed") {
|
|
1554
|
-
try {
|
|
1555
|
-
const pollResult = await pollMessages(runtimeUrl, assistantId, bearerToken);
|
|
1556
|
-
for (const msg of pollResult.messages) {
|
|
1557
|
-
if (!seenMessageIdsRef.current.has(msg.id)) {
|
|
1558
|
-
seenMessageIdsRef.current.add(msg.id);
|
|
1559
|
-
if (msg.role === "assistant") {
|
|
1560
|
-
h.addMessage(msg);
|
|
1561
|
-
chatLogRef.current.push({ role: "assistant", content: msg.content });
|
|
1562
|
-
}
|
|
1563
|
-
}
|
|
1564
|
-
}
|
|
1565
|
-
} catch {
|
|
1566
|
-
// Final poll failure; continue to cleanup
|
|
1567
|
-
}
|
|
1568
|
-
h.setBusy(false);
|
|
1569
|
-
h.hideSpinner();
|
|
1570
|
-
return;
|
|
1571
|
-
}
|
|
1572
|
-
|
|
1573
|
-
if (runStatus.status === "failed") {
|
|
1574
|
-
h.setBusy(false);
|
|
1575
|
-
h.hideSpinner();
|
|
1576
|
-
const errorMsg = runStatus.error ?? "Run failed";
|
|
1577
|
-
h.showError(errorMsg);
|
|
1578
|
-
chatLogRef.current.push({ role: "error", content: errorMsg });
|
|
1579
|
-
return;
|
|
1580
|
-
}
|
|
1581
|
-
} catch {
|
|
1582
|
-
// Run status poll failure; fall through to message poll
|
|
1506
|
+
});
|
|
1507
|
+
h.showSpinner("Working...");
|
|
1508
|
+
continue;
|
|
1583
1509
|
}
|
|
1510
|
+
} catch {
|
|
1511
|
+
// Pending interactions poll failure; fall through to message poll
|
|
1584
1512
|
}
|
|
1585
1513
|
|
|
1514
|
+
// Poll for new messages to detect completion
|
|
1586
1515
|
try {
|
|
1587
1516
|
const pollResult = await pollMessages(runtimeUrl, assistantId, bearerToken);
|
|
1588
1517
|
for (const msg of pollResult.messages) {
|
|
@@ -1591,11 +1520,9 @@ function ChatApp({
|
|
|
1591
1520
|
if (msg.role === "assistant") {
|
|
1592
1521
|
h.addMessage(msg);
|
|
1593
1522
|
chatLogRef.current.push({ role: "assistant", content: msg.content });
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
return;
|
|
1598
|
-
}
|
|
1523
|
+
h.setBusy(false);
|
|
1524
|
+
h.hideSpinner();
|
|
1525
|
+
return;
|
|
1599
1526
|
}
|
|
1600
1527
|
}
|
|
1601
1528
|
}
|
|
@@ -1613,14 +1540,9 @@ function ChatApp({
|
|
|
1613
1540
|
h.showError(errorMsg);
|
|
1614
1541
|
chatLogRef.current.push({ role: "error", content: errorMsg });
|
|
1615
1542
|
} else {
|
|
1616
|
-
const
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
} else {
|
|
1620
|
-
const errorMsg = `Failed to send: ${error instanceof Error ? error.message : error}`;
|
|
1621
|
-
h.showError(errorMsg);
|
|
1622
|
-
chatLogRef.current.push({ role: "error", content: errorMsg });
|
|
1623
|
-
}
|
|
1543
|
+
const errorMsg = `Failed to send: ${error instanceof Error ? error.message : error}`;
|
|
1544
|
+
h.showError(errorMsg);
|
|
1545
|
+
chatLogRef.current.push({ role: "error", content: errorMsg });
|
|
1624
1546
|
}
|
|
1625
1547
|
}
|
|
1626
1548
|
},
|