@tangle-network/agent-app 0.43.24 → 0.43.26
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/dist/app-auth/index.d.ts +163 -0
- package/dist/app-auth/index.js +166 -0
- package/dist/app-auth/index.js.map +1 -0
- package/dist/assets/index.d.ts +2 -2
- package/dist/assistant/index.d.ts +2 -0
- package/dist/assistant/index.js +3 -1
- package/dist/assistant/index.js.map +1 -1
- package/dist/chat-routes/index.d.ts +276 -0
- package/dist/chat-routes/index.js +564 -0
- package/dist/chat-routes/index.js.map +1 -0
- package/dist/chat-store/index.d.ts +194 -0
- package/dist/chat-store/index.js +198 -0
- package/dist/chat-store/index.js.map +1 -0
- package/dist/chunk-4TXDD6P2.js +163 -0
- package/dist/chunk-4TXDD6P2.js.map +1 -0
- package/dist/chunk-5EQCITY3.js +20 -0
- package/dist/chunk-5EQCITY3.js.map +1 -0
- package/dist/chunk-5SV5PSU7.js +80 -0
- package/dist/chunk-5SV5PSU7.js.map +1 -0
- package/dist/chunk-7LNGJDNA.js +1 -0
- package/dist/chunk-7LNGJDNA.js.map +1 -0
- package/dist/{chunk-77RLNLFP.js → chunk-ATRJULKZ.js} +41 -5
- package/dist/chunk-ATRJULKZ.js.map +1 -0
- package/dist/{chunk-VMY4TKMN.js → chunk-FCQP75JT.js} +936 -436
- package/dist/chunk-FCQP75JT.js.map +1 -0
- package/dist/chunk-I2R2XT4M.js +62 -0
- package/dist/chunk-I2R2XT4M.js.map +1 -0
- package/dist/{chunk-3PK3T4KD.js → chunk-JJGZ54EB.js} +44 -1
- package/dist/chunk-JJGZ54EB.js.map +1 -0
- package/dist/chunk-TKVJE63N.js +304 -0
- package/dist/chunk-TKVJE63N.js.map +1 -0
- package/dist/{chunk-SAOAAA3S.js → chunk-UHXQ3KNX.js} +1 -22
- package/dist/chunk-UHXQ3KNX.js.map +1 -0
- package/dist/chunk-Y4QHNQ75.js +203 -0
- package/dist/chunk-Y4QHNQ75.js.map +1 -0
- package/dist/contract-DYbTzEDf.d.ts +122 -0
- package/dist/core-7qIM7svy.d.ts +21 -0
- package/dist/index.d.ts +6 -2
- package/dist/index.js +179 -92
- package/dist/interactions/index.d.ts +141 -0
- package/dist/interactions/index.js +60 -0
- package/dist/interactions/index.js.map +1 -0
- package/dist/parts-BcbitSNp.d.ts +176 -0
- package/dist/platform/index.d.ts +2 -270
- package/dist/platform/index.js +14 -278
- package/dist/platform/index.js.map +1 -1
- package/dist/preset-cloudflare/index.d.ts +0 -10
- package/dist/preset-cloudflare/index.js +1 -1
- package/dist/profile/index.d.ts +33 -2
- package/dist/profile/index.js +37 -1
- package/dist/profile/index.js.map +1 -1
- package/dist/sandbox/index.d.ts +47 -1
- package/dist/sandbox/index.js +11 -1
- package/dist/sso-CNOsARMJ.d.ts +285 -0
- package/dist/stream/index.js +1 -1
- package/dist/teams/index.js +9 -9
- package/dist/teams/invitations-api.js +3 -3
- package/dist/web-react/index.d.ts +229 -99
- package/dist/web-react/index.js +72 -22
- package/dist/wire-BaUF66AS.d.ts +61 -0
- package/package.json +25 -1
- package/dist/chunk-3PK3T4KD.js.map +0 -1
- package/dist/chunk-77RLNLFP.js.map +0 -1
- package/dist/chunk-SAOAAA3S.js.map +0 -1
- package/dist/chunk-VMY4TKMN.js.map +0 -1
|
@@ -1,13 +1,21 @@
|
|
|
1
1
|
import {
|
|
2
2
|
stepActivityFlowTrace
|
|
3
3
|
} from "./chunk-2QI7XV2T.js";
|
|
4
|
+
import {
|
|
5
|
+
cancelStatusFor,
|
|
6
|
+
fieldAcceptsFreeText,
|
|
7
|
+
interactionFromWireRequest,
|
|
8
|
+
isTerminalInteractionStatus,
|
|
9
|
+
parseInteractionRequest,
|
|
10
|
+
questionInteractionContentSignature
|
|
11
|
+
} from "./chunk-4TXDD6P2.js";
|
|
4
12
|
import {
|
|
5
13
|
snapHarnessToModel,
|
|
6
14
|
snapModelToHarness
|
|
7
15
|
} from "./chunk-E7QYOOON.js";
|
|
8
16
|
|
|
9
17
|
// src/web-react/index.tsx
|
|
10
|
-
import { useEffect as useEffect5, useMemo as
|
|
18
|
+
import { useEffect as useEffect5, useMemo as useMemo6, useRef as useRef6, useState as useState9, memo } from "react";
|
|
11
19
|
|
|
12
20
|
// src/web-react/smooth-text.ts
|
|
13
21
|
import { useEffect, useRef, useState } from "react";
|
|
@@ -364,145 +372,6 @@ function BrandMark({ size = 24, className }) {
|
|
|
364
372
|
return /* @__PURE__ */ jsx3(Suspense, { fallback: /* @__PURE__ */ jsx3(MarkSpacer, { size, className }), children: /* @__PURE__ */ jsx3(LazyKnot, { size, className }) });
|
|
365
373
|
}
|
|
366
374
|
|
|
367
|
-
// src/web-react/chat-interactions.ts
|
|
368
|
-
import {
|
|
369
|
-
InteractionRequestSchema
|
|
370
|
-
} from "@tangle-network/agent-interface";
|
|
371
|
-
var INTERACTION_EVENT = "interaction";
|
|
372
|
-
var INTERACTION_CANCEL_EVENT = "interaction.cancel";
|
|
373
|
-
var INTERACTION_RESOLVED_EVENT = "interaction.resolved";
|
|
374
|
-
var RENDERABLE_INTERACTION_KINDS = /* @__PURE__ */ new Set(["question", "plan"]);
|
|
375
|
-
function isRenderableInteractionKind(kind) {
|
|
376
|
-
return RENDERABLE_INTERACTION_KINDS.has(kind);
|
|
377
|
-
}
|
|
378
|
-
function isSafeInteractionFieldKey(key) {
|
|
379
|
-
return /^[A-Za-z0-9_-]+$/.test(key) && key !== "__proto__" && key !== "constructor" && key !== "prototype";
|
|
380
|
-
}
|
|
381
|
-
function isTerminalInteractionStatus(status) {
|
|
382
|
-
return status !== "pending";
|
|
383
|
-
}
|
|
384
|
-
function canTransitionInteractionStatus(from, to) {
|
|
385
|
-
return from === "pending" && to !== from;
|
|
386
|
-
}
|
|
387
|
-
function cancelStatusFor(reason) {
|
|
388
|
-
return reason === "timeout" ? "expired" : "cancelled";
|
|
389
|
-
}
|
|
390
|
-
function stableValue(value) {
|
|
391
|
-
if (Array.isArray(value)) return value.map(stableValue);
|
|
392
|
-
if (!value || typeof value !== "object") return value;
|
|
393
|
-
return Object.fromEntries(
|
|
394
|
-
Object.entries(value).sort(([left], [right]) => left.localeCompare(right)).map(([key, nested]) => [key, stableValue(nested)])
|
|
395
|
-
);
|
|
396
|
-
}
|
|
397
|
-
function normalizedInteractionText(value) {
|
|
398
|
-
return (value ?? "").replace(/\s+/g, " ").trim();
|
|
399
|
-
}
|
|
400
|
-
function questionInteractionContentSignature(interaction) {
|
|
401
|
-
if (interaction.kind !== "question") return null;
|
|
402
|
-
return JSON.stringify(stableValue({
|
|
403
|
-
kind: interaction.kind,
|
|
404
|
-
title: normalizedInteractionText(interaction.title),
|
|
405
|
-
body: normalizedInteractionText(interaction.body),
|
|
406
|
-
fields: interaction.fields
|
|
407
|
-
}));
|
|
408
|
-
}
|
|
409
|
-
function dedupeQuestionInteractionsByContent(interactions) {
|
|
410
|
-
const seen = /* @__PURE__ */ new Set();
|
|
411
|
-
return interactions.filter((interaction) => {
|
|
412
|
-
const signature = questionInteractionContentSignature(interaction);
|
|
413
|
-
if (!signature) return true;
|
|
414
|
-
if (seen.has(signature)) return false;
|
|
415
|
-
seen.add(signature);
|
|
416
|
-
return true;
|
|
417
|
-
});
|
|
418
|
-
}
|
|
419
|
-
function parseInteractionRequest(data) {
|
|
420
|
-
const request = data?.request;
|
|
421
|
-
if (!request || typeof request !== "object") {
|
|
422
|
-
return { succeeded: false, error: "interaction event carried no request object" };
|
|
423
|
-
}
|
|
424
|
-
const validation = InteractionRequestSchema.safeParse(request);
|
|
425
|
-
if (!validation.success) {
|
|
426
|
-
return { succeeded: false, error: `malformed interaction request: ${validation.error.message}` };
|
|
427
|
-
}
|
|
428
|
-
return { succeeded: true, value: request };
|
|
429
|
-
}
|
|
430
|
-
function parseInteractionCancel(data) {
|
|
431
|
-
const id = typeof data?.id === "string" && data.id ? data.id : null;
|
|
432
|
-
if (!id) return { succeeded: false, error: "interaction.cancel event carried no id" };
|
|
433
|
-
const reason = typeof data?.reason === "string" && data.reason ? data.reason : void 0;
|
|
434
|
-
return { succeeded: true, value: { id, ...reason ? { reason } : {} } };
|
|
435
|
-
}
|
|
436
|
-
function fieldAcceptsFreeText(field) {
|
|
437
|
-
if (field.type === "text") return true;
|
|
438
|
-
if (field.type === "select") return field.allowCustom === true;
|
|
439
|
-
return false;
|
|
440
|
-
}
|
|
441
|
-
function composerAnswerDeliveries(pending) {
|
|
442
|
-
const deliveries = [];
|
|
443
|
-
for (const interaction of pending) {
|
|
444
|
-
if (interaction.kind !== "question") continue;
|
|
445
|
-
const field = interaction.fields.find(fieldAcceptsFreeText) ?? interaction.fields[0];
|
|
446
|
-
if (!field) continue;
|
|
447
|
-
deliveries.push({ interactionId: interaction.id, field });
|
|
448
|
-
}
|
|
449
|
-
return deliveries;
|
|
450
|
-
}
|
|
451
|
-
function composerAnswerData(field, text) {
|
|
452
|
-
return { [field.name]: field.type === "select" ? [text] : text };
|
|
453
|
-
}
|
|
454
|
-
function interactionPartKey(id) {
|
|
455
|
-
return `interaction:${id}`;
|
|
456
|
-
}
|
|
457
|
-
function noticePartKey(id) {
|
|
458
|
-
return `notice:${id}`;
|
|
459
|
-
}
|
|
460
|
-
function noticePart(noticeKind, id, text) {
|
|
461
|
-
return { type: "notice", id, noticeKind, text };
|
|
462
|
-
}
|
|
463
|
-
function interactionFromWireRequest(request) {
|
|
464
|
-
return {
|
|
465
|
-
id: request.id,
|
|
466
|
-
kind: request.kind,
|
|
467
|
-
title: request.title,
|
|
468
|
-
...request.body ? { body: request.body } : {},
|
|
469
|
-
fields: request.answerSpec.fields,
|
|
470
|
-
status: "pending"
|
|
471
|
-
};
|
|
472
|
-
}
|
|
473
|
-
function interactionToPersistedPart(request, status, cancelReason) {
|
|
474
|
-
return {
|
|
475
|
-
type: "interaction",
|
|
476
|
-
id: request.id,
|
|
477
|
-
kind: request.kind,
|
|
478
|
-
title: request.title,
|
|
479
|
-
...request.body ? { body: request.body } : {},
|
|
480
|
-
answerSpec: { fields: request.answerSpec.fields },
|
|
481
|
-
status,
|
|
482
|
-
...cancelReason ? { cancelReason } : {}
|
|
483
|
-
};
|
|
484
|
-
}
|
|
485
|
-
function persistedPartToInteraction(part) {
|
|
486
|
-
if (String(part.type ?? "") !== "interaction") return null;
|
|
487
|
-
const id = typeof part.id === "string" && part.id ? part.id : null;
|
|
488
|
-
const kind = typeof part.kind === "string" && part.kind ? part.kind : null;
|
|
489
|
-
const title = typeof part.title === "string" ? part.title : "";
|
|
490
|
-
const answerSpec = part.answerSpec;
|
|
491
|
-
const fields = Array.isArray(answerSpec?.fields) ? answerSpec.fields : null;
|
|
492
|
-
const status = part.status;
|
|
493
|
-
const validStatus = status && ["pending", "answered", "declined", "cancelled", "expired"].includes(status);
|
|
494
|
-
if (!id || !kind || !fields || !validStatus) return null;
|
|
495
|
-
return {
|
|
496
|
-
id,
|
|
497
|
-
kind,
|
|
498
|
-
title,
|
|
499
|
-
...typeof part.body === "string" && part.body ? { body: part.body } : {},
|
|
500
|
-
fields,
|
|
501
|
-
status,
|
|
502
|
-
...typeof part.cancelReason === "string" && part.cancelReason ? { cancelReason: part.cancelReason } : {}
|
|
503
|
-
};
|
|
504
|
-
}
|
|
505
|
-
|
|
506
375
|
// src/web-react/chat-stream.ts
|
|
507
376
|
function dispatchChatStreamLine(line, cb) {
|
|
508
377
|
let receivedContent = false;
|
|
@@ -578,9 +447,19 @@ function dispatchChatStreamLine(line, cb) {
|
|
|
578
447
|
}
|
|
579
448
|
break;
|
|
580
449
|
}
|
|
581
|
-
case "error":
|
|
582
|
-
|
|
450
|
+
case "error": {
|
|
451
|
+
const message = String(evt.details ?? evt.error ?? "Unknown stream error");
|
|
452
|
+
if (cb.onErrorEvent) {
|
|
453
|
+
cb.onErrorEvent(message);
|
|
454
|
+
} else {
|
|
455
|
+
console.error("[chat-stream] unhandled stream error event:", message);
|
|
456
|
+
cb.onText?.(`
|
|
457
|
+
|
|
458
|
+
The agent hit an error and this turn stopped: ${message}`);
|
|
459
|
+
receivedContent = true;
|
|
460
|
+
}
|
|
583
461
|
break;
|
|
462
|
+
}
|
|
584
463
|
default:
|
|
585
464
|
break;
|
|
586
465
|
}
|
|
@@ -670,6 +549,7 @@ function UploadGlyph({ className }) {
|
|
|
670
549
|
var MAX_HEIGHT = 168;
|
|
671
550
|
function ChatComposer({
|
|
672
551
|
onSend,
|
|
552
|
+
onSendParts,
|
|
673
553
|
onCancel,
|
|
674
554
|
isStreaming = false,
|
|
675
555
|
disabled = false,
|
|
@@ -722,13 +602,23 @@ function ChatComposer({
|
|
|
722
602
|
document.addEventListener("keydown", onKeyDown);
|
|
723
603
|
return () => document.removeEventListener("keydown", onKeyDown);
|
|
724
604
|
}, [focusShortcut, disabled]);
|
|
725
|
-
const
|
|
605
|
+
const readyParts = pendingFiles.filter((f) => f.status === "ready" && f.part).map((f) => f.part);
|
|
606
|
+
const hasSendable = onSendParts ? text.trim().length > 0 || readyParts.length > 0 : text.trim().length > 0;
|
|
607
|
+
const canSend = hasSendable && !isStreaming && !disabled;
|
|
726
608
|
const send = useCallback(() => {
|
|
727
609
|
const trimmed = text.trim();
|
|
728
|
-
if (
|
|
729
|
-
|
|
610
|
+
if (isStreaming || disabled) return;
|
|
611
|
+
if (onSendParts) {
|
|
612
|
+
const parts = pendingFiles.filter((f) => f.status === "ready" && f.part).map((f) => f.part);
|
|
613
|
+
if (!trimmed && parts.length === 0) return;
|
|
614
|
+
onSendParts(trimmed, parts);
|
|
615
|
+
setText("");
|
|
616
|
+
return;
|
|
617
|
+
}
|
|
618
|
+
if (!trimmed) return;
|
|
619
|
+
onSend?.(trimmed);
|
|
730
620
|
setText("");
|
|
731
|
-
}, [text, isStreaming, disabled, onSend, setText]);
|
|
621
|
+
}, [text, isStreaming, disabled, onSend, onSendParts, pendingFiles, setText]);
|
|
732
622
|
const handleKeyDown = (e) => {
|
|
733
623
|
if (e.nativeEvent.isComposing) return;
|
|
734
624
|
if (e.key === "Enter" && !e.shiftKey) {
|
|
@@ -914,9 +804,618 @@ function ChatComposer({
|
|
|
914
804
|
);
|
|
915
805
|
}
|
|
916
806
|
|
|
917
|
-
// src/web-react/
|
|
918
|
-
|
|
807
|
+
// src/web-react/interaction-card-support.ts
|
|
808
|
+
function interactionStatusLabels(labels) {
|
|
809
|
+
return { cancelled: "Withdrawn", expired: "Expired", ...labels };
|
|
810
|
+
}
|
|
811
|
+
function interactionTerminalNotes(noun, extra) {
|
|
812
|
+
return {
|
|
813
|
+
expired: `This ${noun} expired \u2014 send a new message to continue.`,
|
|
814
|
+
cancelled: `The agent withdrew this ${noun}.`,
|
|
815
|
+
...extra
|
|
816
|
+
};
|
|
817
|
+
}
|
|
818
|
+
function fieldAnswer(field, values) {
|
|
819
|
+
const value = values[field.name] ?? {};
|
|
820
|
+
if (field.type === "select") {
|
|
821
|
+
const custom = field.allowCustom === true ? value.custom?.trim() : void 0;
|
|
822
|
+
const chosen = [...value.selected ?? [], ...custom ? [custom] : []];
|
|
823
|
+
if (field.multi !== true && custom) return [custom];
|
|
824
|
+
return chosen.length > 0 ? chosen : null;
|
|
825
|
+
}
|
|
826
|
+
if (field.type === "number") {
|
|
827
|
+
const parsed = Number(value.text);
|
|
828
|
+
return value.text?.trim() && Number.isFinite(parsed) ? parsed : null;
|
|
829
|
+
}
|
|
830
|
+
if (field.type === "boolean") return value.selected ? value.selected[0] === "true" : null;
|
|
831
|
+
const text = value.text?.trim();
|
|
832
|
+
return text ? text : null;
|
|
833
|
+
}
|
|
834
|
+
function buildAnswerData(fields, values) {
|
|
835
|
+
const data = {};
|
|
836
|
+
for (const field of fields) {
|
|
837
|
+
const answer = fieldAnswer(field, values);
|
|
838
|
+
if (answer === null) {
|
|
839
|
+
if (field.required === false) continue;
|
|
840
|
+
return null;
|
|
841
|
+
}
|
|
842
|
+
data[field.name] = answer;
|
|
843
|
+
}
|
|
844
|
+
return data;
|
|
845
|
+
}
|
|
846
|
+
function isLateAnswerableStatus(status) {
|
|
847
|
+
return status === "expired" || status === "cancelled";
|
|
848
|
+
}
|
|
849
|
+
function hasSecretField(fields) {
|
|
850
|
+
return fields.some((field) => field.type === "secret");
|
|
851
|
+
}
|
|
852
|
+
function optionLabel(field, value) {
|
|
853
|
+
return field.options.find((option) => option.value === value)?.label ?? value;
|
|
854
|
+
}
|
|
855
|
+
function answerText(field, answer) {
|
|
856
|
+
if (field.type === "select" && Array.isArray(answer)) {
|
|
857
|
+
return answer.map((value) => optionLabel(field, value)).join(", ");
|
|
858
|
+
}
|
|
859
|
+
if (field.type === "boolean") return answer === true ? "Yes" : "No";
|
|
860
|
+
if (field.type === "secret") return "[secret omitted]";
|
|
861
|
+
return String(answer);
|
|
862
|
+
}
|
|
863
|
+
function lateAnswerMessage(interaction, data) {
|
|
864
|
+
const title = interaction.title.trim() || "the earlier question";
|
|
865
|
+
const body = interaction.body?.trim();
|
|
866
|
+
const answers = interaction.fields.map((field) => {
|
|
867
|
+
const answer = data[field.name];
|
|
868
|
+
if (answer === void 0) return null;
|
|
869
|
+
return { label: field.label.trim(), text: answerText(field, answer).trim() };
|
|
870
|
+
}).filter((item) => !!item && item.text.length > 0);
|
|
871
|
+
const only = answers.length === 1 ? answers[0] : void 0;
|
|
872
|
+
const answerSummary = only ? only.text : answers.map((item) => `${item.label || "Answer"}: ${item.text}`).join("\n");
|
|
873
|
+
return [
|
|
874
|
+
`Regarding your earlier question: "${title}"`,
|
|
875
|
+
body ? `Context: ${body}` : null,
|
|
876
|
+
`My answer: ${answerSummary}`
|
|
877
|
+
].filter((line) => !!line).join("\n");
|
|
878
|
+
}
|
|
879
|
+
var INTERACTION_SUBMIT_TIMEOUT_MS = 3e4;
|
|
880
|
+
var INTERACTION_SUBMIT_TIMEOUT_MESSAGE = "Could not reach the agent. Try again.";
|
|
881
|
+
async function responseErrorMessage(res) {
|
|
882
|
+
const text = await res.text().catch(() => "");
|
|
883
|
+
if (text) {
|
|
884
|
+
try {
|
|
885
|
+
const parsed = JSON.parse(text);
|
|
886
|
+
const message = typeof parsed.error === "string" && parsed.error.trim() ? parsed.error : typeof parsed.message === "string" && parsed.message.trim() ? parsed.message : null;
|
|
887
|
+
if (message) return { ...typeof parsed.code === "string" ? { code: parsed.code } : {}, message };
|
|
888
|
+
} catch {
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
return { message: `Answer failed (${res.status})` };
|
|
892
|
+
}
|
|
893
|
+
function createInteractionAnswerSubmitter(options) {
|
|
894
|
+
const timeoutMs = options.timeoutMs ?? INTERACTION_SUBMIT_TIMEOUT_MS;
|
|
895
|
+
return async (submission) => {
|
|
896
|
+
const doFetch = options.fetchImpl ?? fetch;
|
|
897
|
+
const url = typeof options.url === "function" ? options.url(submission) : options.url;
|
|
898
|
+
const extra = typeof options.body === "function" ? options.body(submission) : options.body ?? {};
|
|
899
|
+
const controller = new AbortController();
|
|
900
|
+
const timer = setTimeout(() => controller.abort(INTERACTION_SUBMIT_TIMEOUT_MESSAGE), timeoutMs);
|
|
901
|
+
try {
|
|
902
|
+
const res = await doFetch(url, {
|
|
903
|
+
method: "POST",
|
|
904
|
+
headers: { "Content-Type": "application/json" },
|
|
905
|
+
signal: controller.signal,
|
|
906
|
+
body: JSON.stringify({
|
|
907
|
+
...extra,
|
|
908
|
+
id: submission.id,
|
|
909
|
+
outcome: submission.outcome,
|
|
910
|
+
...submission.data ? { data: submission.data } : {}
|
|
911
|
+
})
|
|
912
|
+
});
|
|
913
|
+
if (res.ok) return { ok: true };
|
|
914
|
+
const failure = await responseErrorMessage(res);
|
|
915
|
+
return { ok: false, expired: res.status === 410, message: failure.message };
|
|
916
|
+
} catch (err) {
|
|
917
|
+
if (controller.signal.aborted) {
|
|
918
|
+
return { ok: false, expired: false, message: INTERACTION_SUBMIT_TIMEOUT_MESSAGE };
|
|
919
|
+
}
|
|
920
|
+
return { ok: false, expired: false, message: err instanceof Error ? err.message : "Failed to submit the answer" };
|
|
921
|
+
} finally {
|
|
922
|
+
clearTimeout(timer);
|
|
923
|
+
}
|
|
924
|
+
};
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
// src/web-react/interaction-question-card.tsx
|
|
928
|
+
import { useMemo as useMemo2, useRef as useRef4, useState as useState4 } from "react";
|
|
919
929
|
import { Fragment as Fragment3, jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
930
|
+
function CheckGlyph({ className }) {
|
|
931
|
+
return /* @__PURE__ */ jsx5("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: /* @__PURE__ */ jsx5("path", { d: "M20 6 9 17l-5-5" }) });
|
|
932
|
+
}
|
|
933
|
+
var BADGE_VARIANT_CLASSES = {
|
|
934
|
+
outline: "border-border text-foreground",
|
|
935
|
+
default: "border-transparent bg-primary text-primary-foreground",
|
|
936
|
+
destructive: "border-transparent bg-destructive/15 text-destructive"
|
|
937
|
+
};
|
|
938
|
+
function InteractionBadge({ variant, children }) {
|
|
939
|
+
return /* @__PURE__ */ jsx5("span", { className: `inline-flex items-center rounded-md border px-2 py-0.5 text-xs font-medium ${BADGE_VARIANT_CLASSES[variant]}`, children });
|
|
940
|
+
}
|
|
941
|
+
function InteractionActionButton({
|
|
942
|
+
variant = "primary",
|
|
943
|
+
onClick,
|
|
944
|
+
disabled,
|
|
945
|
+
children
|
|
946
|
+
}) {
|
|
947
|
+
const variantClasses = variant === "primary" ? "bg-primary text-primary-foreground shadow-sm hover:bg-primary/90" : "border border-border bg-transparent text-foreground hover:bg-accent/40";
|
|
948
|
+
return /* @__PURE__ */ jsx5(
|
|
949
|
+
"button",
|
|
950
|
+
{
|
|
951
|
+
type: "button",
|
|
952
|
+
onClick,
|
|
953
|
+
disabled,
|
|
954
|
+
className: `inline-flex items-center gap-1.5 rounded-lg px-3 py-1.5 text-sm font-medium transition disabled:cursor-not-allowed disabled:opacity-40 focus:outline-none focus-visible:ring-2 focus-visible:ring-ring ${variantClasses}`,
|
|
955
|
+
children
|
|
956
|
+
}
|
|
957
|
+
);
|
|
958
|
+
}
|
|
959
|
+
var FIELD_INPUT_CLASSES = "w-full rounded-lg border border-border bg-background px-3 py-2 text-sm text-foreground outline-none focus:border-primary disabled:opacity-50";
|
|
960
|
+
function QuestionOptionList({
|
|
961
|
+
groupName,
|
|
962
|
+
idPrefix,
|
|
963
|
+
options,
|
|
964
|
+
multi,
|
|
965
|
+
selectedValues,
|
|
966
|
+
disabled,
|
|
967
|
+
onToggle
|
|
968
|
+
}) {
|
|
969
|
+
return /* @__PURE__ */ jsx5(Fragment3, { children: options.map((option, optionIndex) => {
|
|
970
|
+
const inputId = `${idPrefix}-${optionIndex}`;
|
|
971
|
+
const checked = selectedValues.includes(option.value);
|
|
972
|
+
return /* @__PURE__ */ jsxs4("label", { htmlFor: inputId, className: "flex cursor-pointer gap-2 rounded-lg border border-border/70 p-3 transition-colors hover:bg-muted/50", children: [
|
|
973
|
+
/* @__PURE__ */ jsx5(
|
|
974
|
+
"input",
|
|
975
|
+
{
|
|
976
|
+
id: inputId,
|
|
977
|
+
type: multi ? "checkbox" : "radio",
|
|
978
|
+
name: groupName,
|
|
979
|
+
value: option.value,
|
|
980
|
+
checked,
|
|
981
|
+
disabled,
|
|
982
|
+
onChange: () => onToggle(option.value),
|
|
983
|
+
"aria-labelledby": `${inputId}-label`,
|
|
984
|
+
"aria-describedby": option.description ? `${inputId}-description` : void 0,
|
|
985
|
+
className: "mt-0.5 h-4 w-4 shrink-0 accent-primary"
|
|
986
|
+
}
|
|
987
|
+
),
|
|
988
|
+
/* @__PURE__ */ jsxs4("span", { className: "min-w-0", children: [
|
|
989
|
+
/* @__PURE__ */ jsx5("span", { id: `${inputId}-label`, className: "block text-sm font-medium leading-5 text-foreground", children: option.label }),
|
|
990
|
+
option.description && /* @__PURE__ */ jsx5("span", { id: `${inputId}-description`, className: "mt-0.5 block text-xs leading-5 text-muted-foreground", children: option.description })
|
|
991
|
+
] })
|
|
992
|
+
] }, `${option.value}-${optionIndex}`);
|
|
993
|
+
}) });
|
|
994
|
+
}
|
|
995
|
+
function selectField(field) {
|
|
996
|
+
return field.type === "select" ? field : null;
|
|
997
|
+
}
|
|
998
|
+
function valuesWithSelected(values, field, optionValue) {
|
|
999
|
+
const current = values[field.name]?.selected ?? [];
|
|
1000
|
+
let selected = [optionValue];
|
|
1001
|
+
if (field.multi === true) {
|
|
1002
|
+
selected = current.includes(optionValue) ? current.filter((item) => item !== optionValue) : [...current, optionValue];
|
|
1003
|
+
}
|
|
1004
|
+
return { ...values, [field.name]: { ...values[field.name], selected } };
|
|
1005
|
+
}
|
|
1006
|
+
var STATUS_LABELS = interactionStatusLabels({
|
|
1007
|
+
pending: "Waiting for your answer",
|
|
1008
|
+
answered: "Answered",
|
|
1009
|
+
declined: "Declined"
|
|
1010
|
+
});
|
|
1011
|
+
var TERMINAL_NOTES = interactionTerminalNotes("question", {
|
|
1012
|
+
expired: "The original run ended. Answer now to send a new message with this context.",
|
|
1013
|
+
cancelled: "The agent withdrew this question. Answer now to send a new message with this context."
|
|
1014
|
+
});
|
|
1015
|
+
function InteractionQuestionCard({
|
|
1016
|
+
interaction,
|
|
1017
|
+
canWrite,
|
|
1018
|
+
submitAnswer,
|
|
1019
|
+
onResolved,
|
|
1020
|
+
onLateAnswer,
|
|
1021
|
+
className
|
|
1022
|
+
}) {
|
|
1023
|
+
const [values, setValues] = useState4({});
|
|
1024
|
+
const [submitting, setSubmitting] = useState4(false);
|
|
1025
|
+
const [localStatus, setLocalStatus] = useState4(null);
|
|
1026
|
+
const [lateAnswerSent, setLateAnswerSent] = useState4(false);
|
|
1027
|
+
const [error, setError] = useState4(null);
|
|
1028
|
+
const submitInFlightRef = useRef4(false);
|
|
1029
|
+
const status = isTerminalInteractionStatus(interaction.status) ? interaction.status : localStatus ?? interaction.status;
|
|
1030
|
+
const answered = status === "answered";
|
|
1031
|
+
const lateAnswerable = isLateAnswerableStatus(status) && onLateAnswer !== void 0;
|
|
1032
|
+
const secretLateAnswerBlocked = lateAnswerable && hasSecretField(interaction.fields);
|
|
1033
|
+
const canLateAnswer = canWrite && lateAnswerable && !lateAnswerSent && !secretLateAnswerBlocked;
|
|
1034
|
+
const disabled = !canWrite || status !== "pending" && !canLateAnswer || submitting;
|
|
1035
|
+
const answerData = useMemo2(() => buildAnswerData(interaction.fields, values), [interaction.fields, values]);
|
|
1036
|
+
const setFieldValue = (name, patch) => {
|
|
1037
|
+
setValues((prev) => ({ ...prev, [name]: { ...prev[name], ...patch } }));
|
|
1038
|
+
};
|
|
1039
|
+
const toggleSelected = (field, optionValue) => {
|
|
1040
|
+
setValues((prev) => valuesWithSelected(prev, field, optionValue));
|
|
1041
|
+
};
|
|
1042
|
+
async function submitLateAnswer() {
|
|
1043
|
+
if (submitInFlightRef.current || !canLateAnswer || !onLateAnswer) return;
|
|
1044
|
+
const data = buildAnswerData(interaction.fields, values);
|
|
1045
|
+
if (!data) return;
|
|
1046
|
+
submitInFlightRef.current = true;
|
|
1047
|
+
setSubmitting(true);
|
|
1048
|
+
setError(null);
|
|
1049
|
+
let accepted;
|
|
1050
|
+
try {
|
|
1051
|
+
accepted = await onLateAnswer(lateAnswerMessage(interaction, data));
|
|
1052
|
+
} catch {
|
|
1053
|
+
accepted = false;
|
|
1054
|
+
} finally {
|
|
1055
|
+
submitInFlightRef.current = false;
|
|
1056
|
+
setSubmitting(false);
|
|
1057
|
+
}
|
|
1058
|
+
if (accepted === false) {
|
|
1059
|
+
setError("The new message was not sent. Try again from this card.");
|
|
1060
|
+
return;
|
|
1061
|
+
}
|
|
1062
|
+
setLateAnswerSent(true);
|
|
1063
|
+
}
|
|
1064
|
+
async function submit() {
|
|
1065
|
+
if (lateAnswerable) {
|
|
1066
|
+
await submitLateAnswer();
|
|
1067
|
+
return;
|
|
1068
|
+
}
|
|
1069
|
+
if (submitInFlightRef.current || disabled || !answerData) return;
|
|
1070
|
+
submitInFlightRef.current = true;
|
|
1071
|
+
setSubmitting(true);
|
|
1072
|
+
setError(null);
|
|
1073
|
+
try {
|
|
1074
|
+
const result = await submitAnswer({ id: interaction.id, outcome: "accepted", data: answerData });
|
|
1075
|
+
if (result.ok) {
|
|
1076
|
+
setLocalStatus("answered");
|
|
1077
|
+
onResolved?.(interaction.id, "answered");
|
|
1078
|
+
return;
|
|
1079
|
+
}
|
|
1080
|
+
if (result.expired) {
|
|
1081
|
+
setLocalStatus("expired");
|
|
1082
|
+
onResolved?.(interaction.id, "expired");
|
|
1083
|
+
return;
|
|
1084
|
+
}
|
|
1085
|
+
setError(result.message);
|
|
1086
|
+
} finally {
|
|
1087
|
+
submitInFlightRef.current = false;
|
|
1088
|
+
setSubmitting(false);
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
const terminalNote = secretLateAnswerBlocked ? "This question asked for a secret, so it cannot be sent as a new chat message. Ask the agent to request it again." : TERMINAL_NOTES[status];
|
|
1092
|
+
const showSubmitButton = status === "pending" || canWrite && lateAnswerable && !lateAnswerSent;
|
|
1093
|
+
let submitLabel = "Submit answer";
|
|
1094
|
+
if (lateAnswerable) {
|
|
1095
|
+
submitLabel = submitting ? "Sending\u2026" : "Send as new message";
|
|
1096
|
+
} else if (submitting) {
|
|
1097
|
+
submitLabel = "Submitting\u2026";
|
|
1098
|
+
}
|
|
1099
|
+
return /* @__PURE__ */ jsxs4("div", { className: `rounded-xl border border-border bg-card p-4 shadow-sm ${className ?? ""}`, children: [
|
|
1100
|
+
/* @__PURE__ */ jsxs4("div", { className: "mb-3 flex flex-wrap items-center justify-between gap-2", children: [
|
|
1101
|
+
/* @__PURE__ */ jsxs4("div", { className: "flex flex-wrap items-center gap-2", children: [
|
|
1102
|
+
/* @__PURE__ */ jsx5(InteractionBadge, { variant: "outline", children: "Question" }),
|
|
1103
|
+
/* @__PURE__ */ jsx5(InteractionBadge, { variant: answered ? "default" : status === "expired" || status === "declined" ? "destructive" : "outline", children: STATUS_LABELS[status] })
|
|
1104
|
+
] }),
|
|
1105
|
+
/* @__PURE__ */ jsx5("span", { className: "text-xs text-muted-foreground", children: "The agent asked for input" })
|
|
1106
|
+
] }),
|
|
1107
|
+
interaction.title.trim() && interaction.fields.every((field) => field.label !== interaction.title) && /* @__PURE__ */ jsx5("p", { className: "mb-3 text-sm font-medium leading-5 text-foreground", children: interaction.title }),
|
|
1108
|
+
interaction.body && /* @__PURE__ */ jsx5("p", { className: "mb-3 text-sm leading-5 text-muted-foreground", children: interaction.body }),
|
|
1109
|
+
/* @__PURE__ */ jsx5("div", { className: "space-y-4", children: interaction.fields.map((field) => {
|
|
1110
|
+
const value = values[field.name] ?? {};
|
|
1111
|
+
const select = selectField(field);
|
|
1112
|
+
return /* @__PURE__ */ jsxs4("fieldset", { className: "space-y-2", children: [
|
|
1113
|
+
/* @__PURE__ */ jsx5("p", { className: "text-sm font-medium leading-5 text-foreground", children: field.label }),
|
|
1114
|
+
select ? /* @__PURE__ */ jsxs4("div", { className: "space-y-2", children: [
|
|
1115
|
+
/* @__PURE__ */ jsx5(
|
|
1116
|
+
QuestionOptionList,
|
|
1117
|
+
{
|
|
1118
|
+
groupName: `${interaction.id}-${field.name}`,
|
|
1119
|
+
idPrefix: `${interaction.id}-${field.name}`,
|
|
1120
|
+
options: select.options,
|
|
1121
|
+
multi: select.multi === true,
|
|
1122
|
+
selectedValues: value.selected ?? [],
|
|
1123
|
+
disabled,
|
|
1124
|
+
onToggle: (optionValue) => toggleSelected(select, optionValue)
|
|
1125
|
+
}
|
|
1126
|
+
),
|
|
1127
|
+
select.allowCustom === true && /* @__PURE__ */ jsx5(
|
|
1128
|
+
"input",
|
|
1129
|
+
{
|
|
1130
|
+
type: "text",
|
|
1131
|
+
value: value.custom ?? "",
|
|
1132
|
+
disabled,
|
|
1133
|
+
onChange: (event) => setFieldValue(field.name, { custom: event.target.value }),
|
|
1134
|
+
placeholder: "Other \u2014 type your own answer",
|
|
1135
|
+
"aria-label": `Custom answer for ${field.label}`,
|
|
1136
|
+
className: FIELD_INPUT_CLASSES
|
|
1137
|
+
}
|
|
1138
|
+
)
|
|
1139
|
+
] }) : field.type === "boolean" ? /* @__PURE__ */ jsx5("div", { className: "flex gap-4", children: ["true", "false"].map((boolValue) => /* @__PURE__ */ jsxs4("label", { className: "flex cursor-pointer items-center gap-2 text-sm text-foreground", children: [
|
|
1140
|
+
/* @__PURE__ */ jsx5(
|
|
1141
|
+
"input",
|
|
1142
|
+
{
|
|
1143
|
+
type: "radio",
|
|
1144
|
+
name: `${interaction.id}-${field.name}`,
|
|
1145
|
+
value: boolValue,
|
|
1146
|
+
checked: (value.selected ?? [])[0] === boolValue,
|
|
1147
|
+
disabled,
|
|
1148
|
+
onChange: () => setFieldValue(field.name, { selected: [boolValue] }),
|
|
1149
|
+
className: "h-4 w-4 accent-primary"
|
|
1150
|
+
}
|
|
1151
|
+
),
|
|
1152
|
+
boolValue === "true" ? "Yes" : "No"
|
|
1153
|
+
] }, boolValue)) }) : field.type === "number" ? /* @__PURE__ */ jsx5(
|
|
1154
|
+
"input",
|
|
1155
|
+
{
|
|
1156
|
+
type: "number",
|
|
1157
|
+
value: value.text ?? "",
|
|
1158
|
+
disabled,
|
|
1159
|
+
"aria-label": field.label,
|
|
1160
|
+
onChange: (event) => setFieldValue(field.name, { text: event.target.value }),
|
|
1161
|
+
className: FIELD_INPUT_CLASSES
|
|
1162
|
+
}
|
|
1163
|
+
) : field.type === "secret" ? /* @__PURE__ */ jsx5(
|
|
1164
|
+
"input",
|
|
1165
|
+
{
|
|
1166
|
+
type: "password",
|
|
1167
|
+
value: value.text ?? "",
|
|
1168
|
+
disabled,
|
|
1169
|
+
"aria-label": field.label,
|
|
1170
|
+
onChange: (event) => setFieldValue(field.name, { text: event.target.value }),
|
|
1171
|
+
placeholder: field.placeholder,
|
|
1172
|
+
className: FIELD_INPUT_CLASSES
|
|
1173
|
+
}
|
|
1174
|
+
) : /* @__PURE__ */ jsx5(
|
|
1175
|
+
"textarea",
|
|
1176
|
+
{
|
|
1177
|
+
value: value.text ?? "",
|
|
1178
|
+
disabled,
|
|
1179
|
+
"aria-label": field.label,
|
|
1180
|
+
onChange: (event) => setFieldValue(field.name, { text: event.target.value }),
|
|
1181
|
+
rows: 3,
|
|
1182
|
+
placeholder: field.type === "text" ? field.placeholder : void 0,
|
|
1183
|
+
className: FIELD_INPUT_CLASSES
|
|
1184
|
+
}
|
|
1185
|
+
)
|
|
1186
|
+
] }, field.name);
|
|
1187
|
+
}) }),
|
|
1188
|
+
error && /* @__PURE__ */ jsx5("p", { className: "mt-3 text-xs text-destructive", children: error }),
|
|
1189
|
+
terminalNote && /* @__PURE__ */ jsx5("p", { className: "mt-3 text-xs text-muted-foreground", children: terminalNote }),
|
|
1190
|
+
showSubmitButton && /* @__PURE__ */ jsx5("div", { className: "mt-4 flex items-center justify-end gap-2", children: /* @__PURE__ */ jsx5(InteractionActionButton, { onClick: () => void submit(), disabled: disabled || !answerData, children: submitLabel }) }),
|
|
1191
|
+
answered && /* @__PURE__ */ jsx5("div", { className: "mt-4 flex items-center justify-end", children: /* @__PURE__ */ jsxs4("span", { className: "inline-flex items-center gap-1 text-xs text-muted-foreground", children: [
|
|
1192
|
+
/* @__PURE__ */ jsx5(CheckGlyph, { className: "h-3 w-3" }),
|
|
1193
|
+
"Answered"
|
|
1194
|
+
] }) }),
|
|
1195
|
+
lateAnswerSent && /* @__PURE__ */ jsx5("div", { className: "mt-4 flex items-center justify-end", children: /* @__PURE__ */ jsxs4("span", { className: "inline-flex items-center gap-1 text-xs text-muted-foreground", children: [
|
|
1196
|
+
/* @__PURE__ */ jsx5(CheckGlyph, { className: "h-3 w-3" }),
|
|
1197
|
+
"Sent as new message"
|
|
1198
|
+
] }) })
|
|
1199
|
+
] });
|
|
1200
|
+
}
|
|
1201
|
+
|
|
1202
|
+
// src/web-react/interaction-plan-card.tsx
|
|
1203
|
+
import { useMemo as useMemo3, useRef as useRef5, useState as useState5 } from "react";
|
|
1204
|
+
import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1205
|
+
function CheckGlyph2({ className }) {
|
|
1206
|
+
return /* @__PURE__ */ jsx6("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: /* @__PURE__ */ jsx6("path", { d: "M20 6 9 17l-5-5" }) });
|
|
1207
|
+
}
|
|
1208
|
+
function ChevronDownGlyph({ className }) {
|
|
1209
|
+
return /* @__PURE__ */ jsx6("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: /* @__PURE__ */ jsx6("path", { d: "m6 9 6 6 6-6" }) });
|
|
1210
|
+
}
|
|
1211
|
+
var STATUS_LABELS2 = interactionStatusLabels({
|
|
1212
|
+
pending: "Waiting for your approval",
|
|
1213
|
+
answered: "Approved",
|
|
1214
|
+
declined: "Rejected"
|
|
1215
|
+
});
|
|
1216
|
+
var TERMINAL_NOTES2 = interactionTerminalNotes("plan", {
|
|
1217
|
+
declined: "The agent was asked to revise the plan."
|
|
1218
|
+
});
|
|
1219
|
+
var COLLAPSED_MAX_HEIGHT = 320;
|
|
1220
|
+
function InteractionPlanCard({
|
|
1221
|
+
interaction,
|
|
1222
|
+
canWrite,
|
|
1223
|
+
submitAnswer,
|
|
1224
|
+
onResolved,
|
|
1225
|
+
renderMarkdown,
|
|
1226
|
+
className
|
|
1227
|
+
}) {
|
|
1228
|
+
const [values, setValues] = useState5({});
|
|
1229
|
+
const [expanded, setExpanded] = useState5(false);
|
|
1230
|
+
const [submitting, setSubmitting] = useState5(null);
|
|
1231
|
+
const [localStatus, setLocalStatus] = useState5(null);
|
|
1232
|
+
const [error, setError] = useState5(null);
|
|
1233
|
+
const submitInFlightRef = useRef5(false);
|
|
1234
|
+
const status = isTerminalInteractionStatus(interaction.status) ? interaction.status : localStatus ?? interaction.status;
|
|
1235
|
+
const disabled = !canWrite || status !== "pending" || submitting !== null;
|
|
1236
|
+
const approveData = useMemo3(() => buildAnswerData(interaction.fields, values), [interaction.fields, values]);
|
|
1237
|
+
const rejectData = useMemo3(() => {
|
|
1238
|
+
const data = {};
|
|
1239
|
+
for (const field of interaction.fields) {
|
|
1240
|
+
const answer = fieldAnswer(field, values);
|
|
1241
|
+
if (answer !== null) data[field.name] = answer;
|
|
1242
|
+
}
|
|
1243
|
+
return data;
|
|
1244
|
+
}, [interaction.fields, values]);
|
|
1245
|
+
async function submit(outcome) {
|
|
1246
|
+
const data = outcome === "accepted" ? approveData : rejectData;
|
|
1247
|
+
if (submitInFlightRef.current || disabled || data === null) return;
|
|
1248
|
+
submitInFlightRef.current = true;
|
|
1249
|
+
setSubmitting(outcome === "accepted" ? "approve" : "reject");
|
|
1250
|
+
setError(null);
|
|
1251
|
+
try {
|
|
1252
|
+
const result = await submitAnswer({ id: interaction.id, outcome, data });
|
|
1253
|
+
if (result.ok) {
|
|
1254
|
+
const resolved = outcome === "accepted" ? "answered" : "declined";
|
|
1255
|
+
setLocalStatus(resolved);
|
|
1256
|
+
onResolved?.(interaction.id, resolved);
|
|
1257
|
+
return;
|
|
1258
|
+
}
|
|
1259
|
+
if (result.expired) {
|
|
1260
|
+
setLocalStatus("expired");
|
|
1261
|
+
onResolved?.(interaction.id, "expired");
|
|
1262
|
+
return;
|
|
1263
|
+
}
|
|
1264
|
+
setError(result.message);
|
|
1265
|
+
} finally {
|
|
1266
|
+
submitInFlightRef.current = false;
|
|
1267
|
+
setSubmitting(null);
|
|
1268
|
+
}
|
|
1269
|
+
}
|
|
1270
|
+
const terminalNote = TERMINAL_NOTES2[status];
|
|
1271
|
+
const approved = status === "answered";
|
|
1272
|
+
return /* @__PURE__ */ jsxs5("div", { className: `rounded-xl border border-border bg-card p-4 shadow-sm ${className ?? ""}`, children: [
|
|
1273
|
+
/* @__PURE__ */ jsxs5("div", { className: "mb-3 flex flex-wrap items-center justify-between gap-2", children: [
|
|
1274
|
+
/* @__PURE__ */ jsxs5("div", { className: "flex flex-wrap items-center gap-2", children: [
|
|
1275
|
+
/* @__PURE__ */ jsx6(InteractionBadge, { variant: "outline", children: "Plan" }),
|
|
1276
|
+
/* @__PURE__ */ jsx6(InteractionBadge, { variant: approved ? "default" : status === "expired" || status === "declined" ? "destructive" : "outline", children: STATUS_LABELS2[status] })
|
|
1277
|
+
] }),
|
|
1278
|
+
/* @__PURE__ */ jsx6("span", { className: "text-xs text-muted-foreground", children: "The agent proposed a plan" })
|
|
1279
|
+
] }),
|
|
1280
|
+
interaction.title.trim() && /* @__PURE__ */ jsx6("p", { className: "mb-3 text-sm font-medium leading-5 text-foreground", children: interaction.title }),
|
|
1281
|
+
interaction.body && /* @__PURE__ */ jsxs5("div", { className: "relative", children: [
|
|
1282
|
+
/* @__PURE__ */ jsx6(
|
|
1283
|
+
"div",
|
|
1284
|
+
{
|
|
1285
|
+
className: "overflow-hidden text-sm text-foreground",
|
|
1286
|
+
style: expanded ? void 0 : { maxHeight: COLLAPSED_MAX_HEIGHT },
|
|
1287
|
+
children: renderMarkdown ? renderMarkdown(interaction.body) : /* @__PURE__ */ jsx6("p", { className: "whitespace-pre-wrap leading-5", children: interaction.body })
|
|
1288
|
+
}
|
|
1289
|
+
),
|
|
1290
|
+
!expanded && /* @__PURE__ */ jsx6("div", { className: "pointer-events-none absolute inset-x-0 bottom-0 h-12 bg-gradient-to-t from-card to-transparent" }),
|
|
1291
|
+
/* @__PURE__ */ jsxs5(
|
|
1292
|
+
"button",
|
|
1293
|
+
{
|
|
1294
|
+
type: "button",
|
|
1295
|
+
onClick: () => setExpanded((prev) => !prev),
|
|
1296
|
+
className: "mt-1 inline-flex items-center gap-1 text-xs text-muted-foreground transition hover:text-foreground focus:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
1297
|
+
children: [
|
|
1298
|
+
/* @__PURE__ */ jsx6(ChevronDownGlyph, { className: `h-3 w-3 transition-transform ${expanded ? "rotate-180" : ""}` }),
|
|
1299
|
+
expanded ? "Collapse plan" : "Show full plan"
|
|
1300
|
+
]
|
|
1301
|
+
}
|
|
1302
|
+
)
|
|
1303
|
+
] }),
|
|
1304
|
+
interaction.fields.length > 0 && /* @__PURE__ */ jsx6("div", { className: "mt-3 space-y-4", children: interaction.fields.map((field) => /* @__PURE__ */ jsxs5("fieldset", { className: "space-y-2", children: [
|
|
1305
|
+
/* @__PURE__ */ jsx6("p", { className: "text-sm font-medium leading-5 text-foreground", children: field.label }),
|
|
1306
|
+
fieldAcceptsFreeText(field) ? /* @__PURE__ */ jsx6(
|
|
1307
|
+
"textarea",
|
|
1308
|
+
{
|
|
1309
|
+
value: values[field.name]?.text ?? "",
|
|
1310
|
+
disabled,
|
|
1311
|
+
"aria-label": field.label,
|
|
1312
|
+
onChange: (event) => setValues((prev) => ({ ...prev, [field.name]: { ...prev[field.name], text: event.target.value } })),
|
|
1313
|
+
rows: 2,
|
|
1314
|
+
placeholder: field.type === "text" ? field.placeholder ?? "Optional feedback for the agent" : void 0,
|
|
1315
|
+
className: "w-full rounded-lg border border-border bg-background px-3 py-2 text-sm text-foreground outline-none focus:border-primary disabled:opacity-50"
|
|
1316
|
+
}
|
|
1317
|
+
) : /* @__PURE__ */ jsx6(
|
|
1318
|
+
"input",
|
|
1319
|
+
{
|
|
1320
|
+
type: "text",
|
|
1321
|
+
value: values[field.name]?.text ?? "",
|
|
1322
|
+
disabled,
|
|
1323
|
+
"aria-label": field.label,
|
|
1324
|
+
onChange: (event) => setValues((prev) => ({ ...prev, [field.name]: { ...prev[field.name], text: event.target.value } })),
|
|
1325
|
+
className: "w-full rounded-lg border border-border bg-background px-3 py-2 text-sm text-foreground outline-none focus:border-primary disabled:opacity-50"
|
|
1326
|
+
}
|
|
1327
|
+
)
|
|
1328
|
+
] }, field.name)) }),
|
|
1329
|
+
error && /* @__PURE__ */ jsx6("p", { className: "mt-3 text-xs text-destructive", children: error }),
|
|
1330
|
+
terminalNote && /* @__PURE__ */ jsx6("p", { className: "mt-3 text-xs text-muted-foreground", children: terminalNote }),
|
|
1331
|
+
status === "pending" && /* @__PURE__ */ jsxs5("div", { className: "mt-4 flex items-center justify-end gap-2", children: [
|
|
1332
|
+
/* @__PURE__ */ jsx6(InteractionActionButton, { variant: "outline", onClick: () => void submit("declined"), disabled, children: submitting === "reject" ? "Sending\u2026" : "Request changes" }),
|
|
1333
|
+
/* @__PURE__ */ jsx6(InteractionActionButton, { onClick: () => void submit("accepted"), disabled: disabled || approveData === null, children: submitting === "approve" ? "Approving\u2026" : "Approve plan" })
|
|
1334
|
+
] }),
|
|
1335
|
+
approved && /* @__PURE__ */ jsx6("div", { className: "mt-4 flex items-center justify-end", children: /* @__PURE__ */ jsxs5("span", { className: "inline-flex items-center gap-1 text-xs text-muted-foreground", children: [
|
|
1336
|
+
/* @__PURE__ */ jsx6(CheckGlyph2, { className: "h-3 w-3" }),
|
|
1337
|
+
"Approved"
|
|
1338
|
+
] }) })
|
|
1339
|
+
] });
|
|
1340
|
+
}
|
|
1341
|
+
|
|
1342
|
+
// src/web-react/use-chat-interactions.ts
|
|
1343
|
+
import { useCallback as useCallback2, useMemo as useMemo4, useState as useState6 } from "react";
|
|
1344
|
+
function hasPendingContentDuplicate(list, interaction) {
|
|
1345
|
+
if (interaction.status !== "pending") return false;
|
|
1346
|
+
const signature = questionInteractionContentSignature(interaction);
|
|
1347
|
+
if (!signature) return false;
|
|
1348
|
+
return list.some((item) => item.id !== interaction.id && item.status === "pending" && questionInteractionContentSignature(item) === signature);
|
|
1349
|
+
}
|
|
1350
|
+
function upsertChatInteraction(list, interaction) {
|
|
1351
|
+
const index = list.findIndex((item) => item.id === interaction.id);
|
|
1352
|
+
if (index === -1) {
|
|
1353
|
+
if (hasPendingContentDuplicate(list, interaction)) return list;
|
|
1354
|
+
return [...list, interaction];
|
|
1355
|
+
}
|
|
1356
|
+
const existing = list[index];
|
|
1357
|
+
if (!existing || isTerminalInteractionStatus(existing.status)) return list;
|
|
1358
|
+
const next = [...list];
|
|
1359
|
+
next[index] = interaction;
|
|
1360
|
+
return next;
|
|
1361
|
+
}
|
|
1362
|
+
function cancelChatInteraction(list, cancel) {
|
|
1363
|
+
const index = list.findIndex((item) => item.id === cancel.id);
|
|
1364
|
+
const existing = list[index];
|
|
1365
|
+
if (!existing || existing.status !== "pending") return list;
|
|
1366
|
+
const next = [...list];
|
|
1367
|
+
next[index] = {
|
|
1368
|
+
...existing,
|
|
1369
|
+
status: cancelStatusFor(cancel.reason),
|
|
1370
|
+
...cancel.reason ? { cancelReason: cancel.reason } : {}
|
|
1371
|
+
};
|
|
1372
|
+
return next;
|
|
1373
|
+
}
|
|
1374
|
+
function resolveChatInteraction(list, id, status) {
|
|
1375
|
+
const index = list.findIndex((item) => item.id === id);
|
|
1376
|
+
const existing = list[index];
|
|
1377
|
+
if (!existing || existing.status !== "pending") return list;
|
|
1378
|
+
const next = [...list];
|
|
1379
|
+
next[index] = { ...existing, status };
|
|
1380
|
+
return next;
|
|
1381
|
+
}
|
|
1382
|
+
function terminalizePendingChatInteractions(list, status) {
|
|
1383
|
+
if (!list.some((item) => item.status === "pending")) return list;
|
|
1384
|
+
return list.map((item) => item.status === "pending" ? { ...item, status } : item);
|
|
1385
|
+
}
|
|
1386
|
+
function restoreChatInteractions(list, outstanding) {
|
|
1387
|
+
const outstandingIds = new Set(outstanding.map((request) => request.id));
|
|
1388
|
+
let next = list.map((item) => item.status === "pending" && !outstandingIds.has(item.id) ? { ...item, status: "answered" } : item);
|
|
1389
|
+
for (const request of outstanding) {
|
|
1390
|
+
next = upsertChatInteraction(next, interactionFromWireRequest(request));
|
|
1391
|
+
}
|
|
1392
|
+
return next;
|
|
1393
|
+
}
|
|
1394
|
+
function useChatInteractions() {
|
|
1395
|
+
const [interactions, setInteractions] = useState6([]);
|
|
1396
|
+
const upsert = useCallback2((interaction) => {
|
|
1397
|
+
setInteractions((prev) => upsertChatInteraction(prev, interaction));
|
|
1398
|
+
}, []);
|
|
1399
|
+
const applyCancel = useCallback2((cancel) => {
|
|
1400
|
+
setInteractions((prev) => cancelChatInteraction(prev, cancel));
|
|
1401
|
+
}, []);
|
|
1402
|
+
const markResolved = useCallback2((id, status) => {
|
|
1403
|
+
setInteractions((prev) => resolveChatInteraction(prev, id, status));
|
|
1404
|
+
}, []);
|
|
1405
|
+
const restore = useCallback2((outstanding) => {
|
|
1406
|
+
setInteractions((prev) => restoreChatInteractions(prev, outstanding));
|
|
1407
|
+
}, []);
|
|
1408
|
+
const terminalizePending = useCallback2((status) => {
|
|
1409
|
+
setInteractions((prev) => terminalizePendingChatInteractions(prev, status));
|
|
1410
|
+
}, []);
|
|
1411
|
+
const reset = useCallback2(() => setInteractions([]), []);
|
|
1412
|
+
const pending = useMemo4(() => interactions.filter((item) => item.status === "pending"), [interactions]);
|
|
1413
|
+
return { interactions, pending, upsert, applyCancel, markResolved, restore, terminalizePending, reset };
|
|
1414
|
+
}
|
|
1415
|
+
|
|
1416
|
+
// src/web-react/mission-activity.tsx
|
|
1417
|
+
import { useCallback as useCallback3, useEffect as useEffect4, useState as useState7 } from "react";
|
|
1418
|
+
import { Fragment as Fragment4, jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
920
1419
|
var LIVE_STATUSES = /* @__PURE__ */ new Set(["pending", "running"]);
|
|
921
1420
|
var OK_STATUSES = /* @__PURE__ */ new Set(["completed", "done", "succeeded"]);
|
|
922
1421
|
var ERROR_STATUSES = /* @__PURE__ */ new Set(["failed", "error", "cancelled", "aborted"]);
|
|
@@ -963,20 +1462,20 @@ function waterfallLayout(trace) {
|
|
|
963
1462
|
});
|
|
964
1463
|
}
|
|
965
1464
|
function ChevronGlyph({ className }) {
|
|
966
|
-
return /* @__PURE__ */
|
|
1465
|
+
return /* @__PURE__ */ jsx7("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: /* @__PURE__ */ jsx7("path", { d: "m6 9 6 6 6-6" }) });
|
|
967
1466
|
}
|
|
968
1467
|
function RefreshGlyph({ className }) {
|
|
969
|
-
return /* @__PURE__ */
|
|
1468
|
+
return /* @__PURE__ */ jsx7("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: /* @__PURE__ */ jsx7("path", { d: "M21 12a9 9 0 1 1-2.64-6.36M21 3v6h-6" }) });
|
|
970
1469
|
}
|
|
971
1470
|
function CopyGlyph({ className }) {
|
|
972
|
-
return /* @__PURE__ */
|
|
973
|
-
/* @__PURE__ */
|
|
974
|
-
/* @__PURE__ */
|
|
1471
|
+
return /* @__PURE__ */ jsxs6("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
|
|
1472
|
+
/* @__PURE__ */ jsx7("rect", { x: "9", y: "9", width: "13", height: "13", rx: "2" }),
|
|
1473
|
+
/* @__PURE__ */ jsx7("path", { d: "M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" })
|
|
975
1474
|
] });
|
|
976
1475
|
}
|
|
977
1476
|
function TraceIdCopy({ traceId }) {
|
|
978
|
-
const [copied, setCopied] =
|
|
979
|
-
const copy =
|
|
1477
|
+
const [copied, setCopied] = useState7(false);
|
|
1478
|
+
const copy = useCallback3(() => {
|
|
980
1479
|
void navigator.clipboard?.writeText(traceId).then(
|
|
981
1480
|
() => {
|
|
982
1481
|
setCopied(true);
|
|
@@ -986,7 +1485,7 @@ function TraceIdCopy({ traceId }) {
|
|
|
986
1485
|
}
|
|
987
1486
|
);
|
|
988
1487
|
}, [traceId]);
|
|
989
|
-
return /* @__PURE__ */
|
|
1488
|
+
return /* @__PURE__ */ jsxs6(
|
|
990
1489
|
"button",
|
|
991
1490
|
{
|
|
992
1491
|
type: "button",
|
|
@@ -995,23 +1494,23 @@ function TraceIdCopy({ traceId }) {
|
|
|
995
1494
|
"aria-label": "Copy trace id",
|
|
996
1495
|
className: "inline-flex min-w-0 items-center gap-1.5 rounded text-left font-mono text-muted-foreground transition hover:text-foreground focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-card",
|
|
997
1496
|
children: [
|
|
998
|
-
/* @__PURE__ */
|
|
999
|
-
/* @__PURE__ */
|
|
1000
|
-
copied && /* @__PURE__ */
|
|
1497
|
+
/* @__PURE__ */ jsx7("span", { className: "truncate", children: traceId }),
|
|
1498
|
+
/* @__PURE__ */ jsx7(CopyGlyph, { className: "h-3 w-3 shrink-0" }),
|
|
1499
|
+
copied && /* @__PURE__ */ jsx7("span", { className: "shrink-0 not-italic text-success", children: "copied" })
|
|
1001
1500
|
]
|
|
1002
1501
|
}
|
|
1003
1502
|
);
|
|
1004
1503
|
}
|
|
1005
1504
|
function StatusDot({ tone }) {
|
|
1006
|
-
return /* @__PURE__ */
|
|
1007
|
-
/* @__PURE__ */
|
|
1505
|
+
return /* @__PURE__ */ jsxs6("span", { className: "inline-flex items-center", children: [
|
|
1506
|
+
/* @__PURE__ */ jsx7(
|
|
1008
1507
|
"span",
|
|
1009
1508
|
{
|
|
1010
1509
|
"aria-hidden": true,
|
|
1011
1510
|
className: `h-2 w-2 shrink-0 rounded-full ${tone === "live" ? "animate-pulse bg-warning" : tone === "ok" ? "bg-success" : tone === "error" ? "bg-destructive" : "bg-muted-foreground/40"}`
|
|
1012
1511
|
}
|
|
1013
1512
|
),
|
|
1014
|
-
/* @__PURE__ */
|
|
1513
|
+
/* @__PURE__ */ jsx7("span", { className: "sr-only", children: tone })
|
|
1015
1514
|
] });
|
|
1016
1515
|
}
|
|
1017
1516
|
var BAR_CLASS = {
|
|
@@ -1023,19 +1522,19 @@ function FlowWaterfall({ trace }) {
|
|
|
1023
1522
|
const rows = waterfallLayout(trace);
|
|
1024
1523
|
if (rows.length === 0) return null;
|
|
1025
1524
|
const cost = formatActivityCost(trace.costUsd);
|
|
1026
|
-
return /* @__PURE__ */
|
|
1027
|
-
rows.map((row, i) => /* @__PURE__ */
|
|
1028
|
-
/* @__PURE__ */
|
|
1029
|
-
/* @__PURE__ */
|
|
1525
|
+
return /* @__PURE__ */ jsxs6("div", { className: "space-y-1", children: [
|
|
1526
|
+
rows.map((row, i) => /* @__PURE__ */ jsxs6("div", { className: "grid grid-cols-[minmax(0,2fr)_minmax(0,3fr)_auto] items-center gap-2", children: [
|
|
1527
|
+
/* @__PURE__ */ jsx7("span", { className: "truncate font-mono text-[11px] text-muted-foreground", title: row.name, children: row.name }),
|
|
1528
|
+
/* @__PURE__ */ jsx7("div", { className: "relative h-2 rounded-sm bg-muted/40", children: /* @__PURE__ */ jsx7(
|
|
1030
1529
|
"div",
|
|
1031
1530
|
{
|
|
1032
1531
|
className: `absolute inset-y-0 rounded-sm ${row.ok ? BAR_CLASS[row.kind] : "bg-destructive/80"} ${row.approx ? "opacity-70" : ""}`,
|
|
1033
1532
|
style: { left: `${row.offsetPct}%`, width: `${row.widthPct}%` }
|
|
1034
1533
|
}
|
|
1035
1534
|
) }),
|
|
1036
|
-
/* @__PURE__ */
|
|
1535
|
+
/* @__PURE__ */ jsx7("span", { className: "shrink-0 font-mono text-[10px] tabular-nums text-muted-foreground/70", children: row.durationLabel })
|
|
1037
1536
|
] }, i)),
|
|
1038
|
-
/* @__PURE__ */
|
|
1537
|
+
/* @__PURE__ */ jsxs6("p", { className: "pt-0.5 text-right font-mono text-[10px] tabular-nums text-muted-foreground/60", children: [
|
|
1039
1538
|
(trace.totalMs / 1e3).toFixed(1),
|
|
1040
1539
|
"s",
|
|
1041
1540
|
cost ? ` \xB7 ${cost}` : ""
|
|
@@ -1043,43 +1542,43 @@ function FlowWaterfall({ trace }) {
|
|
|
1043
1542
|
] });
|
|
1044
1543
|
}
|
|
1045
1544
|
function MissionActivityLane({ activity, startedAt, nowMs }) {
|
|
1046
|
-
const [expanded, setExpanded] =
|
|
1545
|
+
const [expanded, setExpanded] = useState7(false);
|
|
1047
1546
|
if (activity.length === 0) return null;
|
|
1048
|
-
return /* @__PURE__ */
|
|
1547
|
+
return /* @__PURE__ */ jsxs6("div", { className: "mt-1 border-l border-border/50 pl-3", children: [
|
|
1049
1548
|
activity.map((run) => {
|
|
1050
1549
|
const tone = activityTone(run.status);
|
|
1051
1550
|
const cost = formatActivityCost(run.costUsd);
|
|
1052
1551
|
const duration = formatActivityDuration(run.durationMs);
|
|
1053
|
-
return /* @__PURE__ */
|
|
1054
|
-
/* @__PURE__ */
|
|
1055
|
-
/* @__PURE__ */
|
|
1056
|
-
/* @__PURE__ */
|
|
1057
|
-
/* @__PURE__ */
|
|
1552
|
+
return /* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-2 py-1 text-xs", children: [
|
|
1553
|
+
/* @__PURE__ */ jsx7(StatusDot, { tone }),
|
|
1554
|
+
/* @__PURE__ */ jsxs6("span", { className: "min-w-0 flex-1 truncate", children: [
|
|
1555
|
+
/* @__PURE__ */ jsx7("span", { className: "font-medium", children: run.tool }),
|
|
1556
|
+
/* @__PURE__ */ jsxs6("span", { className: "text-muted-foreground", children: [
|
|
1058
1557
|
" \u2014 ",
|
|
1059
1558
|
run.detail
|
|
1060
1559
|
] })
|
|
1061
1560
|
] }),
|
|
1062
|
-
tone === "live" && (run.iteration !== void 0 || run.phase !== void 0) && /* @__PURE__ */
|
|
1063
|
-
/* @__PURE__ */
|
|
1064
|
-
tone !== "live" && tone !== "ok" && /* @__PURE__ */
|
|
1065
|
-
cost && /* @__PURE__ */
|
|
1066
|
-
duration && /* @__PURE__ */
|
|
1561
|
+
tone === "live" && (run.iteration !== void 0 || run.phase !== void 0) && /* @__PURE__ */ jsx7("span", { className: "shrink-0 rounded-full bg-warning/10 px-1.5 py-0.5 font-mono text-[10px] text-warning", children: [run.iteration !== void 0 ? `iter ${run.iteration}` : null, run.phase ?? null].filter(Boolean).join(" \xB7 ") }),
|
|
1562
|
+
/* @__PURE__ */ jsxs6("span", { className: "flex shrink-0 items-center gap-1.5 font-mono text-[10px] tabular-nums text-muted-foreground/70", children: [
|
|
1563
|
+
tone !== "live" && tone !== "ok" && /* @__PURE__ */ jsx7("span", { children: run.status }),
|
|
1564
|
+
cost && /* @__PURE__ */ jsx7("span", { children: cost }),
|
|
1565
|
+
duration && /* @__PURE__ */ jsx7("span", { children: duration })
|
|
1067
1566
|
] })
|
|
1068
1567
|
] }, run.taskId);
|
|
1069
1568
|
}),
|
|
1070
|
-
/* @__PURE__ */
|
|
1569
|
+
/* @__PURE__ */ jsxs6(
|
|
1071
1570
|
"button",
|
|
1072
1571
|
{
|
|
1073
1572
|
type: "button",
|
|
1074
1573
|
onClick: () => setExpanded((v) => !v),
|
|
1075
1574
|
className: "flex items-center gap-1 py-0.5 text-[10px] font-medium text-muted-foreground/70 transition hover:text-foreground",
|
|
1076
1575
|
children: [
|
|
1077
|
-
/* @__PURE__ */
|
|
1576
|
+
/* @__PURE__ */ jsx7(ChevronGlyph, { className: `h-3 w-3 transition-transform ${expanded ? "rotate-180" : ""}` }),
|
|
1078
1577
|
"timeline"
|
|
1079
1578
|
]
|
|
1080
1579
|
}
|
|
1081
1580
|
),
|
|
1082
|
-
expanded && /* @__PURE__ */
|
|
1581
|
+
expanded && /* @__PURE__ */ jsx7("div", { className: "rounded-md border border-border/50 bg-muted/10 p-2", children: /* @__PURE__ */ jsx7(
|
|
1083
1582
|
FlowWaterfall,
|
|
1084
1583
|
{
|
|
1085
1584
|
trace: stepActivityFlowTrace(activity, {
|
|
@@ -1094,45 +1593,45 @@ function ActivityRow({
|
|
|
1094
1593
|
record,
|
|
1095
1594
|
renderMissionRef
|
|
1096
1595
|
}) {
|
|
1097
|
-
const [open, setOpen] =
|
|
1596
|
+
const [open, setOpen] = useState7(false);
|
|
1098
1597
|
const tone = activityTone(record.status);
|
|
1099
1598
|
const cost = formatActivityCost(record.costUsd);
|
|
1100
1599
|
const duration = formatActivityDuration(record.durationMs);
|
|
1101
|
-
return /* @__PURE__ */
|
|
1102
|
-
/* @__PURE__ */
|
|
1103
|
-
/* @__PURE__ */
|
|
1104
|
-
/* @__PURE__ */
|
|
1105
|
-
/* @__PURE__ */
|
|
1106
|
-
/* @__PURE__ */
|
|
1600
|
+
return /* @__PURE__ */ jsxs6("div", { className: "rounded-lg border border-border/60 bg-card", children: [
|
|
1601
|
+
/* @__PURE__ */ jsxs6("button", { type: "button", onClick: () => setOpen((v) => !v), className: "flex w-full items-center gap-2.5 px-3 py-2 text-left text-sm", children: [
|
|
1602
|
+
/* @__PURE__ */ jsx7(StatusDot, { tone }),
|
|
1603
|
+
/* @__PURE__ */ jsxs6("span", { className: "min-w-0 flex-1 truncate", children: [
|
|
1604
|
+
/* @__PURE__ */ jsx7("span", { className: "font-medium", children: record.tool }),
|
|
1605
|
+
/* @__PURE__ */ jsxs6("span", { className: "text-muted-foreground", children: [
|
|
1107
1606
|
" \u2014 ",
|
|
1108
1607
|
record.detail
|
|
1109
1608
|
] })
|
|
1110
1609
|
] }),
|
|
1111
|
-
tone === "live" && (record.iteration !== void 0 || record.phase !== void 0) && /* @__PURE__ */
|
|
1112
|
-
/* @__PURE__ */
|
|
1610
|
+
tone === "live" && (record.iteration !== void 0 || record.phase !== void 0) && /* @__PURE__ */ jsx7("span", { className: "shrink-0 rounded-full bg-warning/10 px-2 py-0.5 font-mono text-[10px] text-warning", children: [record.iteration !== void 0 ? `iter ${record.iteration}` : null, record.phase ?? null].filter(Boolean).join(" \xB7 ") }),
|
|
1611
|
+
/* @__PURE__ */ jsx7(
|
|
1113
1612
|
"span",
|
|
1114
1613
|
{
|
|
1115
1614
|
className: `shrink-0 rounded-full px-2 py-0.5 text-[10px] font-medium ${tone === "ok" ? "bg-success/10 text-success" : tone === "error" ? "bg-destructive/10 text-destructive" : tone === "live" ? "bg-warning/10 text-warning" : "bg-muted/60 text-muted-foreground"}`,
|
|
1116
1615
|
children: record.status
|
|
1117
1616
|
}
|
|
1118
1617
|
),
|
|
1119
|
-
cost && /* @__PURE__ */
|
|
1120
|
-
/* @__PURE__ */
|
|
1618
|
+
cost && /* @__PURE__ */ jsx7("span", { className: "shrink-0 font-mono text-[11px] tabular-nums text-muted-foreground", children: cost }),
|
|
1619
|
+
/* @__PURE__ */ jsx7(ChevronGlyph, { className: `h-3 w-3 shrink-0 text-muted-foreground transition-transform ${open ? "rotate-180" : ""}` })
|
|
1121
1620
|
] }),
|
|
1122
|
-
open && /* @__PURE__ */
|
|
1123
|
-
record.durationMs !== void 0 && /* @__PURE__ */
|
|
1124
|
-
/* @__PURE__ */
|
|
1125
|
-
/* @__PURE__ */
|
|
1126
|
-
/* @__PURE__ */
|
|
1127
|
-
/* @__PURE__ */
|
|
1128
|
-
/* @__PURE__ */
|
|
1129
|
-
duration && /* @__PURE__ */
|
|
1130
|
-
/* @__PURE__ */
|
|
1131
|
-
/* @__PURE__ */
|
|
1621
|
+
open && /* @__PURE__ */ jsxs6("div", { className: "space-y-2.5 border-t border-border/40 px-3 py-2.5", children: [
|
|
1622
|
+
record.durationMs !== void 0 && /* @__PURE__ */ jsx7("div", { className: "rounded-md border border-border/50 bg-muted/10 p-2", children: /* @__PURE__ */ jsx7(FlowWaterfall, { trace: stepActivityFlowTrace([record]) }) }),
|
|
1623
|
+
/* @__PURE__ */ jsxs6("dl", { className: "grid grid-cols-[auto_1fr] gap-x-3 gap-y-1 font-mono text-[11px]", children: [
|
|
1624
|
+
/* @__PURE__ */ jsx7("dt", { className: "text-muted-foreground/60", children: "task" }),
|
|
1625
|
+
/* @__PURE__ */ jsx7("dd", { className: "truncate text-muted-foreground", children: record.taskId }),
|
|
1626
|
+
/* @__PURE__ */ jsx7("dt", { className: "text-muted-foreground/60", children: "started" }),
|
|
1627
|
+
/* @__PURE__ */ jsx7("dd", { className: "text-muted-foreground", children: new Date(record.startedAt).toLocaleString() }),
|
|
1628
|
+
duration && /* @__PURE__ */ jsxs6(Fragment4, { children: [
|
|
1629
|
+
/* @__PURE__ */ jsx7("dt", { className: "text-muted-foreground/60", children: "duration" }),
|
|
1630
|
+
/* @__PURE__ */ jsx7("dd", { className: "text-muted-foreground", children: duration })
|
|
1132
1631
|
] }),
|
|
1133
|
-
record.traceId && /* @__PURE__ */
|
|
1134
|
-
/* @__PURE__ */
|
|
1135
|
-
/* @__PURE__ */
|
|
1632
|
+
record.traceId && /* @__PURE__ */ jsxs6(Fragment4, { children: [
|
|
1633
|
+
/* @__PURE__ */ jsx7("dt", { className: "text-muted-foreground/60", children: "trace" }),
|
|
1634
|
+
/* @__PURE__ */ jsx7("dd", { className: "min-w-0", children: /* @__PURE__ */ jsx7(TraceIdCopy, { traceId: record.traceId }) })
|
|
1136
1635
|
] })
|
|
1137
1636
|
] }),
|
|
1138
1637
|
record.missionRef && renderMissionRef?.(record.missionRef, record)
|
|
@@ -1140,11 +1639,11 @@ function ActivityRow({
|
|
|
1140
1639
|
] });
|
|
1141
1640
|
}
|
|
1142
1641
|
function AgentActivityPanel({ fetchActivity, renderMissionRef, title = "Agent activity", emptyLabel = "No agent runs yet." }) {
|
|
1143
|
-
const [rows, setRows] =
|
|
1144
|
-
const [cursor, setCursor] =
|
|
1145
|
-
const [loading, setLoading] =
|
|
1146
|
-
const [error, setError] =
|
|
1147
|
-
const load =
|
|
1642
|
+
const [rows, setRows] = useState7([]);
|
|
1643
|
+
const [cursor, setCursor] = useState7(void 0);
|
|
1644
|
+
const [loading, setLoading] = useState7(false);
|
|
1645
|
+
const [error, setError] = useState7(null);
|
|
1646
|
+
const load = useCallback3(
|
|
1148
1647
|
async (from) => {
|
|
1149
1648
|
setLoading(true);
|
|
1150
1649
|
setError(null);
|
|
@@ -1163,10 +1662,10 @@ function AgentActivityPanel({ fetchActivity, renderMissionRef, title = "Agent ac
|
|
|
1163
1662
|
useEffect4(() => {
|
|
1164
1663
|
void load();
|
|
1165
1664
|
}, [load]);
|
|
1166
|
-
return /* @__PURE__ */
|
|
1167
|
-
/* @__PURE__ */
|
|
1168
|
-
/* @__PURE__ */
|
|
1169
|
-
/* @__PURE__ */
|
|
1665
|
+
return /* @__PURE__ */ jsxs6("div", { className: "space-y-2", children: [
|
|
1666
|
+
/* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-2", children: [
|
|
1667
|
+
/* @__PURE__ */ jsx7("h2", { className: "flex-1 text-sm font-semibold", children: title }),
|
|
1668
|
+
/* @__PURE__ */ jsx7(
|
|
1170
1669
|
"button",
|
|
1171
1670
|
{
|
|
1172
1671
|
type: "button",
|
|
@@ -1174,14 +1673,14 @@ function AgentActivityPanel({ fetchActivity, renderMissionRef, title = "Agent ac
|
|
|
1174
1673
|
disabled: loading,
|
|
1175
1674
|
"aria-label": "Refresh",
|
|
1176
1675
|
className: "rounded-md p-1.5 text-muted-foreground transition hover:bg-accent/30 hover:text-foreground disabled:opacity-50",
|
|
1177
|
-
children: /* @__PURE__ */
|
|
1676
|
+
children: /* @__PURE__ */ jsx7(RefreshGlyph, { className: `h-3.5 w-3.5 ${loading ? "animate-spin" : ""}` })
|
|
1178
1677
|
}
|
|
1179
1678
|
)
|
|
1180
1679
|
] }),
|
|
1181
|
-
error && /* @__PURE__ */
|
|
1182
|
-
!error && rows.length === 0 && !loading && /* @__PURE__ */
|
|
1183
|
-
/* @__PURE__ */
|
|
1184
|
-
cursor && /* @__PURE__ */
|
|
1680
|
+
error && /* @__PURE__ */ jsx7("p", { role: "alert", className: "rounded-md border border-destructive/40 bg-destructive/5 px-3 py-2 text-xs text-destructive", children: error }),
|
|
1681
|
+
!error && rows.length === 0 && !loading && /* @__PURE__ */ jsx7("p", { className: "px-1 text-sm text-muted-foreground", children: emptyLabel }),
|
|
1682
|
+
/* @__PURE__ */ jsx7("div", { className: "space-y-1.5", children: rows.map((record) => /* @__PURE__ */ jsx7(ActivityRow, { record, renderMissionRef }, record.taskId)) }),
|
|
1683
|
+
cursor && /* @__PURE__ */ jsx7(
|
|
1185
1684
|
"button",
|
|
1186
1685
|
{
|
|
1187
1686
|
type: "button",
|
|
@@ -1195,9 +1694,9 @@ function AgentActivityPanel({ fetchActivity, renderMissionRef, title = "Agent ac
|
|
|
1195
1694
|
}
|
|
1196
1695
|
|
|
1197
1696
|
// src/web-react/seat-paywall.tsx
|
|
1198
|
-
import { jsx as
|
|
1199
|
-
function
|
|
1200
|
-
return /* @__PURE__ */
|
|
1697
|
+
import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
1698
|
+
function CheckGlyph3() {
|
|
1699
|
+
return /* @__PURE__ */ jsx8(
|
|
1201
1700
|
"svg",
|
|
1202
1701
|
{
|
|
1203
1702
|
className: "h-4 w-4 shrink-0 text-primary",
|
|
@@ -1208,14 +1707,14 @@ function CheckGlyph() {
|
|
|
1208
1707
|
strokeLinecap: "round",
|
|
1209
1708
|
strokeLinejoin: "round",
|
|
1210
1709
|
"aria-hidden": true,
|
|
1211
|
-
children: /* @__PURE__ */
|
|
1710
|
+
children: /* @__PURE__ */ jsx8("path", { d: "M20 6 9 17l-5-5" })
|
|
1212
1711
|
}
|
|
1213
1712
|
);
|
|
1214
1713
|
}
|
|
1215
1714
|
function Benefit({ children }) {
|
|
1216
|
-
return /* @__PURE__ */
|
|
1217
|
-
/* @__PURE__ */
|
|
1218
|
-
/* @__PURE__ */
|
|
1715
|
+
return /* @__PURE__ */ jsxs7("li", { className: "flex items-start gap-2.5 text-sm text-foreground", children: [
|
|
1716
|
+
/* @__PURE__ */ jsx8("span", { className: "mt-0.5", children: /* @__PURE__ */ jsx8(CheckGlyph3, {}) }),
|
|
1717
|
+
/* @__PURE__ */ jsx8("span", { children })
|
|
1219
1718
|
] });
|
|
1220
1719
|
}
|
|
1221
1720
|
function SeatPaywall({
|
|
@@ -1229,30 +1728,30 @@ function SeatPaywall({
|
|
|
1229
1728
|
footnote
|
|
1230
1729
|
}) {
|
|
1231
1730
|
const { pending, run } = usePending();
|
|
1232
|
-
return /* @__PURE__ */
|
|
1233
|
-
/* @__PURE__ */
|
|
1234
|
-
/* @__PURE__ */
|
|
1731
|
+
return /* @__PURE__ */ jsx8("div", { className: "flex min-h-[60vh] w-full items-center justify-center p-6", children: /* @__PURE__ */ jsxs7("div", { className: "w-full max-w-md rounded-2xl border border-border bg-card p-8 shadow-sm", children: [
|
|
1732
|
+
/* @__PURE__ */ jsx8("p", { className: "text-xs font-medium uppercase tracking-wide text-muted-foreground", children: product }),
|
|
1733
|
+
/* @__PURE__ */ jsxs7("h1", { className: "mt-2 text-2xl font-semibold tracking-tight text-foreground", children: [
|
|
1235
1734
|
"Unlock ",
|
|
1236
1735
|
product
|
|
1237
1736
|
] }),
|
|
1238
|
-
tagline && /* @__PURE__ */
|
|
1239
|
-
/* @__PURE__ */
|
|
1240
|
-
/* @__PURE__ */
|
|
1737
|
+
tagline && /* @__PURE__ */ jsx8("p", { className: "mt-2 text-sm text-muted-foreground", children: tagline }),
|
|
1738
|
+
/* @__PURE__ */ jsxs7("div", { className: "mt-6 flex items-baseline gap-1.5", children: [
|
|
1739
|
+
/* @__PURE__ */ jsxs7("span", { className: "text-3xl font-semibold text-foreground", children: [
|
|
1241
1740
|
"$",
|
|
1242
1741
|
priceUsd
|
|
1243
1742
|
] }),
|
|
1244
|
-
/* @__PURE__ */
|
|
1743
|
+
/* @__PURE__ */ jsx8("span", { className: "text-sm text-muted-foreground", children: "/mo" })
|
|
1245
1744
|
] }),
|
|
1246
|
-
/* @__PURE__ */
|
|
1745
|
+
/* @__PURE__ */ jsxs7("p", { className: "mt-1 text-sm text-muted-foreground", children: [
|
|
1247
1746
|
"Includes $",
|
|
1248
1747
|
includedUsageUsd,
|
|
1249
1748
|
"/mo of AI usage"
|
|
1250
1749
|
] }),
|
|
1251
|
-
/* @__PURE__ */
|
|
1750
|
+
/* @__PURE__ */ jsx8("ul", { className: "mt-6 space-y-2.5", children: (benefits ?? [
|
|
1252
1751
|
`Full access to ${product}`,
|
|
1253
1752
|
`$${includedUsageUsd}/mo of AI usage included, every month`
|
|
1254
|
-
]).map((benefit, i) => /* @__PURE__ */
|
|
1255
|
-
/* @__PURE__ */
|
|
1753
|
+
]).map((benefit, i) => /* @__PURE__ */ jsx8(Benefit, { children: benefit }, i)) }),
|
|
1754
|
+
/* @__PURE__ */ jsx8(
|
|
1256
1755
|
"button",
|
|
1257
1756
|
{
|
|
1258
1757
|
type: "button",
|
|
@@ -1262,13 +1761,13 @@ function SeatPaywall({
|
|
|
1262
1761
|
children: pending ? "Opening checkout\u2026" : ctaLabel ?? `Unlock ${product}`
|
|
1263
1762
|
}
|
|
1264
1763
|
),
|
|
1265
|
-
footnote && /* @__PURE__ */
|
|
1764
|
+
footnote && /* @__PURE__ */ jsx8("p", { className: "mt-3 text-center text-xs text-muted-foreground/70", children: footnote })
|
|
1266
1765
|
] }) });
|
|
1267
1766
|
}
|
|
1268
1767
|
|
|
1269
1768
|
// src/web-react/agent-session-controls.tsx
|
|
1270
|
-
import { useMemo as
|
|
1271
|
-
import { jsx as
|
|
1769
|
+
import { useMemo as useMemo5, useState as useState8 } from "react";
|
|
1770
|
+
import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1272
1771
|
var HARNESS_LABELS = {
|
|
1273
1772
|
opencode: "OpenCode (any model)",
|
|
1274
1773
|
"claude-code": "Claude Code (Anthropic)",
|
|
@@ -1288,12 +1787,12 @@ function harnessLabel(h) {
|
|
|
1288
1787
|
return HARNESS_LABELS[h] ?? h;
|
|
1289
1788
|
}
|
|
1290
1789
|
function ChevronDown2({ className }) {
|
|
1291
|
-
return /* @__PURE__ */
|
|
1790
|
+
return /* @__PURE__ */ jsx9("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: /* @__PURE__ */ jsx9("path", { d: "m6 9 6 6 6-6" }) });
|
|
1292
1791
|
}
|
|
1293
1792
|
function GearGlyph({ className }) {
|
|
1294
|
-
return /* @__PURE__ */
|
|
1295
|
-
/* @__PURE__ */
|
|
1296
|
-
/* @__PURE__ */
|
|
1793
|
+
return /* @__PURE__ */ jsxs8("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
|
|
1794
|
+
/* @__PURE__ */ jsx9("circle", { cx: "12", cy: "12", r: "3" }),
|
|
1795
|
+
/* @__PURE__ */ jsx9("path", { d: "M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1Z" })
|
|
1297
1796
|
] });
|
|
1298
1797
|
}
|
|
1299
1798
|
var FOCUS_RING = "focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background";
|
|
@@ -1302,11 +1801,11 @@ function HarnessPicker({
|
|
|
1302
1801
|
onChange,
|
|
1303
1802
|
available
|
|
1304
1803
|
}) {
|
|
1305
|
-
const [open, setOpen] =
|
|
1804
|
+
const [open, setOpen] = useState8(false);
|
|
1306
1805
|
const { containerRef, triggerProps } = usePopover(open, setOpen);
|
|
1307
1806
|
const options = available ?? Object.keys(HARNESS_LABELS);
|
|
1308
|
-
return /* @__PURE__ */
|
|
1309
|
-
/* @__PURE__ */
|
|
1807
|
+
return /* @__PURE__ */ jsxs8("div", { ref: containerRef, className: "relative inline-flex", children: [
|
|
1808
|
+
/* @__PURE__ */ jsxs8(
|
|
1310
1809
|
"button",
|
|
1311
1810
|
{
|
|
1312
1811
|
type: "button",
|
|
@@ -1315,12 +1814,12 @@ function HarnessPicker({
|
|
|
1315
1814
|
title: "Agent backend",
|
|
1316
1815
|
className: `inline-flex w-full items-center justify-between gap-1.5 rounded-lg border border-border bg-card px-3 py-1.5 text-sm font-medium text-foreground transition hover:bg-accent/30 ${FOCUS_RING}`,
|
|
1317
1816
|
children: [
|
|
1318
|
-
/* @__PURE__ */
|
|
1319
|
-
/* @__PURE__ */
|
|
1817
|
+
/* @__PURE__ */ jsx9("span", { className: "truncate", children: harnessLabel(value) }),
|
|
1818
|
+
/* @__PURE__ */ jsx9(ChevronDown2, { className: "h-3.5 w-3.5 text-muted-foreground" })
|
|
1320
1819
|
]
|
|
1321
1820
|
}
|
|
1322
1821
|
),
|
|
1323
|
-
open && /* @__PURE__ */
|
|
1822
|
+
open && /* @__PURE__ */ jsx9("div", { role: "menu", className: "absolute bottom-full left-0 z-50 mb-2 max-h-64 w-full min-w-[220px] overflow-y-auto rounded-xl border border-border bg-card p-1 shadow-lg", children: options.map((h) => /* @__PURE__ */ jsx9(
|
|
1324
1823
|
"button",
|
|
1325
1824
|
{
|
|
1326
1825
|
type: "button",
|
|
@@ -1339,7 +1838,7 @@ function HarnessPicker({
|
|
|
1339
1838
|
}
|
|
1340
1839
|
function useCoherentHandlers(props) {
|
|
1341
1840
|
const { model, models, harness, onModelChange, onHarnessChange } = props;
|
|
1342
|
-
const canonicalIds =
|
|
1841
|
+
const canonicalIds = useMemo5(() => models.map((m) => m.id), [models]);
|
|
1343
1842
|
const onModel = (next) => {
|
|
1344
1843
|
onModelChange(next);
|
|
1345
1844
|
const nextHarness = snapHarnessToModel(harness, next);
|
|
@@ -1367,11 +1866,11 @@ function AgentSessionControls(props) {
|
|
|
1367
1866
|
className
|
|
1368
1867
|
} = props;
|
|
1369
1868
|
const { onModel, onHarness } = useCoherentHandlers(props);
|
|
1370
|
-
const [open, setOpen] =
|
|
1869
|
+
const [open, setOpen] = useState8(false);
|
|
1371
1870
|
const { containerRef: popoverRef, triggerProps } = usePopover(open, setOpen);
|
|
1372
1871
|
const selectedModel = models.find((m) => m.id === model);
|
|
1373
1872
|
const showEffort = selectedModel?.supportsReasoning ?? true;
|
|
1374
|
-
const modelPicker = /* @__PURE__ */
|
|
1873
|
+
const modelPicker = /* @__PURE__ */ jsx9(
|
|
1375
1874
|
ModelPicker,
|
|
1376
1875
|
{
|
|
1377
1876
|
value: model,
|
|
@@ -1382,17 +1881,17 @@ function AgentSessionControls(props) {
|
|
|
1382
1881
|
}
|
|
1383
1882
|
);
|
|
1384
1883
|
if (layout === "inline") {
|
|
1385
|
-
return /* @__PURE__ */
|
|
1884
|
+
return /* @__PURE__ */ jsxs8("div", { className: `flex items-center gap-1.5 ${className ?? ""}`, children: [
|
|
1386
1885
|
modelPicker,
|
|
1387
|
-
showHarness && /* @__PURE__ */
|
|
1388
|
-
showEffort && /* @__PURE__ */
|
|
1886
|
+
showHarness && /* @__PURE__ */ jsx9(HarnessPicker, { value: harness, onChange: onHarness, available: availableHarnesses }),
|
|
1887
|
+
showEffort && /* @__PURE__ */ jsx9(EffortPicker, { value: effort, onChange: onEffortChange })
|
|
1389
1888
|
] });
|
|
1390
1889
|
}
|
|
1391
1890
|
const hasAdvanced = showHarness || showEffort;
|
|
1392
|
-
return /* @__PURE__ */
|
|
1891
|
+
return /* @__PURE__ */ jsxs8("div", { className: `flex items-center gap-1.5 ${className ?? ""}`, children: [
|
|
1393
1892
|
modelPicker,
|
|
1394
|
-
hasAdvanced && /* @__PURE__ */
|
|
1395
|
-
/* @__PURE__ */
|
|
1893
|
+
hasAdvanced && /* @__PURE__ */ jsxs8("div", { ref: popoverRef, className: "relative inline-flex", children: [
|
|
1894
|
+
/* @__PURE__ */ jsx9(
|
|
1396
1895
|
"button",
|
|
1397
1896
|
{
|
|
1398
1897
|
type: "button",
|
|
@@ -1401,19 +1900,19 @@ function AgentSessionControls(props) {
|
|
|
1401
1900
|
title: "Model settings \u2014 pick the agent backend and how hard it thinks",
|
|
1402
1901
|
className: `flex h-8 w-8 items-center justify-center rounded-full text-muted-foreground transition-colors hover:bg-muted hover:text-foreground data-[state=open]:bg-muted ${FOCUS_RING}`,
|
|
1403
1902
|
"data-state": open ? "open" : "closed",
|
|
1404
|
-
children: /* @__PURE__ */
|
|
1903
|
+
children: /* @__PURE__ */ jsx9(GearGlyph, { className: "h-4 w-4" })
|
|
1405
1904
|
}
|
|
1406
1905
|
),
|
|
1407
|
-
open && /* @__PURE__ */
|
|
1408
|
-
showHarness && /* @__PURE__ */
|
|
1409
|
-
/* @__PURE__ */
|
|
1410
|
-
/* @__PURE__ */
|
|
1411
|
-
/* @__PURE__ */
|
|
1906
|
+
open && /* @__PURE__ */ jsxs8("div", { className: "absolute bottom-full left-0 z-50 mb-2 w-72 space-y-3 rounded-xl border border-border bg-card p-3 shadow-lg", children: [
|
|
1907
|
+
showHarness && /* @__PURE__ */ jsxs8("div", { className: "space-y-1.5", children: [
|
|
1908
|
+
/* @__PURE__ */ jsx9("p", { className: "text-xs font-medium text-foreground", children: "Agent backend" }),
|
|
1909
|
+
/* @__PURE__ */ jsx9(HarnessPicker, { value: harness, onChange: onHarness, available: availableHarnesses }),
|
|
1910
|
+
/* @__PURE__ */ jsx9("p", { className: "text-[11px] leading-snug text-muted-foreground", children: "The engine that runs the agent. Switching it keeps your model choice compatible." })
|
|
1412
1911
|
] }),
|
|
1413
|
-
showEffort && /* @__PURE__ */
|
|
1414
|
-
/* @__PURE__ */
|
|
1415
|
-
/* @__PURE__ */
|
|
1416
|
-
/* @__PURE__ */
|
|
1912
|
+
showEffort && /* @__PURE__ */ jsxs8("div", { className: "space-y-1.5", children: [
|
|
1913
|
+
/* @__PURE__ */ jsx9("p", { className: "text-xs font-medium text-foreground", children: "Thinking" }),
|
|
1914
|
+
/* @__PURE__ */ jsx9(EffortPicker, { value: effort, onChange: onEffortChange, label: "" }),
|
|
1915
|
+
/* @__PURE__ */ jsx9("p", { className: "text-[11px] leading-snug text-muted-foreground", children: "How hard the agent thinks before answering. Higher is slower but more thorough." })
|
|
1417
1916
|
] })
|
|
1418
1917
|
] })
|
|
1419
1918
|
] })
|
|
@@ -1421,7 +1920,7 @@ function AgentSessionControls(props) {
|
|
|
1421
1920
|
}
|
|
1422
1921
|
|
|
1423
1922
|
// src/web-react/index.tsx
|
|
1424
|
-
import { Fragment as
|
|
1923
|
+
import { Fragment as Fragment5, jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
1425
1924
|
function formatModelCost(msg, models) {
|
|
1426
1925
|
if (msg.promptTokens == null && msg.completionTokens == null) return null;
|
|
1427
1926
|
const pricing = models.find((m) => m.id === msg.modelUsed)?.pricing;
|
|
@@ -1435,41 +1934,41 @@ function formatTokensPerSecond(msg) {
|
|
|
1435
1934
|
return `${Math.round(msg.completionTokens / (msg.durationMs / 1e3))} tok/s`;
|
|
1436
1935
|
}
|
|
1437
1936
|
function RunDrillIn({ run, onClose }) {
|
|
1438
|
-
return /* @__PURE__ */
|
|
1439
|
-
/* @__PURE__ */
|
|
1440
|
-
/* @__PURE__ */
|
|
1937
|
+
return /* @__PURE__ */ jsxs9("div", { className: "fixed inset-y-0 right-0 z-50 flex w-[480px] max-w-full flex-col border-l border-border bg-card shadow-xl", children: [
|
|
1938
|
+
/* @__PURE__ */ jsxs9("div", { className: "flex items-center gap-2 border-b border-border px-4 py-3", children: [
|
|
1939
|
+
/* @__PURE__ */ jsx10(
|
|
1441
1940
|
"span",
|
|
1442
1941
|
{
|
|
1443
1942
|
className: `h-2 w-2 shrink-0 rounded-full ${run.status === "running" ? "bg-warning" : run.status === "error" ? "bg-destructive" : "bg-success"}`
|
|
1444
1943
|
}
|
|
1445
1944
|
),
|
|
1446
|
-
/* @__PURE__ */
|
|
1447
|
-
/* @__PURE__ */
|
|
1448
|
-
/* @__PURE__ */
|
|
1945
|
+
/* @__PURE__ */ jsxs9("div", { className: "min-w-0 flex-1", children: [
|
|
1946
|
+
/* @__PURE__ */ jsx10("p", { className: "truncate text-sm font-semibold", children: run.title }),
|
|
1947
|
+
/* @__PURE__ */ jsx10("p", { className: "truncate font-mono text-[11px] text-muted-foreground", children: run.toolName })
|
|
1449
1948
|
] }),
|
|
1450
|
-
/* @__PURE__ */
|
|
1949
|
+
/* @__PURE__ */ jsx10(
|
|
1451
1950
|
"button",
|
|
1452
1951
|
{
|
|
1453
1952
|
type: "button",
|
|
1454
1953
|
onClick: onClose,
|
|
1455
1954
|
"aria-label": "Close",
|
|
1456
1955
|
className: "rounded-md p-1.5 text-muted-foreground transition hover:bg-accent/30 hover:text-foreground",
|
|
1457
|
-
children: /* @__PURE__ */
|
|
1956
|
+
children: /* @__PURE__ */ jsx10("svg", { className: "h-4 w-4", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", "aria-hidden": true, children: /* @__PURE__ */ jsx10("path", { d: "M18 6 6 18M6 6l12 12" }) })
|
|
1458
1957
|
}
|
|
1459
1958
|
)
|
|
1460
1959
|
] }),
|
|
1461
|
-
/* @__PURE__ */
|
|
1462
|
-
run.steps.length === 0 && /* @__PURE__ */
|
|
1463
|
-
run.steps.map((step, i) => /* @__PURE__ */
|
|
1464
|
-
/* @__PURE__ */
|
|
1465
|
-
/* @__PURE__ */
|
|
1466
|
-
/* @__PURE__ */
|
|
1467
|
-
/* @__PURE__ */
|
|
1960
|
+
/* @__PURE__ */ jsxs9("div", { className: "flex-1 space-y-3 overflow-y-auto p-4", children: [
|
|
1961
|
+
run.steps.length === 0 && /* @__PURE__ */ jsx10("p", { className: "text-sm text-muted-foreground", children: "No steps recorded yet." }),
|
|
1962
|
+
run.steps.map((step, i) => /* @__PURE__ */ jsxs9("div", { className: "rounded-lg border border-border/60 bg-background", children: [
|
|
1963
|
+
/* @__PURE__ */ jsxs9("div", { className: "flex items-baseline gap-2 border-b border-border/40 px-3 py-1.5", children: [
|
|
1964
|
+
/* @__PURE__ */ jsx10("span", { className: `font-mono text-[11px] ${step.status === "error" ? "text-destructive" : "text-muted-foreground"}`, children: step.status === "error" ? "\u2717" : "$" }),
|
|
1965
|
+
/* @__PURE__ */ jsx10("code", { className: "min-w-0 flex-1 truncate font-mono text-xs", children: step.label }),
|
|
1966
|
+
/* @__PURE__ */ jsx10("span", { className: "shrink-0 text-[10px] text-muted-foreground", children: new Date(step.at).toLocaleTimeString() })
|
|
1468
1967
|
] }),
|
|
1469
|
-
step.detail && /* @__PURE__ */
|
|
1968
|
+
step.detail && /* @__PURE__ */ jsx10("pre", { className: "max-h-48 overflow-auto whitespace-pre-wrap px-3 py-2 font-mono text-[11px] leading-relaxed text-muted-foreground", children: step.detail })
|
|
1470
1969
|
] }, i))
|
|
1471
1970
|
] }),
|
|
1472
|
-
/* @__PURE__ */
|
|
1971
|
+
/* @__PURE__ */ jsx10("p", { className: "border-t border-border px-4 py-2 text-[11px] text-muted-foreground", children: "Readonly drill-in. Follow up in the main chat." })
|
|
1473
1972
|
] });
|
|
1474
1973
|
}
|
|
1475
1974
|
function pendingApprovalOf(call) {
|
|
@@ -1483,20 +1982,20 @@ function ChatEmptyState({
|
|
|
1483
1982
|
subline = "Describe the outcome you want. The agent works through it step by step, and pauses for your approval before anything irreversible.",
|
|
1484
1983
|
doors
|
|
1485
1984
|
}) {
|
|
1486
|
-
return /* @__PURE__ */
|
|
1487
|
-
/* @__PURE__ */
|
|
1488
|
-
/* @__PURE__ */
|
|
1489
|
-
/* @__PURE__ */
|
|
1490
|
-
subline && /* @__PURE__ */
|
|
1491
|
-
doors && doors.length > 0 && /* @__PURE__ */
|
|
1985
|
+
return /* @__PURE__ */ jsxs9("div", { className: "mx-auto flex w-full max-w-2xl flex-col items-center px-6 py-12 text-center sm:py-20", children: [
|
|
1986
|
+
/* @__PURE__ */ jsx10("span", { className: "mb-5 inline-flex h-14 w-14 items-center justify-center rounded-2xl bg-primary/10 ring-1 ring-primary/15", children: /* @__PURE__ */ jsx10(BrandMark, { size: 32, className: "shrink-0" }) }),
|
|
1987
|
+
/* @__PURE__ */ jsx10("p", { className: "text-[11px] font-semibold uppercase tracking-[0.18em] text-muted-foreground", children: productName }),
|
|
1988
|
+
/* @__PURE__ */ jsx10("h2", { className: "mt-1.5 text-balance text-2xl font-semibold leading-tight text-foreground sm:text-[28px]", children: headline }),
|
|
1989
|
+
subline && /* @__PURE__ */ jsx10("p", { className: "mt-3 max-w-md text-[15px] leading-relaxed text-muted-foreground", children: subline }),
|
|
1990
|
+
doors && doors.length > 0 && /* @__PURE__ */ jsx10("div", { className: "mt-7 grid w-full gap-2.5 sm:grid-cols-3", children: doors.slice(0, 3).map((door, i) => /* @__PURE__ */ jsxs9(
|
|
1492
1991
|
"button",
|
|
1493
1992
|
{
|
|
1494
1993
|
type: "button",
|
|
1495
1994
|
onClick: door.onSelect,
|
|
1496
1995
|
className: "group flex min-h-[44px] flex-col items-start rounded-xl border border-border bg-card px-4 py-3 text-left transition hover:border-primary/40 hover:bg-accent/30 focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
|
|
1497
1996
|
children: [
|
|
1498
|
-
/* @__PURE__ */
|
|
1499
|
-
door.description && /* @__PURE__ */
|
|
1997
|
+
/* @__PURE__ */ jsx10("span", { className: "text-sm font-semibold text-foreground", children: door.label }),
|
|
1998
|
+
door.description && /* @__PURE__ */ jsx10("span", { className: "mt-0.5 text-[12px] leading-snug text-muted-foreground", children: door.description })
|
|
1500
1999
|
]
|
|
1501
2000
|
},
|
|
1502
2001
|
i
|
|
@@ -1505,26 +2004,26 @@ function ChatEmptyState({
|
|
|
1505
2004
|
}
|
|
1506
2005
|
function ToolGlyph({ name, className }) {
|
|
1507
2006
|
if (name.startsWith("sandbox_")) {
|
|
1508
|
-
return /* @__PURE__ */
|
|
1509
|
-
/* @__PURE__ */
|
|
1510
|
-
/* @__PURE__ */
|
|
2007
|
+
return /* @__PURE__ */ jsxs9("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
|
|
2008
|
+
/* @__PURE__ */ jsx10("polyline", { points: "4 17 10 11 4 5" }),
|
|
2009
|
+
/* @__PURE__ */ jsx10("line", { x1: "12", y1: "19", x2: "20", y2: "19" })
|
|
1511
2010
|
] });
|
|
1512
2011
|
}
|
|
1513
2012
|
if (name === "submit_proposal") {
|
|
1514
|
-
return /* @__PURE__ */
|
|
1515
|
-
/* @__PURE__ */
|
|
1516
|
-
/* @__PURE__ */
|
|
2013
|
+
return /* @__PURE__ */ jsxs9("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
|
|
2014
|
+
/* @__PURE__ */ jsx10("path", { d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" }),
|
|
2015
|
+
/* @__PURE__ */ jsx10("path", { d: "M14 2v6h6M9 15l2 2 4-4" })
|
|
1517
2016
|
] });
|
|
1518
2017
|
}
|
|
1519
2018
|
if (name === "schedule_followup") {
|
|
1520
|
-
return /* @__PURE__ */
|
|
1521
|
-
/* @__PURE__ */
|
|
1522
|
-
/* @__PURE__ */
|
|
2019
|
+
return /* @__PURE__ */ jsxs9("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", "aria-hidden": true, children: [
|
|
2020
|
+
/* @__PURE__ */ jsx10("circle", { cx: "12", cy: "12", r: "9" }),
|
|
2021
|
+
/* @__PURE__ */ jsx10("path", { d: "M12 7v5l3 3" })
|
|
1523
2022
|
] });
|
|
1524
2023
|
}
|
|
1525
|
-
return /* @__PURE__ */
|
|
1526
|
-
/* @__PURE__ */
|
|
1527
|
-
/* @__PURE__ */
|
|
2024
|
+
return /* @__PURE__ */ jsxs9("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
|
|
2025
|
+
/* @__PURE__ */ jsx10("path", { d: "M12 3v3m0 12v3M3 12h3m12 0h3" }),
|
|
2026
|
+
/* @__PURE__ */ jsx10("circle", { cx: "12", cy: "12", r: "4" })
|
|
1528
2027
|
] });
|
|
1529
2028
|
}
|
|
1530
2029
|
function toolOutcomeOf(call) {
|
|
@@ -1591,36 +2090,36 @@ function truncate(v, max = 240) {
|
|
|
1591
2090
|
function KvRows({ data }) {
|
|
1592
2091
|
const entries = Object.entries(data).filter(([, v]) => v !== void 0 && v !== null && v !== "");
|
|
1593
2092
|
if (!entries.length) return null;
|
|
1594
|
-
return /* @__PURE__ */
|
|
1595
|
-
/* @__PURE__ */
|
|
1596
|
-
/* @__PURE__ */
|
|
2093
|
+
return /* @__PURE__ */ jsx10("dl", { className: "grid grid-cols-[auto_1fr] gap-x-3 gap-y-1", children: entries.map(([k, v]) => /* @__PURE__ */ jsxs9("div", { className: "contents", children: [
|
|
2094
|
+
/* @__PURE__ */ jsx10("dt", { className: "font-mono text-[11px] text-muted-foreground", children: k }),
|
|
2095
|
+
/* @__PURE__ */ jsx10("dd", { className: "min-w-0 whitespace-pre-wrap break-words font-mono text-[11px] text-muted-foreground", children: truncate(v) })
|
|
1597
2096
|
] }, k)) });
|
|
1598
2097
|
}
|
|
1599
2098
|
function ShellDetail({ call }) {
|
|
1600
2099
|
const outcome = toolOutcomeOf(call);
|
|
1601
2100
|
const r = outcome?.result ?? {};
|
|
1602
|
-
return /* @__PURE__ */
|
|
1603
|
-
/* @__PURE__ */
|
|
1604
|
-
/* @__PURE__ */
|
|
1605
|
-
/* @__PURE__ */
|
|
1606
|
-
r.exitCode != null && /* @__PURE__ */
|
|
2101
|
+
return /* @__PURE__ */ jsxs9("div", { className: "overflow-hidden rounded-md bg-zinc-900 font-mono text-[11px] leading-relaxed", children: [
|
|
2102
|
+
/* @__PURE__ */ jsxs9("div", { className: "flex items-center gap-2 px-3 pt-2 text-zinc-400", children: [
|
|
2103
|
+
/* @__PURE__ */ jsx10("span", { className: "select-none text-zinc-500", children: "$" }),
|
|
2104
|
+
/* @__PURE__ */ jsx10("span", { className: "min-w-0 flex-1 truncate text-zinc-200", children: String(call.args?.command ?? "") }),
|
|
2105
|
+
r.exitCode != null && /* @__PURE__ */ jsxs9("span", { className: r.exitCode === 0 ? "text-success" : "text-destructive", children: [
|
|
1607
2106
|
"exit ",
|
|
1608
2107
|
r.exitCode
|
|
1609
2108
|
] })
|
|
1610
2109
|
] }),
|
|
1611
|
-
/* @__PURE__ */
|
|
2110
|
+
/* @__PURE__ */ jsx10("pre", { className: "max-h-56 overflow-auto whitespace-pre-wrap px-3 pb-2.5 pt-1.5 text-zinc-300", children: outcome?.ok === false ? outcome.message ?? "failed" : [r.stdout, r.stderr].filter(Boolean).join("\n") || "(no output)" })
|
|
1612
2111
|
] });
|
|
1613
2112
|
}
|
|
1614
2113
|
function DefaultToolDetail({ call }) {
|
|
1615
2114
|
const outcome = toolOutcomeOf(call);
|
|
1616
|
-
return /* @__PURE__ */
|
|
1617
|
-
call.args && Object.keys(call.args).length > 0 && /* @__PURE__ */
|
|
1618
|
-
/* @__PURE__ */
|
|
1619
|
-
/* @__PURE__ */
|
|
2115
|
+
return /* @__PURE__ */ jsxs9("div", { className: "space-y-2", children: [
|
|
2116
|
+
call.args && Object.keys(call.args).length > 0 && /* @__PURE__ */ jsxs9("div", { children: [
|
|
2117
|
+
/* @__PURE__ */ jsx10("p", { className: "mb-1 text-[10px] font-semibold uppercase tracking-wide text-muted-foreground", children: "Called with" }),
|
|
2118
|
+
/* @__PURE__ */ jsx10(KvRows, { data: call.args })
|
|
1620
2119
|
] }),
|
|
1621
|
-
outcome && /* @__PURE__ */
|
|
1622
|
-
/* @__PURE__ */
|
|
1623
|
-
outcome.ok === false ? /* @__PURE__ */
|
|
2120
|
+
outcome && /* @__PURE__ */ jsxs9("div", { children: [
|
|
2121
|
+
/* @__PURE__ */ jsx10("p", { className: "mb-1 text-[10px] font-semibold uppercase tracking-wide text-muted-foreground", children: outcome.ok === false ? "Failed" : "Result" }),
|
|
2122
|
+
outcome.ok === false ? /* @__PURE__ */ jsx10("p", { className: "text-xs text-destructive", children: outcome.message ?? "Tool failed" }) : outcome.result && typeof outcome.result === "object" ? /* @__PURE__ */ jsx10(KvRows, { data: outcome.result }) : /* @__PURE__ */ jsx10("p", { className: "font-mono text-[11px] text-muted-foreground", children: truncate(outcome.result) })
|
|
1624
2123
|
] })
|
|
1625
2124
|
] });
|
|
1626
2125
|
}
|
|
@@ -1631,23 +2130,23 @@ function ProposalCard({
|
|
|
1631
2130
|
approval,
|
|
1632
2131
|
renderers
|
|
1633
2132
|
}) {
|
|
1634
|
-
const [expanded, setExpanded] =
|
|
2133
|
+
const [expanded, setExpanded] = useState9(false);
|
|
1635
2134
|
const { summary, meta } = proposalPreview(call);
|
|
1636
2135
|
const custom = renderers?.[call.name]?.(call, message);
|
|
1637
2136
|
const { pending: deciding, run: decide } = usePending();
|
|
1638
|
-
return /* @__PURE__ */
|
|
1639
|
-
/* @__PURE__ */
|
|
1640
|
-
/* @__PURE__ */
|
|
1641
|
-
/* @__PURE__ */
|
|
1642
|
-
/* @__PURE__ */
|
|
1643
|
-
/* @__PURE__ */
|
|
1644
|
-
summary && /* @__PURE__ */
|
|
1645
|
-
meta.length > 0 && /* @__PURE__ */
|
|
2137
|
+
return /* @__PURE__ */ jsxs9("div", { className: "w-full max-w-full rounded-xl border border-warning/50 bg-warning/[0.06] text-sm shadow-sm ring-1 ring-warning/10", children: [
|
|
2138
|
+
/* @__PURE__ */ jsxs9("div", { className: "flex items-start gap-2.5 px-4 pt-3.5", children: [
|
|
2139
|
+
/* @__PURE__ */ jsx10("span", { className: "mt-0.5 inline-flex h-6 w-6 shrink-0 items-center justify-center rounded-full bg-warning/15 text-warning", children: /* @__PURE__ */ jsx10(ToolGlyph, { name: call.name, className: "h-3.5 w-3.5" }) }),
|
|
2140
|
+
/* @__PURE__ */ jsxs9("div", { className: "min-w-0 flex-1", children: [
|
|
2141
|
+
/* @__PURE__ */ jsx10("p", { className: "text-[10px] font-semibold uppercase tracking-wider text-warning-foreground", children: "Needs your approval" }),
|
|
2142
|
+
/* @__PURE__ */ jsx10("p", { className: "mt-0.5 text-[15px] font-semibold leading-snug text-foreground", children: friendlyToolTitle(call) }),
|
|
2143
|
+
summary && /* @__PURE__ */ jsx10("p", { className: "mt-1 text-[13px] leading-relaxed text-muted-foreground", children: summary }),
|
|
2144
|
+
meta.length > 0 && /* @__PURE__ */ jsx10("div", { className: "mt-1.5 flex flex-wrap items-center gap-1.5", children: meta.map((m, i) => /* @__PURE__ */ jsx10("span", { className: "rounded-full bg-muted/60 px-2 py-0.5 text-[11px] font-medium text-muted-foreground", children: m }, i)) })
|
|
1646
2145
|
] })
|
|
1647
2146
|
] }),
|
|
1648
|
-
/* @__PURE__ */
|
|
1649
|
-
approval ? /* @__PURE__ */
|
|
1650
|
-
/* @__PURE__ */
|
|
2147
|
+
/* @__PURE__ */ jsxs9("div", { className: "flex flex-wrap items-center gap-2 px-4 pb-3.5 pt-3", children: [
|
|
2148
|
+
approval ? /* @__PURE__ */ jsxs9(Fragment5, { children: [
|
|
2149
|
+
/* @__PURE__ */ jsx10(
|
|
1651
2150
|
"button",
|
|
1652
2151
|
{
|
|
1653
2152
|
type: "button",
|
|
@@ -1657,7 +2156,7 @@ function ProposalCard({
|
|
|
1657
2156
|
children: "Approve & run"
|
|
1658
2157
|
}
|
|
1659
2158
|
),
|
|
1660
|
-
/* @__PURE__ */
|
|
2159
|
+
/* @__PURE__ */ jsx10(
|
|
1661
2160
|
"button",
|
|
1662
2161
|
{
|
|
1663
2162
|
type: "button",
|
|
@@ -1667,8 +2166,8 @@ function ProposalCard({
|
|
|
1667
2166
|
children: "Reject"
|
|
1668
2167
|
}
|
|
1669
2168
|
)
|
|
1670
|
-
] }) : /* @__PURE__ */
|
|
1671
|
-
/* @__PURE__ */
|
|
2169
|
+
] }) : /* @__PURE__ */ jsx10("span", { className: "text-[12px] font-medium text-muted-foreground", children: "Awaiting approval\u2026" }),
|
|
2170
|
+
/* @__PURE__ */ jsxs9(
|
|
1672
2171
|
"button",
|
|
1673
2172
|
{
|
|
1674
2173
|
type: "button",
|
|
@@ -1677,23 +2176,23 @@ function ProposalCard({
|
|
|
1677
2176
|
className: "ml-auto inline-flex items-center gap-1 rounded text-[12px] font-medium text-muted-foreground transition hover:text-foreground focus:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
1678
2177
|
children: [
|
|
1679
2178
|
expanded ? "Hide details" : "View details",
|
|
1680
|
-
/* @__PURE__ */
|
|
2179
|
+
/* @__PURE__ */ jsx10(ChevronDown, { className: `h-3 w-3 transition-transform ${expanded ? "rotate-180" : ""}` })
|
|
1681
2180
|
]
|
|
1682
2181
|
}
|
|
1683
2182
|
)
|
|
1684
2183
|
] }),
|
|
1685
|
-
expanded && /* @__PURE__ */
|
|
2184
|
+
expanded && /* @__PURE__ */ jsx10("div", { className: "border-t border-warning/20 px-4 py-3 text-xs", children: custom ?? /* @__PURE__ */ jsx10(DefaultToolDetail, { call }) })
|
|
1686
2185
|
] });
|
|
1687
2186
|
}
|
|
1688
2187
|
function FollowupCard({ call }) {
|
|
1689
2188
|
const a = call.args ?? {};
|
|
1690
2189
|
const when = typeof a.when === "string" ? a.when : typeof a.at === "string" ? a.at : typeof a.schedule === "string" ? a.schedule : null;
|
|
1691
|
-
return /* @__PURE__ */
|
|
1692
|
-
/* @__PURE__ */
|
|
1693
|
-
/* @__PURE__ */
|
|
1694
|
-
/* @__PURE__ */
|
|
2190
|
+
return /* @__PURE__ */ jsxs9("div", { className: "w-fit min-w-[260px] max-w-full rounded-lg border border-border/60 border-l-2 border-l-primary/60 bg-muted/20 px-3 py-2 text-sm", children: [
|
|
2191
|
+
/* @__PURE__ */ jsxs9("div", { className: "flex items-center gap-2", children: [
|
|
2192
|
+
/* @__PURE__ */ jsx10(ToolGlyph, { name: call.name, className: "h-3.5 w-3.5 shrink-0 text-primary/80" }),
|
|
2193
|
+
/* @__PURE__ */ jsx10("span", { className: "min-w-0 flex-1 truncate font-medium text-foreground", children: friendlyToolTitle(call) })
|
|
1695
2194
|
] }),
|
|
1696
|
-
when && /* @__PURE__ */
|
|
2195
|
+
when && /* @__PURE__ */ jsx10("p", { className: "mt-0.5 pl-[22px] text-[12px] text-muted-foreground", children: when })
|
|
1697
2196
|
] });
|
|
1698
2197
|
}
|
|
1699
2198
|
function ToolCallCard({
|
|
@@ -1703,13 +2202,13 @@ function ToolCallCard({
|
|
|
1703
2202
|
onOpenRun,
|
|
1704
2203
|
renderers
|
|
1705
2204
|
}) {
|
|
1706
|
-
const [expanded, setExpanded] =
|
|
2205
|
+
const [expanded, setExpanded] = useState9(false);
|
|
1707
2206
|
const pending = call.status === "done" ? pendingApprovalOf(call) : null;
|
|
1708
2207
|
const kind = blockKindOf(call);
|
|
1709
2208
|
const failed = call.status === "error" || toolOutcomeOf(call)?.ok === false;
|
|
1710
2209
|
const custom = renderers?.[call.name]?.(call, message);
|
|
1711
2210
|
if (pending) {
|
|
1712
|
-
return /* @__PURE__ */
|
|
2211
|
+
return /* @__PURE__ */ jsx10(
|
|
1713
2212
|
ProposalCard,
|
|
1714
2213
|
{
|
|
1715
2214
|
call,
|
|
@@ -1721,16 +2220,16 @@ function ToolCallCard({
|
|
|
1721
2220
|
);
|
|
1722
2221
|
}
|
|
1723
2222
|
if (kind === "followup" && !failed) {
|
|
1724
|
-
return /* @__PURE__ */
|
|
2223
|
+
return /* @__PURE__ */ jsx10(FollowupCard, { call });
|
|
1725
2224
|
}
|
|
1726
2225
|
const isCommand = kind === "command";
|
|
1727
|
-
return /* @__PURE__ */
|
|
2226
|
+
return /* @__PURE__ */ jsxs9(
|
|
1728
2227
|
"div",
|
|
1729
2228
|
{
|
|
1730
2229
|
className: `w-fit min-w-[280px] max-w-full rounded-lg border text-xs transition ${failed ? "border-destructive/40 bg-destructive/5" : "border-border/60 bg-muted/20"}`,
|
|
1731
2230
|
children: [
|
|
1732
|
-
/* @__PURE__ */
|
|
1733
|
-
/* @__PURE__ */
|
|
2231
|
+
/* @__PURE__ */ jsxs9("div", { className: "flex w-full items-center gap-2 px-3 py-2", children: [
|
|
2232
|
+
/* @__PURE__ */ jsxs9(
|
|
1734
2233
|
"button",
|
|
1735
2234
|
{
|
|
1736
2235
|
type: "button",
|
|
@@ -1738,14 +2237,14 @@ function ToolCallCard({
|
|
|
1738
2237
|
"aria-expanded": expanded,
|
|
1739
2238
|
className: "flex min-w-0 flex-1 items-center gap-2 rounded text-left focus:outline-none focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
1740
2239
|
children: [
|
|
1741
|
-
/* @__PURE__ */
|
|
2240
|
+
/* @__PURE__ */ jsx10(
|
|
1742
2241
|
"span",
|
|
1743
2242
|
{
|
|
1744
2243
|
className: `h-2 w-2 shrink-0 rounded-full ${call.status === "running" ? "animate-pulse bg-warning" : failed ? "bg-destructive" : "bg-success"}`
|
|
1745
2244
|
}
|
|
1746
2245
|
),
|
|
1747
|
-
/* @__PURE__ */
|
|
1748
|
-
/* @__PURE__ */
|
|
2246
|
+
/* @__PURE__ */ jsx10(ToolGlyph, { name: call.name, className: "h-3.5 w-3.5 shrink-0 text-muted-foreground" }),
|
|
2247
|
+
/* @__PURE__ */ jsx10(
|
|
1749
2248
|
"span",
|
|
1750
2249
|
{
|
|
1751
2250
|
className: `min-w-0 flex-1 truncate ${isCommand ? "font-mono text-[12px] tracking-tight text-foreground/90" : "font-medium"}`,
|
|
@@ -1755,8 +2254,8 @@ function ToolCallCard({
|
|
|
1755
2254
|
]
|
|
1756
2255
|
}
|
|
1757
2256
|
),
|
|
1758
|
-
/* @__PURE__ */
|
|
1759
|
-
/* @__PURE__ */
|
|
2257
|
+
/* @__PURE__ */ jsx10("span", { className: "shrink-0 text-[11px] text-muted-foreground", children: call.status === "running" ? "running\u2026" : failed ? "failed" : "done" }),
|
|
2258
|
+
/* @__PURE__ */ jsx10(
|
|
1760
2259
|
"button",
|
|
1761
2260
|
{
|
|
1762
2261
|
type: "button",
|
|
@@ -1764,13 +2263,13 @@ function ToolCallCard({
|
|
|
1764
2263
|
"aria-label": expanded ? "Collapse details" : "Expand details",
|
|
1765
2264
|
"aria-expanded": expanded,
|
|
1766
2265
|
className: "shrink-0 rounded p-0.5 focus:outline-none focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
1767
|
-
children: /* @__PURE__ */
|
|
2266
|
+
children: /* @__PURE__ */ jsx10(ChevronDown, { className: `h-3 w-3 text-muted-foreground transition-transform ${expanded ? "rotate-180" : ""}` })
|
|
1768
2267
|
}
|
|
1769
2268
|
)
|
|
1770
2269
|
] }),
|
|
1771
|
-
expanded && /* @__PURE__ */
|
|
1772
|
-
custom ?? (call.name === "sandbox_run_command" ? /* @__PURE__ */
|
|
1773
|
-
onOpenRun && call.name.startsWith("sandbox_") && /* @__PURE__ */
|
|
2270
|
+
expanded && /* @__PURE__ */ jsxs9("div", { className: "border-t border-border/40 px-3 py-2.5", children: [
|
|
2271
|
+
custom ?? (call.name === "sandbox_run_command" ? /* @__PURE__ */ jsx10(ShellDetail, { call }) : /* @__PURE__ */ jsx10(DefaultToolDetail, { call })),
|
|
2272
|
+
onOpenRun && call.name.startsWith("sandbox_") && /* @__PURE__ */ jsx10(
|
|
1774
2273
|
"button",
|
|
1775
2274
|
{
|
|
1776
2275
|
type: "button",
|
|
@@ -1785,7 +2284,7 @@ function ToolCallCard({
|
|
|
1785
2284
|
);
|
|
1786
2285
|
}
|
|
1787
2286
|
function StreamingCaret() {
|
|
1788
|
-
return /* @__PURE__ */
|
|
2287
|
+
return /* @__PURE__ */ jsx10(
|
|
1789
2288
|
"span",
|
|
1790
2289
|
{
|
|
1791
2290
|
className: "ml-0.5 inline-block h-[1.1em] w-[3px] translate-y-[2px] animate-pulse rounded-sm bg-foreground/70",
|
|
@@ -1800,11 +2299,11 @@ function SegmentText({
|
|
|
1800
2299
|
renderBody
|
|
1801
2300
|
}) {
|
|
1802
2301
|
const text = useSmoothText(content, streaming);
|
|
1803
|
-
const body =
|
|
2302
|
+
const body = useMemo6(() => renderBody(text), [renderBody, text]);
|
|
1804
2303
|
if (!content.trim() && !showCaret) return null;
|
|
1805
|
-
return /* @__PURE__ */
|
|
2304
|
+
return /* @__PURE__ */ jsxs9("div", { className: "text-base leading-[1.75]", children: [
|
|
1806
2305
|
body,
|
|
1807
|
-
showCaret && /* @__PURE__ */
|
|
2306
|
+
showCaret && /* @__PURE__ */ jsx10(StreamingCaret, {})
|
|
1808
2307
|
] });
|
|
1809
2308
|
}
|
|
1810
2309
|
var COLLAPSE_TOOL_RUN_AT = 3;
|
|
@@ -1827,7 +2326,7 @@ function SegmentedBody({
|
|
|
1827
2326
|
const leftoverToolCalls = (msg.toolCalls ?? []).filter(
|
|
1828
2327
|
(tc) => !segmentToolIds.has(tc.id)
|
|
1829
2328
|
);
|
|
1830
|
-
const renderToolCard = (call) => /* @__PURE__ */
|
|
2329
|
+
const renderToolCard = (call) => /* @__PURE__ */ jsx10(
|
|
1831
2330
|
ToolCallCard,
|
|
1832
2331
|
{
|
|
1833
2332
|
call,
|
|
@@ -1850,9 +2349,9 @@ function SegmentedBody({
|
|
|
1850
2349
|
else groups.push({ kind: "tools", index: i, calls: [seg.call] });
|
|
1851
2350
|
}
|
|
1852
2351
|
}
|
|
1853
|
-
return /* @__PURE__ */
|
|
2352
|
+
return /* @__PURE__ */ jsxs9("div", { className: "flex flex-col gap-2", children: [
|
|
1854
2353
|
groups.map(
|
|
1855
|
-
(g) => g.kind === "text" ? /* @__PURE__ */
|
|
2354
|
+
(g) => g.kind === "text" ? /* @__PURE__ */ jsx10(
|
|
1856
2355
|
SegmentText,
|
|
1857
2356
|
{
|
|
1858
2357
|
content: g.content,
|
|
@@ -1861,24 +2360,24 @@ function SegmentedBody({
|
|
|
1861
2360
|
renderBody
|
|
1862
2361
|
},
|
|
1863
2362
|
`text-${g.index}`
|
|
1864
|
-
) : !streaming && g.calls.length >= COLLAPSE_TOOL_RUN_AT && !g.calls.some(isImportantTool) ? /* @__PURE__ */
|
|
2363
|
+
) : !streaming && g.calls.length >= COLLAPSE_TOOL_RUN_AT && !g.calls.some(isImportantTool) ? /* @__PURE__ */ jsxs9(
|
|
1865
2364
|
"details",
|
|
1866
2365
|
{
|
|
1867
2366
|
className: "rounded-lg border-l-2 border-border/70 bg-muted/20 px-3 py-2",
|
|
1868
2367
|
children: [
|
|
1869
|
-
/* @__PURE__ */
|
|
2368
|
+
/* @__PURE__ */ jsxs9("summary", { className: "cursor-pointer select-none text-xs font-medium text-muted-foreground", children: [
|
|
1870
2369
|
"Worked through ",
|
|
1871
2370
|
g.calls.length,
|
|
1872
2371
|
" steps"
|
|
1873
2372
|
] }),
|
|
1874
|
-
/* @__PURE__ */
|
|
2373
|
+
/* @__PURE__ */ jsx10("div", { className: "mt-2 flex flex-col gap-2", children: g.calls.map(renderToolCard) })
|
|
1875
2374
|
]
|
|
1876
2375
|
},
|
|
1877
2376
|
`tools-${g.index}`
|
|
1878
|
-
) : /* @__PURE__ */
|
|
2377
|
+
) : /* @__PURE__ */ jsx10("div", { className: "flex flex-col gap-2", children: g.calls.map(renderToolCard) }, `tools-${g.index}`)
|
|
1879
2378
|
),
|
|
1880
2379
|
leftoverToolCalls.map(renderToolCard),
|
|
1881
|
-
streaming && segments[lastIndex]?.kind === "tool" && /* @__PURE__ */
|
|
2380
|
+
streaming && segments[lastIndex]?.kind === "tool" && /* @__PURE__ */ jsx10(StreamingCaret, {})
|
|
1882
2381
|
] });
|
|
1883
2382
|
}
|
|
1884
2383
|
function AssistantMessageImpl({
|
|
@@ -1894,12 +2393,12 @@ function AssistantMessageImpl({
|
|
|
1894
2393
|
}) {
|
|
1895
2394
|
const content = useSmoothText(msg.content, streaming);
|
|
1896
2395
|
const reasoning = useSmoothText(msg.reasoning ?? "", streaming);
|
|
1897
|
-
const body =
|
|
2396
|
+
const body = useMemo6(() => renderBody(content), [renderBody, content]);
|
|
1898
2397
|
const segments = msg.segments;
|
|
1899
2398
|
const hasAnswerText = content !== "" || (segments?.some((s) => s.kind === "text" && s.content.trim() !== "") ?? false);
|
|
1900
|
-
const reasoningScrollRef =
|
|
1901
|
-
const thinkStartRef =
|
|
1902
|
-
const thinkMsRef =
|
|
2399
|
+
const reasoningScrollRef = useRef6(null);
|
|
2400
|
+
const thinkStartRef = useRef6(null);
|
|
2401
|
+
const thinkMsRef = useRef6(null);
|
|
1903
2402
|
if (streaming && reasoning && !hasAnswerText && thinkStartRef.current === null) {
|
|
1904
2403
|
thinkStartRef.current = performance.now();
|
|
1905
2404
|
}
|
|
@@ -1913,21 +2412,21 @@ function AssistantMessageImpl({
|
|
|
1913
2412
|
const thinkingSeconds = useThinkingSeconds(
|
|
1914
2413
|
streaming && !!reasoning && !hasAnswerText
|
|
1915
2414
|
);
|
|
1916
|
-
return /* @__PURE__ */
|
|
1917
|
-
/* @__PURE__ */
|
|
1918
|
-
/* @__PURE__ */
|
|
1919
|
-
msg.modelUsed && /* @__PURE__ */
|
|
1920
|
-
formatTokensPerSecond(msg) && /* @__PURE__ */
|
|
1921
|
-
formatModelCost(msg, models) && /* @__PURE__ */
|
|
2415
|
+
return /* @__PURE__ */ jsxs9("div", { className: "mx-auto w-full max-w-3xl px-6 py-3", children: [
|
|
2416
|
+
/* @__PURE__ */ jsxs9("div", { className: "mb-1 flex items-baseline gap-2 text-[11px] tracking-wide text-muted-foreground", children: [
|
|
2417
|
+
/* @__PURE__ */ jsx10("span", { className: "font-semibold uppercase", children: agentLabel }),
|
|
2418
|
+
msg.modelUsed && /* @__PURE__ */ jsx10("span", { className: "font-mono normal-case", children: msg.modelUsed }),
|
|
2419
|
+
formatTokensPerSecond(msg) && /* @__PURE__ */ jsx10("span", { children: formatTokensPerSecond(msg) }),
|
|
2420
|
+
formatModelCost(msg, models) && /* @__PURE__ */ jsx10("span", { children: formatModelCost(msg, models) })
|
|
1922
2421
|
] }),
|
|
1923
|
-
reasoning && /* @__PURE__ */
|
|
1924
|
-
/* @__PURE__ */
|
|
2422
|
+
reasoning && /* @__PURE__ */ jsxs9("details", { className: "mb-2 rounded-lg border-l-2 border-border/70 bg-muted/20 px-3 py-2", open: !hasAnswerText, children: [
|
|
2423
|
+
/* @__PURE__ */ jsx10("summary", { className: "cursor-pointer select-none text-xs font-medium text-muted-foreground", children: !hasAnswerText ? /* @__PURE__ */ jsxs9("span", { className: "animate-pulse", children: [
|
|
1925
2424
|
"Thinking",
|
|
1926
2425
|
thinkingSeconds >= 3 ? ` \xB7 ${thinkingSeconds}s` : "\u2026"
|
|
1927
2426
|
] }) : thinkMsRef.current != null ? `Thought for ${Math.max(1, Math.round(thinkMsRef.current / 1e3))}s` : "Thought process" }),
|
|
1928
|
-
/* @__PURE__ */
|
|
2427
|
+
/* @__PURE__ */ jsx10("div", { ref: reasoningScrollRef, className: "mt-2 max-h-48 overflow-y-auto whitespace-pre-wrap text-[13px] leading-relaxed text-muted-foreground", children: reasoning })
|
|
1929
2428
|
] }),
|
|
1930
|
-
segments && segments.length > 0 ? /* @__PURE__ */
|
|
2429
|
+
segments && segments.length > 0 ? /* @__PURE__ */ jsx10(
|
|
1931
2430
|
SegmentedBody,
|
|
1932
2431
|
{
|
|
1933
2432
|
segments,
|
|
@@ -1938,12 +2437,12 @@ function AssistantMessageImpl({
|
|
|
1938
2437
|
onToolCallClick,
|
|
1939
2438
|
toolRenderers
|
|
1940
2439
|
}
|
|
1941
|
-
) : /* @__PURE__ */
|
|
1942
|
-
/* @__PURE__ */
|
|
2440
|
+
) : /* @__PURE__ */ jsxs9(Fragment5, { children: [
|
|
2441
|
+
/* @__PURE__ */ jsxs9("div", { className: "text-base leading-[1.75]", children: [
|
|
1943
2442
|
body,
|
|
1944
|
-
streaming && content && !msg.toolCalls?.length && /* @__PURE__ */
|
|
2443
|
+
streaming && content && !msg.toolCalls?.length && /* @__PURE__ */ jsx10(StreamingCaret, {})
|
|
1945
2444
|
] }),
|
|
1946
|
-
msg.toolCalls && msg.toolCalls.length > 0 && /* @__PURE__ */
|
|
2445
|
+
msg.toolCalls && msg.toolCalls.length > 0 && /* @__PURE__ */ jsx10("div", { className: "mt-2 flex flex-col gap-1.5", children: msg.toolCalls.map((tc) => /* @__PURE__ */ jsx10(
|
|
1947
2446
|
ToolCallCard,
|
|
1948
2447
|
{
|
|
1949
2448
|
call: tc,
|
|
@@ -1960,7 +2459,7 @@ function AssistantMessageImpl({
|
|
|
1960
2459
|
}
|
|
1961
2460
|
var AssistantMessage = memo(AssistantMessageImpl);
|
|
1962
2461
|
function useThinkingSeconds(active) {
|
|
1963
|
-
const [seconds, setSeconds] =
|
|
2462
|
+
const [seconds, setSeconds] = useState9(0);
|
|
1964
2463
|
useEffect5(() => {
|
|
1965
2464
|
if (!active) return;
|
|
1966
2465
|
setSeconds(0);
|
|
@@ -1971,23 +2470,23 @@ function useThinkingSeconds(active) {
|
|
|
1971
2470
|
}
|
|
1972
2471
|
function ThinkingRow({ agentLabel }) {
|
|
1973
2472
|
const seconds = useThinkingSeconds(true);
|
|
1974
|
-
return /* @__PURE__ */
|
|
1975
|
-
/* @__PURE__ */
|
|
1976
|
-
/* @__PURE__ */
|
|
1977
|
-
/* @__PURE__ */
|
|
2473
|
+
return /* @__PURE__ */ jsxs9("div", { className: "mx-auto w-full max-w-3xl px-6 py-3", children: [
|
|
2474
|
+
/* @__PURE__ */ jsx10("p", { className: "mb-1 text-[11px] font-semibold uppercase tracking-wide text-muted-foreground", children: agentLabel }),
|
|
2475
|
+
/* @__PURE__ */ jsxs9("div", { className: "flex items-center gap-2 text-base text-muted-foreground", children: [
|
|
2476
|
+
/* @__PURE__ */ jsx10("svg", { className: "h-4 w-4 animate-spin", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", "aria-hidden": true, children: /* @__PURE__ */ jsx10("path", { d: "M21 12a9 9 0 1 1-6.219-8.56", strokeLinecap: "round" }) }),
|
|
1978
2477
|
"Thinking",
|
|
1979
2478
|
seconds >= 3 ? ` \xB7 ${seconds}s` : "..."
|
|
1980
2479
|
] })
|
|
1981
2480
|
] });
|
|
1982
2481
|
}
|
|
1983
2482
|
function StreamErrorRow({ message, onRetry }) {
|
|
1984
|
-
return /* @__PURE__ */
|
|
1985
|
-
/* @__PURE__ */
|
|
1986
|
-
/* @__PURE__ */
|
|
1987
|
-
/* @__PURE__ */
|
|
2483
|
+
return /* @__PURE__ */ jsx10("div", { className: "mx-auto w-full max-w-3xl px-6 py-3", children: /* @__PURE__ */ jsxs9("div", { role: "alert", className: "flex items-start gap-2.5 rounded-lg border border-destructive/40 bg-destructive/5 px-3 py-2.5 text-sm text-destructive", children: [
|
|
2484
|
+
/* @__PURE__ */ jsxs9("svg", { className: "mt-0.5 h-4 w-4 shrink-0", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
|
|
2485
|
+
/* @__PURE__ */ jsx10("circle", { cx: "12", cy: "12", r: "9" }),
|
|
2486
|
+
/* @__PURE__ */ jsx10("path", { d: "M12 8v4m0 4h.01" })
|
|
1988
2487
|
] }),
|
|
1989
|
-
/* @__PURE__ */
|
|
1990
|
-
onRetry && /* @__PURE__ */
|
|
2488
|
+
/* @__PURE__ */ jsx10("span", { className: "min-w-0 flex-1 break-words", children: message }),
|
|
2489
|
+
onRetry && /* @__PURE__ */ jsx10(
|
|
1991
2490
|
"button",
|
|
1992
2491
|
{
|
|
1993
2492
|
type: "button",
|
|
@@ -2015,25 +2514,25 @@ function ChatMessages({
|
|
|
2015
2514
|
emptyState,
|
|
2016
2515
|
header
|
|
2017
2516
|
}) {
|
|
2018
|
-
const renderBody =
|
|
2019
|
-
() => renderMarkdown ?? ((content) => /* @__PURE__ */
|
|
2517
|
+
const renderBody = useMemo6(
|
|
2518
|
+
() => renderMarkdown ?? ((content) => /* @__PURE__ */ jsx10("p", { className: "whitespace-pre-wrap", children: content })),
|
|
2020
2519
|
[renderMarkdown]
|
|
2021
2520
|
);
|
|
2022
2521
|
const lastIsUser = messages[messages.length - 1]?.role === "user";
|
|
2023
2522
|
if (messages.length === 0 && !loading && !error) {
|
|
2024
|
-
const empty = renderEmpty ? renderEmpty() : /* @__PURE__ */
|
|
2025
|
-
return /* @__PURE__ */
|
|
2523
|
+
const empty = renderEmpty ? renderEmpty() : /* @__PURE__ */ jsx10(ChatEmptyState, { ...emptyState });
|
|
2524
|
+
return /* @__PURE__ */ jsxs9(Fragment5, { children: [
|
|
2026
2525
|
header,
|
|
2027
2526
|
empty
|
|
2028
2527
|
] });
|
|
2029
2528
|
}
|
|
2030
|
-
return /* @__PURE__ */
|
|
2529
|
+
return /* @__PURE__ */ jsxs9(Fragment5, { children: [
|
|
2031
2530
|
header,
|
|
2032
2531
|
messages.map(
|
|
2033
|
-
(msg) => msg.role === "user" ? /* @__PURE__ */
|
|
2034
|
-
/* @__PURE__ */
|
|
2035
|
-
/* @__PURE__ */
|
|
2036
|
-
] }) }, msg.id) : /* @__PURE__ */
|
|
2532
|
+
(msg) => msg.role === "user" ? /* @__PURE__ */ jsx10("div", { className: "mx-auto w-full max-w-3xl px-6 py-3", children: /* @__PURE__ */ jsxs9("div", { className: "ml-auto w-fit max-w-[85%]", children: [
|
|
2533
|
+
/* @__PURE__ */ jsx10("p", { className: "mb-1 text-right text-[11px] font-semibold uppercase tracking-wide text-muted-foreground", children: userLabel }),
|
|
2534
|
+
/* @__PURE__ */ jsx10("div", { className: "rounded-2xl rounded-tr-md bg-primary/10 px-4 py-2.5 text-base leading-relaxed", children: /* @__PURE__ */ jsx10("p", { className: "whitespace-pre-wrap", children: msg.content }) })
|
|
2535
|
+
] }) }, msg.id) : /* @__PURE__ */ jsx10(
|
|
2037
2536
|
AssistantMessage,
|
|
2038
2537
|
{
|
|
2039
2538
|
msg,
|
|
@@ -2049,8 +2548,8 @@ function ChatMessages({
|
|
|
2049
2548
|
msg.id
|
|
2050
2549
|
)
|
|
2051
2550
|
),
|
|
2052
|
-
loading && lastIsUser && /* @__PURE__ */
|
|
2053
|
-
error && !loading && /* @__PURE__ */
|
|
2551
|
+
loading && lastIsUser && /* @__PURE__ */ jsx10(ThinkingRow, { agentLabel }),
|
|
2552
|
+
error && !loading && /* @__PURE__ */ jsx10(StreamErrorRow, { message: error, onRetry })
|
|
2054
2553
|
] });
|
|
2055
2554
|
}
|
|
2056
2555
|
|
|
@@ -2063,31 +2562,32 @@ export {
|
|
|
2063
2562
|
ModelPicker,
|
|
2064
2563
|
DEFAULT_EFFORT_LEVELS,
|
|
2065
2564
|
EffortPicker,
|
|
2066
|
-
INTERACTION_EVENT,
|
|
2067
|
-
INTERACTION_CANCEL_EVENT,
|
|
2068
|
-
INTERACTION_RESOLVED_EVENT,
|
|
2069
|
-
isRenderableInteractionKind,
|
|
2070
|
-
isSafeInteractionFieldKey,
|
|
2071
|
-
isTerminalInteractionStatus,
|
|
2072
|
-
canTransitionInteractionStatus,
|
|
2073
|
-
cancelStatusFor,
|
|
2074
|
-
questionInteractionContentSignature,
|
|
2075
|
-
dedupeQuestionInteractionsByContent,
|
|
2076
|
-
parseInteractionRequest,
|
|
2077
|
-
parseInteractionCancel,
|
|
2078
|
-
fieldAcceptsFreeText,
|
|
2079
|
-
composerAnswerDeliveries,
|
|
2080
|
-
composerAnswerData,
|
|
2081
|
-
interactionPartKey,
|
|
2082
|
-
noticePartKey,
|
|
2083
|
-
noticePart,
|
|
2084
|
-
interactionFromWireRequest,
|
|
2085
|
-
interactionToPersistedPart,
|
|
2086
|
-
persistedPartToInteraction,
|
|
2087
2565
|
dispatchChatStreamLine,
|
|
2088
2566
|
consumeChatStream,
|
|
2089
2567
|
streamChatTurn,
|
|
2090
2568
|
ChatComposer,
|
|
2569
|
+
interactionStatusLabels,
|
|
2570
|
+
interactionTerminalNotes,
|
|
2571
|
+
fieldAnswer,
|
|
2572
|
+
buildAnswerData,
|
|
2573
|
+
isLateAnswerableStatus,
|
|
2574
|
+
hasSecretField,
|
|
2575
|
+
lateAnswerMessage,
|
|
2576
|
+
INTERACTION_SUBMIT_TIMEOUT_MS,
|
|
2577
|
+
INTERACTION_SUBMIT_TIMEOUT_MESSAGE,
|
|
2578
|
+
responseErrorMessage,
|
|
2579
|
+
createInteractionAnswerSubmitter,
|
|
2580
|
+
InteractionBadge,
|
|
2581
|
+
InteractionActionButton,
|
|
2582
|
+
QuestionOptionList,
|
|
2583
|
+
InteractionQuestionCard,
|
|
2584
|
+
InteractionPlanCard,
|
|
2585
|
+
upsertChatInteraction,
|
|
2586
|
+
cancelChatInteraction,
|
|
2587
|
+
resolveChatInteraction,
|
|
2588
|
+
terminalizePendingChatInteractions,
|
|
2589
|
+
restoreChatInteractions,
|
|
2590
|
+
useChatInteractions,
|
|
2091
2591
|
activityTone,
|
|
2092
2592
|
formatActivityCost,
|
|
2093
2593
|
formatActivityDuration,
|
|
@@ -2106,4 +2606,4 @@ export {
|
|
|
2106
2606
|
useThinkingSeconds,
|
|
2107
2607
|
ChatMessages
|
|
2108
2608
|
};
|
|
2109
|
-
//# sourceMappingURL=chunk-
|
|
2609
|
+
//# sourceMappingURL=chunk-FCQP75JT.js.map
|