pikiloom 0.4.59 → 0.4.60
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/dashboard/dist/assets/{AgentTab-0iSS-Bby.js → AgentTab-KSanVg_l.js} +1 -1
- package/dashboard/dist/assets/{ConnectionModal-DRg8X2s1.js → ConnectionModal-BSoA2mZL.js} +1 -1
- package/dashboard/dist/assets/{DirBrowser-Br3AnAYT.js → DirBrowser-zKX7wmty.js} +1 -1
- package/dashboard/dist/assets/{ExtensionsTab-CHO2uMeN.js → ExtensionsTab-DKLjCr4u.js} +1 -1
- package/dashboard/dist/assets/{IMAccessTab-7v8e2UqN.js → IMAccessTab-BhvB7Hes.js} +1 -1
- package/dashboard/dist/assets/{Modal-bvNc9zVs.js → Modal-Qwlap_Fl.js} +1 -1
- package/dashboard/dist/assets/{Modals-CXBXc4Xx.js → Modals-2Zw2FSLo.js} +1 -1
- package/dashboard/dist/assets/{Select-D-rJwrhF.js → Select-dIxoi_TN.js} +1 -1
- package/dashboard/dist/assets/SessionPanel--D5NGYgd.js +1 -0
- package/dashboard/dist/assets/{SystemTab-NTIGkssg.js → SystemTab-CtjiZa5s.js} +1 -1
- package/dashboard/dist/assets/{index-h42cuqnj.js → index-BDSh0L9U.js} +3 -3
- package/dashboard/dist/assets/{index-CPmFmj6P.js → index-DN0a6ZnO.js} +16 -16
- package/dashboard/dist/assets/{shared-CUTx2Dth.js → shared-D2sGZJ9f.js} +1 -1
- package/dashboard/dist/index.html +1 -1
- package/dist/agent/drivers/claude.js +28 -1
- package/dist/agent/turn-snapshot.js +141 -0
- package/dist/bot/bot.js +11 -0
- package/package.json +1 -1
- package/dashboard/dist/assets/SessionPanel-CoIrjkQt.js +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
import{j as s}from"./react-vendor-C7Sl8SE7.js";import{O as t,m as i,S as a}from"./index-
|
|
1
|
+
import{j as s}from"./react-vendor-C7Sl8SE7.js";import{O as t,m as i,S as a}from"./index-BDSh0L9U.js";function o({primary:e,secondary:l,tertiary:n}){return s.jsxs("div",{className:"flex flex-col gap-2 pt-1 sm:flex-row sm:flex-wrap sm:items-center sm:justify-between",children:[s.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e&&s.jsxs(i,{tone:"primary",onClick:e.onClick,disabled:e.disabled,children:[e.loading&&s.jsx(a,{}),e.label]}),l&&s.jsx(i,{tone:"secondary",onClick:l.onClick,disabled:l.disabled,children:l.label})]}),n&&s.jsx("div",{className:"text-xs leading-relaxed text-fg-4",children:n})]})}function c({children:e,className:l}){return s.jsx(t,{padding:"md",elevation:"flat",className:l,children:e})}export{o as A,c as S};
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
<link rel="icon" type="image/png" href="/logo.png">
|
|
7
7
|
<title>Pikiloom</title>
|
|
8
8
|
<link href="https://fonts.googleapis.com/css2?family=Geist:wght@400;500;600;700&family=Geist+Mono:wght@400;500&display=swap" rel="stylesheet">
|
|
9
|
-
<script type="module" crossorigin src="/assets/index-
|
|
9
|
+
<script type="module" crossorigin src="/assets/index-BDSh0L9U.js"></script>
|
|
10
10
|
<link rel="modulepreload" crossorigin href="/assets/react-vendor-C7Sl8SE7.js">
|
|
11
11
|
<link rel="modulepreload" crossorigin href="/assets/router-DHISdpPk.js">
|
|
12
12
|
<link rel="stylesheet" crossorigin href="/assets/index-BO-FYAny.css">
|
|
@@ -7,6 +7,7 @@ import { Q, run, agentError, agentLog, agentWarn, buildStreamPreviewMeta, comput
|
|
|
7
7
|
import { AGENT_STREAM_HARD_KILL_GRACE_MS, AGENT_GRACEFUL_ABORT_GRACE_MS, SESSION_RUNNING_THRESHOLD_MS } from '../../core/constants.js';
|
|
8
8
|
import { terminateProcessTree } from '../../core/process-control.js';
|
|
9
9
|
import { getHome, IS_MAC, encodePathAsDirName } from '../../core/platform.js';
|
|
10
|
+
import { loadDeliveredTurns, buildRecoveryQueue, normalizeSnapshotPrompt } from '../turn-snapshot.js';
|
|
10
11
|
function buildClaudeUserMessage(prompt, attachments) {
|
|
11
12
|
const content = [];
|
|
12
13
|
for (const filePath of attachments) {
|
|
@@ -1516,6 +1517,9 @@ function isClaudeSyntheticResumeNoise(text) {
|
|
|
1516
1517
|
return t === 'no response requested.' || t === 'no response requested';
|
|
1517
1518
|
}
|
|
1518
1519
|
const CLAUDE_INCOMPLETE_TURN_NOTICE = '⚠️ This reply ended before a closing message was delivered (interrupted, or the model returned an empty final response).';
|
|
1520
|
+
// Shown under a reply we restored from pikiloom's delivery snapshot because the agent transcript
|
|
1521
|
+
// lost it (see turn-snapshot.ts). The content above is what was actually streamed to the user.
|
|
1522
|
+
const CLAUDE_RECOVERED_TURN_NOTICE = 'ℹ️ Restored by pikiloom from the delivered reply — the agent’s own transcript dropped this turn.';
|
|
1519
1523
|
function getClaudeSessionMessages(opts) {
|
|
1520
1524
|
const projectDir = path.join(getHome(), '.claude', 'projects', claudeProjectDirName(opts.workdir));
|
|
1521
1525
|
const filePath = path.join(projectDir, `${opts.sessionId}.jsonl`);
|
|
@@ -1527,6 +1531,13 @@ function getClaudeSessionMessages(opts) {
|
|
|
1527
1531
|
const lines = content.split('\n').filter(l => l.trim());
|
|
1528
1532
|
const allMsgs = [];
|
|
1529
1533
|
const richMsgs = [];
|
|
1534
|
+
// Delivered-reply snapshots keyed by prompt, consumed at tombstones to restore swallowed turns.
|
|
1535
|
+
const recoveryQueue = buildRecoveryQueue(loadDeliveredTurns(opts.sessionId));
|
|
1536
|
+
let lastUserPromptNorm = '';
|
|
1537
|
+
const takeRecoveredTurn = (promptNorm) => {
|
|
1538
|
+
const list = promptNorm ? recoveryQueue.get(promptNorm) : undefined;
|
|
1539
|
+
return list && list.length ? list.shift() : null;
|
|
1540
|
+
};
|
|
1530
1541
|
let pendingRole = null;
|
|
1531
1542
|
let pendingTextParts = [];
|
|
1532
1543
|
let pendingBlocks = [];
|
|
@@ -1699,6 +1710,8 @@ function getClaudeSessionMessages(opts) {
|
|
|
1699
1710
|
pendingRole = 'user';
|
|
1700
1711
|
pendingTextParts = text ? [text] : [];
|
|
1701
1712
|
pendingBlocks = text ? [{ type: 'text', content: text }, ...imageBlocks] : [...imageBlocks];
|
|
1713
|
+
if (text)
|
|
1714
|
+
lastUserPromptNorm = normalizeSnapshotPrompt(text);
|
|
1702
1715
|
}
|
|
1703
1716
|
}
|
|
1704
1717
|
else if (ev.type === 'assistant') {
|
|
@@ -1715,7 +1728,21 @@ function getClaudeSessionMessages(opts) {
|
|
|
1715
1728
|
if (pendingRole === 'user')
|
|
1716
1729
|
flush();
|
|
1717
1730
|
pendingRole = 'assistant';
|
|
1718
|
-
|
|
1731
|
+
// If this tombstone is the whole assistant turn (nothing landed in the jsonl) and we
|
|
1732
|
+
// hold a delivered-reply snapshot for the preceding prompt, restore the real reply
|
|
1733
|
+
// instead of the "ended before a closing message" notice. When partial content did
|
|
1734
|
+
// land (pending blocks already present) we leave it — partial + notice is truthful.
|
|
1735
|
+
const turnEmpty = pendingBlocks.length === 0 && pendingTextParts.length === 0;
|
|
1736
|
+
const recovered = (displayText === CLAUDE_INCOMPLETE_TURN_NOTICE && turnEmpty)
|
|
1737
|
+
? takeRecoveredTurn(lastUserPromptNorm) : null;
|
|
1738
|
+
if (recovered) {
|
|
1739
|
+
pendingTextParts.push(recovered);
|
|
1740
|
+
pendingBlocks.push({ type: 'text', content: recovered });
|
|
1741
|
+
pendingBlocks.push({ type: 'system_notice', content: CLAUDE_RECOVERED_TURN_NOTICE });
|
|
1742
|
+
}
|
|
1743
|
+
else {
|
|
1744
|
+
pendingBlocks.push({ type: 'system_notice', content: displayText });
|
|
1745
|
+
}
|
|
1719
1746
|
continue;
|
|
1720
1747
|
}
|
|
1721
1748
|
if (pendingRole === 'user')
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { getUserConfigPath } from '../core/config/user-config.js';
|
|
4
|
+
// Durable per-turn snapshot of the content pikiloom actually delivered.
|
|
5
|
+
//
|
|
6
|
+
// The agent CLIs are the source of truth for transcript history, but their session jsonl is
|
|
7
|
+
// lossy under two upstream conditions we cannot prevent: (1) a turn's closing reply dies before
|
|
8
|
+
// the CLI flushes it to disk (kill/flush race), and (2) the CLI's resume rewrites the jsonl in
|
|
9
|
+
// place and drops a turn that never got a synthetic-free conclusion. In both cases pikiloom has
|
|
10
|
+
// already streamed the complete reply to the user (turn-audit confirms ok/end_turn), yet a later
|
|
11
|
+
// history render reads only a "No response requested." tombstone — the swallow.
|
|
12
|
+
//
|
|
13
|
+
// This sidecar is the missing durable copy: one JSON line per delivered turn, keyed by the user
|
|
14
|
+
// prompt, so the claude history renderer can restore the real reply at a tombstone instead of
|
|
15
|
+
// showing a bare "ended before a closing message" notice. It complements turn-audit.jsonl (which
|
|
16
|
+
// records how a turn ended, not what it said). See [[posttool-empty-result-no-response-requested]].
|
|
17
|
+
const MAX_SNAPSHOT_BYTES = 512 * 1024; // per-session cap, single-slot rotation
|
|
18
|
+
const MAX_TEXT_CHARS = 40_000; // don't archive megabyte replies verbatim
|
|
19
|
+
const STALE_MS = 30 * 24 * 60 * 60 * 1000;
|
|
20
|
+
// Match the raw prompt pikiloom ran against the user text reconstructed from the jsonl. Both
|
|
21
|
+
// sides normalize identically: collapse whitespace, trim, cap length. Case is preserved (matching
|
|
22
|
+
// is mostly CJK / mixed-script prose).
|
|
23
|
+
export function normalizeSnapshotPrompt(s) {
|
|
24
|
+
return (s || '').replace(/\s+/g, ' ').trim().slice(0, 240);
|
|
25
|
+
}
|
|
26
|
+
function snapshotDir() {
|
|
27
|
+
return path.join(path.dirname(getUserConfigPath()), 'turn-snapshots');
|
|
28
|
+
}
|
|
29
|
+
function sessionSnapshotPath(sessionId) {
|
|
30
|
+
// sessionId is a uuid / codex rollout id — safe as a filename, but strip separators defensively.
|
|
31
|
+
const safe = sessionId.replace(/[^A-Za-z0-9_-]/g, '_');
|
|
32
|
+
return path.join(snapshotDir(), `${safe}.jsonl`);
|
|
33
|
+
}
|
|
34
|
+
// A finished turn whose delivered message is only a placeholder or an appended incomplete-notice
|
|
35
|
+
// carries nothing worth restoring. Strip a trailing "⚠️ …" note (composeKernelFinalPresentation
|
|
36
|
+
// and the legacy driver append one to real prose) and drop the empty/placeholder shapes.
|
|
37
|
+
function bodyWorthSaving(message) {
|
|
38
|
+
let text = (message || '').replace(/\n\n⚠️[^\n]*$/u, '').trim();
|
|
39
|
+
if (!text)
|
|
40
|
+
return null;
|
|
41
|
+
if (text === '(no textual response)' || text === '(no output)')
|
|
42
|
+
return null;
|
|
43
|
+
if (text.length > MAX_TEXT_CHARS)
|
|
44
|
+
text = text.slice(0, MAX_TEXT_CHARS);
|
|
45
|
+
return text;
|
|
46
|
+
}
|
|
47
|
+
let cleanedThisProcess = false;
|
|
48
|
+
function cleanupStaleSnapshots() {
|
|
49
|
+
if (cleanedThisProcess)
|
|
50
|
+
return;
|
|
51
|
+
cleanedThisProcess = true;
|
|
52
|
+
try {
|
|
53
|
+
const dir = snapshotDir();
|
|
54
|
+
const now = Date.now();
|
|
55
|
+
for (const name of fs.readdirSync(dir)) {
|
|
56
|
+
const p = path.join(dir, name);
|
|
57
|
+
try {
|
|
58
|
+
if (now - fs.statSync(p).mtimeMs > STALE_MS)
|
|
59
|
+
fs.unlinkSync(p);
|
|
60
|
+
}
|
|
61
|
+
catch { /* skip */ }
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
catch { /* no dir yet */ }
|
|
65
|
+
}
|
|
66
|
+
export function recordDeliveredTurn(entry) {
|
|
67
|
+
try {
|
|
68
|
+
if (!entry.sessionId)
|
|
69
|
+
return;
|
|
70
|
+
const text = bodyWorthSaving(entry.message);
|
|
71
|
+
if (!text)
|
|
72
|
+
return;
|
|
73
|
+
const prompt = (entry.prompt || '').slice(0, 500);
|
|
74
|
+
const dir = snapshotDir();
|
|
75
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
76
|
+
cleanupStaleSnapshots();
|
|
77
|
+
const file = sessionSnapshotPath(entry.sessionId);
|
|
78
|
+
try {
|
|
79
|
+
if (fs.statSync(file).size > MAX_SNAPSHOT_BYTES)
|
|
80
|
+
fs.renameSync(file, `${file}.1`);
|
|
81
|
+
}
|
|
82
|
+
catch { /* no file yet */ }
|
|
83
|
+
const line = JSON.stringify({
|
|
84
|
+
ts: new Date().toISOString(),
|
|
85
|
+
prompt,
|
|
86
|
+
promptNorm: normalizeSnapshotPrompt(prompt),
|
|
87
|
+
text,
|
|
88
|
+
model: entry.model ?? null,
|
|
89
|
+
ok: entry.ok,
|
|
90
|
+
stopReason: entry.stopReason ?? null,
|
|
91
|
+
});
|
|
92
|
+
fs.appendFileSync(file, line + '\n');
|
|
93
|
+
}
|
|
94
|
+
catch { /* snapshotting is best-effort by design */ }
|
|
95
|
+
}
|
|
96
|
+
// Ordered list (append order == turn order) of delivered turns for a session, for render merge.
|
|
97
|
+
export function loadDeliveredTurns(sessionId) {
|
|
98
|
+
if (!sessionId)
|
|
99
|
+
return [];
|
|
100
|
+
try {
|
|
101
|
+
const content = fs.readFileSync(sessionSnapshotPath(sessionId), 'utf-8');
|
|
102
|
+
const out = [];
|
|
103
|
+
for (const raw of content.split('\n')) {
|
|
104
|
+
if (!raw.trim() || raw[0] !== '{')
|
|
105
|
+
continue;
|
|
106
|
+
try {
|
|
107
|
+
const ev = JSON.parse(raw);
|
|
108
|
+
if (typeof ev.text !== 'string' || !ev.text)
|
|
109
|
+
continue;
|
|
110
|
+
out.push({
|
|
111
|
+
prompt: typeof ev.prompt === 'string' ? ev.prompt : '',
|
|
112
|
+
promptNorm: typeof ev.promptNorm === 'string' ? ev.promptNorm : normalizeSnapshotPrompt(ev.prompt || ''),
|
|
113
|
+
text: ev.text,
|
|
114
|
+
model: typeof ev.model === 'string' ? ev.model : null,
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
catch { /* skip bad line */ }
|
|
118
|
+
}
|
|
119
|
+
return out;
|
|
120
|
+
}
|
|
121
|
+
catch {
|
|
122
|
+
return [];
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
// A per-prompt FIFO of delivered replies. A tombstone consumes the next reply recorded for its
|
|
126
|
+
// preceding prompt. Front-pop is exact for the common case (a unique recent prompt was swallowed);
|
|
127
|
+
// for a prompt repeated across turns with mixed outcomes the match is by order and may attach a
|
|
128
|
+
// sibling occurrence's reply — still strictly better than a bare tombstone.
|
|
129
|
+
export function buildRecoveryQueue(turns) {
|
|
130
|
+
const q = new Map();
|
|
131
|
+
for (const t of turns) {
|
|
132
|
+
if (!t.promptNorm)
|
|
133
|
+
continue;
|
|
134
|
+
const list = q.get(t.promptNorm);
|
|
135
|
+
if (list)
|
|
136
|
+
list.push(t.text);
|
|
137
|
+
else
|
|
138
|
+
q.set(t.promptNorm, [t.text]);
|
|
139
|
+
}
|
|
140
|
+
return q;
|
|
141
|
+
}
|
package/dist/bot/bot.js
CHANGED
|
@@ -11,6 +11,7 @@ import { resolveGuiIntegrationConfig } from '../agent/mcp/bridge.js';
|
|
|
11
11
|
import { composeSessionToolPrompt } from '../agent/mcp/capabilities.js';
|
|
12
12
|
import { terminateProcessTree } from '../core/process-control.js';
|
|
13
13
|
import { appendTurnAudit } from '../core/turn-audit.js';
|
|
14
|
+
import { recordDeliveredTurn } from '../agent/turn-snapshot.js';
|
|
14
15
|
import { expandTilde } from '../core/platform.js';
|
|
15
16
|
import { VERSION } from '../core/version.js';
|
|
16
17
|
import { buildHumanLoopResponse, createEmptyHumanLoopAnswer, currentHumanLoopQuestion, isHumanLoopAwaitingText, setHumanLoopOption, setHumanLoopText, skipHumanLoopQuestion, summarizeResolvedHumanLoopAnswers, } from './human-loop.js';
|
|
@@ -2132,6 +2133,16 @@ export class Bot {
|
|
|
2132
2133
|
error: result.error ? String(result.error).slice(0, 500) : null,
|
|
2133
2134
|
elapsedS: result.elapsedS, model: result.model ?? resolvedModel, promptPreview: prompt.slice(0, 120),
|
|
2134
2135
|
});
|
|
2136
|
+
// Durable copy of what we just delivered, so the history render can restore it if the CLI's
|
|
2137
|
+
// jsonl later loses this turn to a flush race or an in-place resume rewrite (the swallow).
|
|
2138
|
+
// claude-only: it is the driver whose renderer knows how to merge these at a tombstone.
|
|
2139
|
+
if (cs.agent === 'claude') {
|
|
2140
|
+
recordDeliveredTurn({
|
|
2141
|
+
sessionId: result.sessionId || cs.sessionId || null,
|
|
2142
|
+
prompt, message: result.message, model: result.model ?? resolvedModel ?? null,
|
|
2143
|
+
ok: result.ok, stopReason: result.stopReason ?? null,
|
|
2144
|
+
});
|
|
2145
|
+
}
|
|
2135
2146
|
if (cs.agent === 'claude' && workflowEnabled && result.thinkingEffort) {
|
|
2136
2147
|
result.thinkingEffort = 'ultra';
|
|
2137
2148
|
}
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{r as n,j as s}from"./react-vendor-C7Sl8SE7.js";import{c as on,I as un,S as ze,m as We,a as T,u as ht,d as cn,g as dn,l as fn,e as mn,j as gn,f as pn,s as hn,Y as xn}from"./index-h42cuqnj.js";import{s as kn,l as Sn,n as Et,m as bn,a as vn,o as In,d as Tn,b as yn,p as Rn,h as Mt,c as Qe,e as jn,f as wn,g as Ct,i as $e,j as Ke,k as Nn,q as An,T as Ln,R as On,U as Ut,r as Pn,t as qt,L as Dt,u as En,I as Mn}from"./index-CPmFmj6P.js";import{M as Ft,a as Bt}from"./Modal-bvNc9zVs.js";import"./router-DHISdpPk.js";import"./Select-D-rJwrhF.js";import"./DirBrowser-Br3AnAYT.js";import"./markdown-DxQYQFeH.js";import"./ExtensionsTab-CHO2uMeN.js";function Cn({snapshot:a}){const[t,f]=n.useState(a.currentIndex??0),[N,y]=n.useState(""),[x,h]=n.useState(!1),[C,S]=n.useState(null);n.useEffect(()=>{f(a.currentIndex??0),y(""),S(null)},[a.promptId,a.currentIndex]);const O=a.questions||[],R=O[t]||null,Z=O.length,U=!!(R?.options&&R.options.length),P=U?!!R?.allowFreeform:!0,de=c=>{c&&(f(i=>i+1),y(""))},fe=async c=>{if(!x){h(!0),S(null);try{const i=await T.interactionSelectOption(a.promptId,c);if(!i.ok){S(i.error||"Failed to submit selection.");return}de(i.advanced)}catch(i){S(i?.message||"Network error.")}finally{h(!1)}}},me=async()=>{if(x)return;const c=N.trim();if(!c&&!R?.allowEmpty){S("Please enter a response.");return}h(!0),S(null);try{const i=await T.interactionSubmitText(a.promptId,c);if(!i.ok){S(i.error||"Failed to submit answer.");return}de(i.advanced)}catch(i){S(i?.message||"Network error.")}finally{h(!1)}},m=async()=>{if(!x){h(!0),S(null);try{const c=await T.interactionSkip(a.promptId);if(!c.ok){S(c.error||"Failed to skip.");return}de(c.advanced)}catch(c){S(c?.message||"Network error.")}finally{h(!1)}}},ee=async()=>{if(!x){h(!0);try{await T.interactionCancel(a.promptId)}catch{}}},te=n.useMemo(()=>{const c=[];return a.hint&&c.push(a.hint),Z>1&&c.push(`Question ${t+1} of ${Z}`),c.join(" · ")||void 0},[a.hint,t,Z]);return s.jsxs(Ft,{open:!0,onClose:ee,wide:U&&(R?.options?.length||0)>3,children:[s.jsx(Bt,{title:a.title||"Pikiloom needs your input",description:te,onClose:ee}),R?s.jsxs("div",{className:"space-y-4",children:[s.jsxs("div",{children:[s.jsx("div",{className:"text-xs font-medium uppercase tracking-wide text-fg-5",children:R.header||"Question"}),s.jsx("div",{className:"mt-1 whitespace-pre-wrap text-sm leading-relaxed text-fg",children:R.prompt})]}),U&&s.jsx("div",{className:"grid grid-cols-1 gap-2 sm:grid-cols-2",children:(R.options||[]).map(c=>s.jsxs("button",{type:"button",disabled:x,onClick:()=>fe(c.value||c.label),className:on("group rounded-lg border border-edge bg-panel-alt px-3 py-2 text-left text-sm transition","hover:border-control-border-h hover:bg-control-h hover:shadow-sm","focus:outline-none focus:ring-2 focus:ring-[var(--th-glow-a)]","disabled:cursor-not-allowed disabled:opacity-50"),children:[s.jsx("div",{className:"font-medium text-fg group-hover:text-fg",children:c.label}),c.description&&s.jsx("div",{className:"mt-0.5 text-xs leading-snug text-fg-4",children:c.description})]},c.value||c.label))}),P&&s.jsx("div",{children:s.jsx(un,{value:N,onChange:c=>y(c.target.value),onKeyDown:c=>{c.key==="Enter"&&!c.shiftKey&&!x&&(c.preventDefault(),me())},placeholder:U?"Or type a custom answer…":"Type your answer…",disabled:x,autoFocus:!U})}),C&&s.jsx("div",{className:"rounded-md border border-red-300/40 bg-red-500/10 px-3 py-2 text-xs text-red-600",children:C}),s.jsxs("div",{className:"flex items-center justify-between gap-3",children:[s.jsx("div",{className:"text-xs text-fg-5",children:x?s.jsxs("span",{className:"inline-flex items-center gap-2",children:[s.jsx(ze,{})," Submitting…"]}):s.jsxs("span",{children:["Press ",s.jsx("kbd",{className:"rounded border border-edge bg-panel-alt px-1.5 py-0.5 text-[10px] uppercase",children:"Enter"})," to send"]})}),s.jsxs("div",{className:"flex items-center gap-2",children:[s.jsx(We,{variant:"ghost",size:"sm",onClick:m,disabled:x,children:"Skip"}),P&&s.jsx(We,{variant:"primary",size:"sm",onClick:me,disabled:x||!N.trim()&&!R.allowEmpty,children:"Submit"})]})]})]}):s.jsxs("div",{className:"py-6 text-center text-sm text-fg-5",children:[s.jsx(ze,{className:"mr-2 inline-block"})," Waiting for the agent…"]})]})}function Un(a){return a.isNull?(a.localStreamPending||a.holdsActiveState)&&!a.holdExpired?"reject-null":"apply":(typeof a.updatedAt=="number"?a.updatedAt:0)<a.lastAppliedUpdatedAt?"reject-stale":"apply"}function qn(a,t){return typeof t!="number"?a:t>a?t:a}function Dn(a,t){return!a||!a.length?[]:t.size?a.filter(f=>!t.has(f)):a.slice()}function Hn(a,t,f,N){if(!a.size)return a;const y=new Set(t);let x=!1;const h=new Map;for(const[C,S]of a){if(f-S>N||!y.has(C)){x=!0;continue}h.set(C,S)}return x?h:a}const xt=12,Ht=160,Fn=96,Bn=[],_n=[],Qn=[],$n={phase:"streaming",text:"",thinking:""},Kn=20,zn=6e4,Wn=15e3,Yn=7e3,ie=new Map;function Gn(a,t){return`${a}:${t}`}function Vn(a,t){for(ie.delete(a),ie.set(a,t);ie.size>Kn;)ie.delete(ie.keys().next().value)}const or=n.memo(function({session:t,workdir:f,active:N=!0,onSessionChange:y,initialPendingPrompt:x,initialPendingImageUrls:h,onPendingPromptConsumed:C}){const S=ht(e=>e.locale),O=ht(e=>e.agentStatus?.agents?.find(r=>r.agent===t.agent)??null),R=O?.selectedEffort??null,Z=O?.selectedModel??null,U=ht(e=>e.modelLayer),P=t.profileId?U?.profiles.find(e=>e.id===t.profileId)??null:null,de=P?U?.providers.find(e=>e.id===P.providerId)??null:null,fe=t.profileId===void 0?O?.byokProviderName??null:de?.name??null,me=t.profileId===void 0?O?.byokProfileName??null:P&&P.name.trim().toLowerCase()!==P.modelId.trim().toLowerCase()?P.name:null,m=n.useMemo(()=>cn(S),[S]),ee=dn(t.agent||""),te=fn(t),c=!!x||!!(h&&h.length),[i,Ye]=n.useState(null),[Ge,ge]=n.useState(!c),[pe,kt]=n.useState(!1),[o,B]=n.useState(null),[_,he]=n.useState(!1),[q,Ve]=n.useState(null),[_t,St]=n.useState(0),[Qt,Xe]=n.useState(null),[D,Re]=n.useState([]),[$t,je]=n.useState([]),[xe,Je]=n.useState([]),[g,ne]=n.useState(x||null),[E,re]=n.useState(h||[]),[Kt,se]=n.useState(null),Q=n.useRef(null);Q.current=Kt;const bt=n.useRef(g);bt.current=g;const[we,H]=n.useState([]),Ne=n.useRef([]);Ne.current=we;const ke=n.useRef(null),[zt,vt]=n.useState(null),[Ae,Se]=n.useState(null),[be,Ze]=n.useState(""),[$,et]=n.useState(!1),Wt=!!O?.capabilities?.fork,tt=n.useRef(null),L=n.useRef(h||[]),K=n.useRef(o),nt=n.useRef(_);K.current=o,nt.current=_;const rt=n.useRef(D);rt.current=D;const It=n.useRef(q);It.current=q;const z=n.useRef(null),Le=n.useRef(null),W=n.useRef(!0),le=n.useRef(!1),Oe=n.useRef(null),st=n.useRef(!1),M=n.useRef(c),ae=n.useRef(!1),Y=n.useRef(!1),lt=n.useRef(!1),at=n.useRef(!1),G=n.useRef(null),Pe=n.useRef(0),ve=n.useRef(Date.now()),Ie=n.useRef(new Map),Tt=n.useRef({model:null,effort:null}),Yt=n.useCallback(e=>{Tt.current=e},[]);n.useEffect(()=>{lt.current||!c||(lt.current=!0,x&&!g&&ne(x),h&&h.length&&!E.length&&(re(h),L.current=h),ge(!1),St(e=>e+1),C?.())},[c,C]);const A=n.useCallback(()=>{ne(null),re(e=>{for(const r of e)URL.revokeObjectURL(r);return[]}),L.current=[],se(null)},[]),V=n.useCallback(()=>{H(e=>{if(!e.length)return e;for(const r of e)for(const l of r.imageUrls)URL.revokeObjectURL(l);return[]}),ke.current=null},[]),yt=n.useCallback((e,r)=>{ve.current=Date.now();const l=kn({streaming:nt.current,liveStreamPhase:K.current?.phase??null,streamPhase:It.current,queuedTaskCount:rt.current.length,pendingQueuedCount:Ne.current.length}),u=r||[];if(l){const d=`local-${Date.now().toString(36)}-${Math.random().toString(36).slice(2,8)}`;ke.current=d,H(k=>[...k,{localId:d,taskId:null,prompt:e||"",imageUrls:u}]);return}K.current?.phase==="done"&&B(null);for(const d of L.current)URL.revokeObjectURL(d);ke.current=null,ne(e||null),re(u),L.current=u,se(null)},[]),Gt=n.useCallback(e=>{const r=ke.current;if(r){ke.current=null,H(l=>{const u=l.findIndex(k=>k.localId===r);if(u<0)return l;const d=l.slice();return d[u]={...d[u],taskId:e},d});return}se(e)},[]),Vt=n.useCallback(async()=>{if(!Ae)return;const e=be.trim();if(e){et(!0);try{const r=await T.forkSession(f,t.agent||"",t.sessionId,Ae.atTurn,e,{});if(!r.ok||!r.sessionKey){et(!1);return}const[l,u]=r.sessionKey.split(":");Se(null),Ze(""),y?.({agent:l,sessionId:u,workdir:f})}finally{et(!1)}}},[Ae,be,f,t.agent,t.sessionId,y]);tt.current=Vt;const Ee=n.useCallback(async(e,r={})=>{try{const l=await Sn({workdir:f,agent:t.agent||"",sessionId:t.sessionId,rich:!0,turnOffset:e.turnOffset,turnLimit:e.turnLimit,lastNTurns:e.lastNTurns},{force:r.force});return l.ok?Et(l):null}catch{return null}},[f,t.agent,t.sessionId]),j=n.useCallback(async({keepOlder:e,force:r=!1,scrollToBottom:l=!1})=>{const u=t.sessionId;if(Oe.current===u)return!1;Oe.current=u;try{const d=await Ee({turnOffset:0,turnLimit:xt},{force:r});if(!d||t.sessionId!==u)return!1;if(l&&(le.current=!0),Ye(k=>!k||!e?d:bn(k,d)),ge(!1),ae.current&&(ae.current=!1,A()),Y.current){const k=Y.current;Y.current=!1;const X=k!==!0?k.taskId:null;K.current&&(k===!0||K.current.taskId===X)&&B(null)}return!0}finally{Oe.current===u&&(Oe.current=null)}},[Ee,A,t.sessionId]),Me=n.useCallback(async()=>{if(!i?.hasOlder||st.current)return;const e=z.current;e&&(Le.current={scrollHeight:e.scrollHeight,scrollTop:e.scrollTop}),st.current=!0,kt(!0);try{const r=await Ee({turnOffset:Math.max(0,i.totalTurns-i.startTurn),turnLimit:xt});r?Ye(l=>l?vn(l,r):r):Le.current=null}finally{st.current=!1,kt(!1)}},[Ee,i]),Ce=n.useRef(null),oe=n.useCallback((e,r="ws")=>{const l=nt.current||rt.current.length>0,u=Date.now()-ve.current>Wn;if(Un({updatedAt:e?.updatedAt,isNull:!e,lastAppliedUpdatedAt:Pe.current,localStreamPending:M.current,holdsActiveState:l,holdExpired:u})!=="apply")return;const k=!e&&u&&(M.current||l);if(e&&(ve.current=Date.now(),Pe.current=qn(Pe.current,e.updatedAt)),e?.sessionId&&e.sessionId!==t.sessionId&&(at.current=!0,Te.current=`${t.agent}:${e.sessionId}`,y?.({agent:t.agent||"",sessionId:e.sessionId,workdir:f})),!e){const p=Ce.current;he(!1),k?(M.current=!1,ae.current=!0,Y.current=!0,V(),j({keepOlder:!0,force:!0,scrollToBottom:W.current})):p==="streaming"?(ae.current=!0,Y.current=!0,j({keepOlder:!0,force:!0,scrollToBottom:W.current})):B(null),k||(M.current&&p!=="streaming"?j({keepOlder:!0,force:!0}):(p==="done"&&(A(),V()),p!==null&&(M.current=!1))),Xe(null),Ve(null),Re([]),je([]),Je([]),Ce.current=null;return}Ve(e.phase),Xe(e.taskId||null);const X=[];e.taskId&&X.push(e.taskId),Array.isArray(e.queuedTaskIds)&&X.push(...e.queuedTaskIds),Ie.current=Hn(Ie.current,X,Date.now(),zn);const ue=Ie.current,gt=Dn(e.queuedTaskIds,ue),Pt=(Array.isArray(e.queuedTasks)?e.queuedTasks:[]).filter(p=>!ue.has(p.taskId));if(Re(gt.length?gt:Bn),je(Pt.length?Pt:_n),Je(Array.isArray(e.interactions)&&e.interactions.length?e.interactions:Qn),In({pendingTaskId:Q.current,streamTaskId:e.taskId||null,queuedTaskIds:e.queuedTaskIds})){const p=Q.current,w=bt.current||"",I=L.current;H(v=>v.some(ce=>ce.taskId===p)?v:[...v,{localId:`demote-${p}`,taskId:p,prompt:w,imageUrls:I}]),ne(null),re([]),L.current=[],se(null),Q.current=null}if(e.phase==="streaming"){if(B({taskId:e.taskId||null,phase:"streaming",text:e.text||"",thinking:e.thinking||"",activity:e.activity,plan:e.plan??null,model:e.model??null,effort:e.effort??null,previewMeta:e.previewMeta??null,subAgents:e.previewMeta?.subAgents??null,generatingImages:e.previewMeta?.generatingImages??0,artifacts:e.artifacts??null,startedAt:typeof e.startedAt=="number"?e.startedAt:null,error:null,question:e.question??null,questionBlocks:e.questionBlocks??null}),he(!0),e.taskId&&e.taskId!==Q.current){const p=Ne.current,w=p.findIndex(I=>I.taskId===e.taskId);if(w>=0){const I=p[w];for(const v of L.current)URL.revokeObjectURL(v);ne(I.prompt||null),re(I.imageUrls),L.current=I.imageUrls,se(e.taskId),H(v=>v.filter((ce,J)=>J!==w))}}W.current&&(le.current=!0)}else if(e.phase==="queued")B(null),he(!1);else if(e.phase==="done"){const p=Tn(K.current?.taskId??null,e.taskId||null),w=gt.length>0;if(p){he(!1),B(J=>J?{...J,phase:"done",error:e.error??null}:e.error?{taskId:e.taskId||null,phase:"done",text:"",thinking:"",activity:"",plan:null,model:e.model??null,effort:e.effort??null,previewMeta:e.previewMeta??null,subAgents:e.previewMeta?.subAgents??null,generatingImages:e.previewMeta?.generatingImages??0,artifacts:e.artifacts??null,error:e.error,question:e.question??null,questionBlocks:e.questionBlocks??null}:J);const I=K.current,v=!!I&&yn(I),ce=!!e.incomplete&&v&&!w;if(Ce.current!=="done"){w||(ae.current=!0),Y.current=ce?!1:{taskId:e.taskId||null},j({keepOlder:!0,force:!0,scrollToBottom:W.current});const J=t.agent||"",sn=t.sessionId,ln=Te.current;G.current&&clearTimeout(G.current),G.current=setTimeout(()=>{G.current=null,T.getSessionStreamState(J,sn).then(an=>{Te.current===ln&&Ue.current(an.state,"seed")}).catch(()=>{})},900)}}w||(M.current=!1)}const pt=new Set;if(e.taskId&&pt.add(e.taskId),Array.isArray(e.queuedTaskIds))for(const p of e.queuedTaskIds)pt.add(p);H(p=>{let w=!1;const I=[];for(const v of p)if(!v.taskId||pt.has(v.taskId))I.push(v);else{for(const ce of v.imageUrls)URL.revokeObjectURL(ce);w=!0}return w?I:p}),Ce.current=e.phase},[A,V,j,t.sessionId,t.agent,y,f]),Ue=n.useRef(oe);Ue.current=oe;const Rt=n.useCallback(()=>{M.current=!0,ve.current=Date.now(),St(e=>e+1)},[]);n.useEffect(()=>()=>{G.current&&(clearTimeout(G.current),G.current=null)},[]);const Xt=n.useCallback(async e=>{try{Ie.current.set(e,Date.now()),await T.recallSessionMessage(e),Q.current===e&&A(),H(r=>{let l=!1;const u=[];for(const d of r)if(d.taskId===e){for(const k of d.imageUrls)URL.revokeObjectURL(k);l=!0}else u.push(d);return l?u:r}),Re(r=>r.filter(l=>l!==e)),je(r=>r.filter(l=>l.taskId!==e)),Xe(r=>r===e?null:r)}catch{}},[A]),Jt=n.useCallback(async e=>{const r=Ne.current.find(l=>l.taskId===e)||null;if(r&&r.imageUrls.length>0){for(const l of L.current)URL.revokeObjectURL(l);ne(r.prompt||null),re(r.imageUrls),L.current=r.imageUrls,se(e),Q.current=e,H(l=>l.filter(u=>u.taskId!==e))}try{await T.steerSession(e)}catch{}},[]),Zt=n.useCallback(async()=>{try{await T.stopSession(t.agent||"",t.sessionId)}catch{}},[t.agent,t.sessionId]),qe=Gn(t.agent||"",t.sessionId);n.useEffect(()=>{if(at.current){at.current=!1;let d=!1;return j({keepOlder:!0,force:!0}).finally(()=>{d||ge(!1)}),()=>{d=!0}}let e=!1;const r=Rn({workdir:f,agent:t.agent||"",sessionId:t.sessionId,rich:!0,turnOffset:0,turnLimit:xt},{allowStale:!0}),l=c&&!lt.current,u=r?.ok?Et(r):ie.get(qe)||null;return ge(l?!1:!u),Ye(u),B(null),he(!1),Ve(null),Re([]),je([]),Je([]),Pe.current=0,ve.current=Date.now(),Ie.current=new Map,l||(A(),V(),M.current=!1,ae.current=!1,Y.current=!1),W.current=!0,le.current=!0,l||j({keepOlder:!1,force:!0}).finally(()=>{e||ge(!1)}),()=>{e=!0}},[j,t.agent,t.sessionId,f,qe,A,V]),n.useEffect(()=>{i&&i.turns.length>0&&Vn(qe,i)},[qe,i]),n.useEffect(()=>{N&&j({keepOlder:!0,force:!0})},[N,j]);const Te=n.useRef(`${t.agent}:${t.sessionId}`);Te.current=`${t.agent}:${t.sessionId}`,mn("stream-update",n.useCallback(e=>{e.key===Te.current&&oe(e.snapshot??null)},[oe])),n.useEffect(()=>{let e=!0;return T.getSessionStreamState(t.agent||"",t.sessionId).then(r=>{e&&Ue.current(r.state,"seed")}).catch(()=>{}),()=>{e=!1}},[t.agent,t.sessionId,_t]),gn(n.useCallback(()=>{T.getSessionStreamState(t.agent||"",t.sessionId).then(e=>{oe(e.state,"seed")}).catch(()=>{}),j({keepOlder:!0,force:!0})},[oe,t.agent,t.sessionId,j]));const jt=_||!!q||D.length>0||!!g||we.length>0;n.useEffect(()=>{if(!N||!jt)return;const e=setInterval(()=>{typeof document<"u"&&document.visibilityState!=="visible"||T.getSessionStreamState(t.agent||"",t.sessionId).then(r=>Ue.current(r.state,"seed")).catch(()=>{})},Yn);return()=>clearInterval(e)},[N,jt,t.agent,t.sessionId]),n.useEffect(()=>{!M.current&&te!=="running"&&!_&&!o&&!q&&D.length===0&&(A(),V())},[te,_,o,q,D.length,A,V]),n.useLayoutEffect(()=>{const e=Le.current,r=z.current;!e||!r||(Le.current=null,r.scrollTop=e.scrollTop+(r.scrollHeight-e.scrollHeight))},[i?.turns.length]),n.useLayoutEffect(()=>{if(!le.current)return;const e=z.current;e&&(le.current=!1,e.scrollTop=e.scrollHeight,requestAnimationFrame(()=>{W.current&&(e.scrollTop=e.scrollHeight)}))},[i,o]),n.useLayoutEffect(()=>{if(!g)return;const e=z.current;e&&(e.scrollTop=e.scrollHeight)},[g]),n.useEffect(()=>{if(!i?.hasOlder||Ge||pe)return;const e=z.current;e&&e.scrollHeight<=e.clientHeight+Ht&&Me()},[i?.hasOlder,i?.turns.length,Me,Ge,pe]);const en=n.useCallback(()=>{const e=z.current;if(!e)return;const r=e.scrollHeight-e.scrollTop-e.clientHeight;W.current=r<=Fn,e.scrollTop<=Ht&&Me()},[Me]),ye=o?.model||t.model||Z||null,De=pn(t.agent||"",o?.effort||t.thinkingEffort||R||null,t.workflowEnabled??O?.workflowEnabled)||null,ot=me&&(!ye||ye===Z)?me:ye?hn(ye):null,ut=xn(t,{streaming:_,hasLiveStream:!!o,streamPhase:q,queuedTaskCount:D.length}),b=i?.turns||[],wt=n.useMemo(()=>{for(let e=b.length-1;e>=0;e--){const r=b[e].assistant?.blocks;if(r)for(let l=r.length-1;l>=0;l--){const u=r[l];if(u.type==="plan"&&Mt(u.plan))return u.plan}}return null},[b]),He=n.useMemo(()=>{if(!E.length||!b.length)return!1;const e=b[b.length-1];return!e.user||!Qe(e.user.text,g)?!1:e.user.blocks.filter(l=>l.type==="image").length<E.length},[b,g,E.length]),ct=n.useMemo(()=>E.length?E.map(e=>({type:"image",content:e})):!g||!o?.questionBlocks?.length?[]:Qe(g,o.question)?o.questionBlocks:[],[E,g,o]),it=o?.question||null,Fe=jn(g,it),Nt=o&&Mt(o.plan)?o.plan:o&&wn(g,it)?wt:null,dt=Ct(it,g),At=b.length>0?b[b.length-1]?.user?.text:null,Lt=!!Fe&&b.length>0&&$e(At,Fe),F=n.useMemo(()=>{let e=b;if(He){const ue=e[e.length-1];e=[...e.slice(0,-1),{...ue,user:null}]}if(!o||!e.length)return e;const r=e[e.length-1],l=Fe;if(!r.assistant)return!!r.user&&!!l&&!Qe(r.user.text,l)&&($e(r.user.text,l)||Ct(l,r.user.text))?[...e.slice(0,-1),{...r,user:{...r.user,text:l}}]:e;const u=(o.text||"").trim(),d=r.assistant.text?.trim()||"";if(!(l!=null?$e(r.user?.text,l):!!d&&!!u&&(u.startsWith(d)||d.startsWith(u))))return e;const X=r.user&&l&&!Qe(r.user.text,l)?{...r.user,text:l}:r.user;return[...e.slice(0,-1),{...r,user:X,assistant:null}]},[b,o,Fe,He]),tn=(!!g||ct.length>0)&&!dt&&(He||!Lt)&&!o,nn=!!o&&Ke(o)&&o.phase==="streaming",ft=Nn({sessionRunning:te==="running",streaming:_,streamPhase:q,queuedTaskCount:D.length,pendingQueuedCount:we.length,liveTurnStreaming:nn,pendingBubbleDots:tn}),Be=ft&&F.length>0?F[F.length-1]:null,_e=!!Be?.assistant&&An(Be.assistant),mt=_e?Be.assistant.usage??null:null,rn=_e?Be.assistant.blocks.filter(e=>e.type==="tool_use").length:0,Ot=(()=>{if(!ft||te!=="running")return null;const e=t.runUpdatedAt?Date.parse(t.runUpdatedAt):NaN;return Number.isFinite(e)?e:null})();return s.jsxs("div",{className:"flex flex-col h-full overflow-hidden",children:[s.jsx("div",{ref:z,onScroll:en,className:"flex-1 overflow-y-auto overscroll-contain",children:Ge&&!g&&!E.length&&!o?s.jsx("div",{className:"flex items-center justify-center py-20",children:s.jsx(ze,{className:"h-5 w-5 text-fg-4"})}):F.length===0&&!g&&!E.length&&!o&&!ut?s.jsx("div",{className:"py-20 text-center text-[13px] text-fg-5",children:m("hub.noMessages")}):s.jsxs("div",{className:"max-w-[900px] mx-auto px-6 py-6 space-y-0",children:[(i?.hasOlder||pe)&&s.jsxs("div",{className:"mb-4 flex items-center justify-center gap-2 text-[11px] text-fg-5",children:[pe?s.jsx(ze,{className:"h-3 w-3 text-fg-5"}):s.jsx("span",{className:"h-1.5 w-1.5 rounded-full bg-fg-5/35"}),s.jsx("span",{children:m(pe?"hub.loadingOlderTurns":"hub.loadOlderTurnsHint")})]}),t.migratedFrom?.kind==="fork"&&t.migratedFrom.sessionId&&s.jsxs("button",{type:"button",onClick:()=>y?.({agent:t.migratedFrom.agent||t.agent||"",sessionId:t.migratedFrom.sessionId,workdir:f}),className:"mb-4 inline-flex items-center gap-1.5 rounded-md border border-edge bg-panel-alt px-2.5 py-1 text-[11px] text-fg-5 transition hover:border-edge-h hover:text-fg-2",title:`#${t.migratedFrom.sessionId.slice(0,8)}`,children:[s.jsxs("svg",{width:"10",height:"10",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",children:[s.jsx("circle",{cx:"6",cy:"6",r:"2"}),s.jsx("circle",{cx:"18",cy:"6",r:"2"}),s.jsx("circle",{cx:"12",cy:"20",r:"2"}),s.jsx("path",{d:"M6 8v3a3 3 0 0 0 3 3h6a3 3 0 0 0 3-3V8"}),s.jsx("path",{d:"M12 14v4"})]}),s.jsx("span",{children:m("hub.forkBadge")}),s.jsxs("span",{className:"font-mono",children:["#",t.migratedFrom.sessionId.slice(0,8)]}),typeof t.migratedFrom.forkedAtTurn=="number"&&s.jsxs("span",{className:"text-fg-5/70",children:["· ",m("hub.forkBadgeAt").replace("{turn}",String(t.migratedFrom.forkedAtTurn+1))]})]}),F.map((e,r)=>{const l=(i?.startTurn||0)+r;return s.jsx(Ln,{turn:e,turnIndex:l,hideHeaderUsage:_e&&r===F.length-1,isTail:r===F.length-1,fallbackPlan:r===F.length-1&&!(o&&Ke(o))?wt:void 0,agent:t.agent||"",meta:ee,model:ot,effort:De,providerName:fe,t:m,workdir:f,onResend:u=>{le.current=!0,yt(u);const d=Tt.current;T.sendSessionMessage(f,t.agent||"",t.sessionId,u,{model:d.model||ye||void 0,effort:d.effort||De||void 0}).then(k=>{k.ok&&Rt()}).catch(()=>{A()})},onEdit:u=>vt(u),onFork:Wt?u=>{Ze(""),Se({atTurn:u})}:void 0},`${i?.startTurn||0}:${r}`)}),ut&&s.jsx("div",{className:"mb-5 animate-in",children:s.jsx(On,{detail:ut,t:m})}),(g||ct.length>0)&&!dt&&(He||!Lt)&&s.jsxs("div",{className:"session-turn session-turn--live",children:[s.jsx(Ut,{text:g||"",blocks:ct,t:m}),!o&&s.jsx("div",{className:"mt-3 mb-5 animate-in",children:s.jsx(Pn,{className:"text-fg-5"})})]}),o&&Ke(o)&&o.question&&(!g||dt)&&!(b.length>0&&$e(At,o.question))&&s.jsx("div",{className:"session-turn session-turn--live",children:s.jsx(Ut,{text:o.question,blocks:o.questionBlocks||void 0,t:m})}),o&&Ke(o)&&s.jsxs("div",{className:"mb-6",children:[s.jsx(qt,{agent:t.agent||"",meta:ee,model:ot,effort:De,providerName:fe,previewMeta:o.previewMeta,hideContextUsage:!0}),s.jsx(Dt,{stream:Nt===o.plan?o:{...o,plan:Nt},t:m,workdir:f})]}),ft&&(_e?s.jsx("div",{className:"-mt-3 mb-6 animate-in",children:s.jsx(En,{toolCount:rn,ctxPct:mt?.contextPercent??null,ctxTokens:mt?.contextUsedTokens??0,turnOutTokens:mt?.turnOutputTokens??0,startedAt:Ot})}):s.jsxs("div",{className:"mb-6",children:[s.jsx(qt,{agent:t.agent||"",meta:ee,model:ot,effort:De,providerName:fe,hideContextUsage:!0}),s.jsx(Dt,{stream:{...$n,startedAt:Ot},t:m,workdir:f})]})),s.jsx("div",{className:"h-4"})]})}),s.jsx(Mn,{session:t,workdir:f,onStreamQueued:Rt,onSendStart:yt,onSendTaskAssigned:Gt,onSessionChange:y,t:m,streamPhase:q,streamTaskId:Qt,queuedTaskIds:D,queuedTasks:$t,pendingQueuedSends:we,onRecall:Xt,onSteer:Jt,onStopAll:Zt,editDraft:zt,onEditDraftConsumed:()=>vt(null),onSelectionChange:Yt}),Ae&&s.jsxs(Ft,{open:!0,onClose:()=>{$||Se(null)},children:[s.jsx(Bt,{title:m("hub.forkPromptTitle"),description:m("hub.forkPromptHint"),onClose:()=>{$||Se(null)}}),s.jsx("textarea",{autoFocus:!0,value:be,disabled:$,onChange:e=>Ze(e.target.value),onKeyDown:e=>{e.key==="Enter"&&(e.metaKey||e.ctrlKey)&&be.trim()&&!$&&(e.preventDefault(),tt.current?.())},placeholder:m("hub.forkPromptPlaceholder"),className:"w-full min-h-[120px] resize-y rounded-md border border-edge bg-panel-alt px-3 py-2 text-[13px] leading-relaxed text-fg outline-none focus:border-edge-h"}),s.jsxs("div",{className:"mt-4 flex items-center justify-end gap-2",children:[s.jsx(We,{variant:"ghost",disabled:$,onClick:()=>Se(null),children:m("modal.cancel")}),s.jsx(We,{variant:"primary",disabled:$||!be.trim(),onClick:()=>{tt.current?.()},children:m($?"hub.forkSubmitting":"hub.forkSubmit")})]})]}),N&&xe.length>0&&s.jsx(Cn,{snapshot:xe[xe.length-1]},xe[xe.length-1].promptId)]})});export{or as SessionPanel};
|