pikiloom 0.4.45 → 0.4.47

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.
Files changed (22) hide show
  1. package/dashboard/dist/assets/{AgentTab-B8V2eV_D.js → AgentTab-1PB5sNiV.js} +1 -1
  2. package/dashboard/dist/assets/{ConnectionModal-BOVwXLJB.js → ConnectionModal-MKdYiyph.js} +1 -1
  3. package/dashboard/dist/assets/{DirBrowser-DbeAWYiL.js → DirBrowser-CrTtSp7T.js} +1 -1
  4. package/dashboard/dist/assets/{ExtensionsTab-BMS3PW9N.js → ExtensionsTab-CpbFbTbu.js} +1 -1
  5. package/dashboard/dist/assets/{IMAccessTab-B1sRgJk3.js → IMAccessTab-DnoYQxhx.js} +1 -1
  6. package/dashboard/dist/assets/{Modal-DCwGz46r.js → Modal-BxMOpH7q.js} +1 -1
  7. package/dashboard/dist/assets/{Modals-Bh_0en5P.js → Modals-CgChd_Yq.js} +1 -1
  8. package/dashboard/dist/assets/{Select-DC6zguGC.js → Select-th1z50AY.js} +1 -1
  9. package/dashboard/dist/assets/SessionPanel-DTGtpuIp.js +1 -0
  10. package/dashboard/dist/assets/{SystemTab-uFqZinIZ.js → SystemTab-DYLYxrRz.js} +1 -1
  11. package/dashboard/dist/assets/{index-DooLxbPX.js → index-Bqx1Oo38.js} +15 -15
  12. package/dashboard/dist/assets/{index-CL5H13Cl.js → index-CnZm1BHw.js} +2 -2
  13. package/dashboard/dist/assets/{shared-Byy2BNLq.js → shared-D5m7uSRI.js} +1 -1
  14. package/dashboard/dist/index.html +1 -1
  15. package/dist/agent/stream.js +3 -3
  16. package/dist/bot/bot.js +21 -3
  17. package/package.json +1 -1
  18. package/packages/kernel/dist/drivers/claude.d.ts +4 -1
  19. package/packages/kernel/dist/drivers/claude.js +109 -20
  20. package/packages/kernel/dist/index.d.ts +1 -1
  21. package/packages/kernel/dist/index.js +1 -1
  22. package/dashboard/dist/assets/SessionPanel-DNlLd-PL.js +0 -1
@@ -333,7 +333,7 @@ function prepareStreamOpts(opts) {
333
333
  session.record.lastUserAttachments = [...attachmentRelPaths];
334
334
  if (!session.record.title)
335
335
  session.record.title = summarizePromptTitle(displayPrompt) || null;
336
- session.record.lastQuestion = shortValue(displayPrompt, 500);
336
+ session.record.lastQuestion = trimSessionText(displayPrompt);
337
337
  session.record.lastMessageText = shortValue(displayPrompt, 500);
338
338
  setSessionRunState(session.record, 'running', null);
339
339
  if (session.sessionId)
@@ -381,7 +381,7 @@ function finalizeStreamResult(result, workdir, prompt, session, workflowEnabled,
381
381
  const displayPrompt = collapseSkillPrompt(prompt) ?? prompt;
382
382
  if (!session.record.title)
383
383
  session.record.title = summarizePromptTitle(displayPrompt);
384
- session.record.lastQuestion = shortValue(displayPrompt, 500);
384
+ session.record.lastQuestion = trimSessionText(displayPrompt);
385
385
  session.record.lastAnswer = shortValue(result.message, 500);
386
386
  session.record.lastMessageText = shortValue(result.message, 500) || shortValue(displayPrompt, 500);
387
387
  session.record.lastThinking = trimSessionText(result.thinking);
@@ -647,7 +647,7 @@ export async function doStream(opts) {
647
647
  byokProfileName: prepared.byokProfileName ?? null,
648
648
  };
649
649
  const failureDisplayPrompt = collapseSkillPrompt(opts.prompt) ?? opts.prompt;
650
- session.record.lastQuestion = shortValue(failureDisplayPrompt, 500);
650
+ session.record.lastQuestion = trimSessionText(failureDisplayPrompt);
651
651
  session.record.lastAnswer = shortValue(failedResult.message, 500);
652
652
  session.record.lastMessageText = shortValue(failedResult.message, 500) || shortValue(failureDisplayPrompt, 500);
653
653
  session.record.lastThinking = null;
package/dist/bot/bot.js CHANGED
@@ -215,6 +215,19 @@ export class Bot {
215
215
  }
216
216
  return next;
217
217
  }
218
+ updateTaskPrompt(taskId, fallbackKey, prompt) {
219
+ const task = this.activeTasks.get(taskId);
220
+ const prepared = prompt.trim();
221
+ if (!task || !prepared || task.prompt === prepared)
222
+ return;
223
+ task.prompt = prepared;
224
+ const key = this.liveSessionKey(taskId, fallbackKey);
225
+ const snap = this.streamSnapshots.get(key);
226
+ if (snap) {
227
+ snap.updatedAt = Date.now();
228
+ this.pushSnapshotToSSE(key, true);
229
+ }
230
+ }
218
231
  _onStreamSnapshot = null;
219
232
  streamPushTimers = new Map();
220
233
  streamPushPending = new Map();
@@ -1305,13 +1318,17 @@ export class Bot {
1305
1318
  })
1306
1319
  : null;
1307
1320
  try {
1321
+ const extras = {
1322
+ ...(opts.forkOf ? { forkOf: opts.forkOf } : {}),
1323
+ ...(opts.workflowEnabled !== undefined ? { workflowEnabled: opts.workflowEnabled } : {}),
1324
+ ...(opts.profileId !== undefined ? { profileId: opts.profileId } : {}),
1325
+ onPreparedPrompt: (preparedPrompt) => this.updateTaskPrompt(taskId, session.key, preparedPrompt),
1326
+ };
1308
1327
  const result = await this.runStream(prompt, session, attachments, (text, thinking, activity, meta, plan) => {
1309
1328
  opts.onText?.(text, thinking, activity, meta, plan);
1310
1329
  presenter?.onText(text, thinking, activity, meta, plan);
1311
1330
  this.emitStreamText(taskId, session.key, text, thinking, activity, meta, plan);
1312
- }, undefined, undefined, abortController.signal, this.createInteractionHandler(chatId, taskId), undefined, undefined, (opts.forkOf || opts.workflowEnabled !== undefined || opts.profileId !== undefined)
1313
- ? { ...(opts.forkOf ? { forkOf: opts.forkOf } : {}), ...(opts.workflowEnabled !== undefined ? { workflowEnabled: opts.workflowEnabled } : {}), ...(opts.profileId !== undefined ? { profileId: opts.profileId } : {}) }
1314
- : undefined);
1331
+ }, undefined, undefined, abortController.signal, this.createInteractionHandler(chatId, taskId), undefined, undefined, extras);
1315
1332
  this.emitStreamDone(taskId, session.key, {
1316
1333
  sessionId: result.sessionId || session.sessionId,
1317
1334
  incomplete: !!result.incomplete,
@@ -2030,6 +2047,7 @@ export class Bot {
2030
2047
  });
2031
2048
  if (result.ok && result.seed) {
2032
2049
  prompt = result.seed + '\n\n' + prompt;
2050
+ extras?.onPreparedPrompt?.(prompt);
2033
2051
  this.debug(`[runStream] handover ${describeHandoverRef(handoverFrom)} → ${cs.agent} `
2034
2052
  + `mode=${result.mode} msgs=${result.messagesIncluded}/${result.messagesTotal} `
2035
2053
  + `turnsTotal=${result.turnsTotal} chars=${result.charsIncluded}/${result.budgetChars}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pikiloom",
3
- "version": "0.4.45",
3
+ "version": "0.4.47",
4
4
  "description": "Put the world's smartest AI agents in your pocket. Command local Claude & Gemini via IM. | 让最好用的 IM 变成你电脑上的顶级 Agent 控制台",
5
5
  "type": "module",
6
6
  "bin": {
@@ -31,13 +31,16 @@ export declare function claudeContextWindowFromModel(model: unknown): number | n
31
31
  export declare function claudeEffectiveContextWindow(advertised: number | null): number | null;
32
32
  export declare function handleClaudeEvent(ev: any, s: any, emit: (e: DriverEvent) => void): void;
33
33
  export declare function claudeBgHoldCapMs(): number;
34
+ export declare function claudeBgSettleQuietMs(): number;
34
35
  export declare function isTerminalTaskStatus(status: unknown): boolean;
35
36
  export declare function trackClaudeBackgroundTask(ev: any, s: any): void;
37
+ export declare function markClaudeTaskNotificationTerminal(content: any, s: any): void;
36
38
  export declare function pendingClaudeBackgroundTasks(s: any): number;
37
- export type ClaudeResultSettleDecision = 'settle' | 'hold';
39
+ export type ClaudeResultSettleDecision = 'settle' | 'hold' | 'quiet-settle';
38
40
  export declare function decideClaudeResultSettle(input: {
39
41
  hasError: boolean;
40
42
  pendingBackground: number;
43
+ sawBackground: boolean;
41
44
  }): ClaudeResultSettleDecision;
42
45
  export declare function claudeUserMessage(text: string, attachments?: string[]): string;
43
46
  export declare function emitClaudeImages(blocks: any[], s: any, emit: (e: DriverEvent) => void): void;
@@ -72,12 +72,22 @@ export class ClaudeDriver {
72
72
  return new Promise((resolve) => {
73
73
  let child;
74
74
  let settled = false;
75
+ // holdCap: hard backstop while a background task is still running (never-completing daemon).
76
+ // quiet: fires once all known background tasks finished AND Claude has gone quiet, so trailing
77
+ // wake-up turns can still land before we close (see claudeBgSettleQuietMs).
75
78
  let holdCapTimer = null;
79
+ let quietTimer = null;
76
80
  const usageOf = () => this.usage(state);
81
+ const unref = (tm) => { if (tm && typeof tm.unref === 'function')
82
+ tm.unref(); };
77
83
  const clearHoldCap = () => { if (holdCapTimer) {
78
84
  clearTimeout(holdCapTimer);
79
85
  holdCapTimer = null;
80
86
  } };
87
+ const clearQuiet = () => { if (quietTimer) {
88
+ clearTimeout(quietTimer);
89
+ quietTimer = null;
90
+ } };
81
91
  // kill=true SIGTERMs immediately — fast exit, used once nothing is left running in the
82
92
  // background (a normal turn, or a wake-up turn after every background task finished).
83
93
  // kill=false only ends stdin and lets Claude shut down on its own, so any still-running
@@ -88,6 +98,7 @@ export class ClaudeDriver {
88
98
  return;
89
99
  settled = true;
90
100
  clearHoldCap();
101
+ clearQuiet();
91
102
  try {
92
103
  child?.stdin?.end();
93
104
  }
@@ -104,8 +115,7 @@ export class ClaudeDriver {
104
115
  child?.kill('SIGTERM');
105
116
  }
106
117
  catch { /* ignore */ } }, CLAUDE_EXIT_LEAK_GUARD_MS);
107
- if (typeof guard.unref === 'function')
108
- guard.unref();
118
+ unref(guard);
109
119
  }
110
120
  }
111
121
  resolve(r);
@@ -114,6 +124,23 @@ export class ClaudeDriver {
114
124
  ok: !state.error, text: state.text, reasoning: state.reasoning || undefined,
115
125
  error: state.error, stopReason: opts.stopReason ?? state.stopReason, sessionId: state.sessionId, usage: usageOf(),
116
126
  }, opts.kill ?? true);
127
+ // Absolute cap while holding for a still-running background task (stopReason marks it as
128
+ // "still running in the background" so the empty-text fallback reads right). Idempotent.
129
+ const armHoldCap = () => {
130
+ if (holdCapTimer)
131
+ return;
132
+ holdCapTimer = setTimeout(() => { if (!settled)
133
+ settleResult({ stopReason: 'background', kill: false }); }, claudeBgHoldCapMs());
134
+ unref(holdCapTimer);
135
+ };
136
+ // Grace close once all background work is done: settle gracefully (no kill) if Claude stays
137
+ // quiet for the window. Re-armed on every event, so a still-streaming wake-up keeps it open.
138
+ const armQuiet = () => {
139
+ clearQuiet();
140
+ quietTimer = setTimeout(() => { if (!settled)
141
+ settleResult({ kill: false }); }, claudeBgSettleQuietMs());
142
+ unref(quietTimer);
143
+ };
117
144
  try {
118
145
  child = spawn(this.bin, args, { cwd: input.workdir, env: { ...process.env, ...(input.env || {}) }, stdio: ['pipe', 'pipe', 'pipe'] });
119
146
  }
@@ -162,24 +189,38 @@ export class ClaudeDriver {
162
189
  continue;
163
190
  }
164
191
  handleClaudeEvent(ev, state, ctx.emit);
165
- if (ev.type !== 'result')
166
- continue;
167
- const hasError = !!ev.is_error || (Array.isArray(ev.errors) && ev.errors.length > 0) || !!state.error;
168
192
  const pending = pendingClaudeBackgroundTasks(state);
169
- if (decideClaudeResultSettle({ hasError, pendingBackground: pending }) === 'hold') {
170
- // Background work is still running: do NOT end the turn here. Keep stdin open so Claude
171
- // wakes itself up and streams a follow-up turn reporting the finished work — we settle
172
- // on THAT result (pending back to 0). A cap bounds the wait so a never-completing daemon
173
- // (e.g. a dev server) eventually settles (graceful, no kill) instead of holding forever.
174
- if (!holdCapTimer) {
175
- holdCapTimer = setTimeout(() => { if (!settled)
176
- settleResult({ stopReason: 'background', kill: false }); }, claudeBgHoldCapMs());
177
- if (typeof holdCapTimer.unref === 'function')
178
- holdCapTimer.unref();
193
+ if (ev.type === 'result') {
194
+ const hasError = !!ev.is_error || (Array.isArray(ev.errors) && ev.errors.length > 0) || !!state.error;
195
+ const decision = decideClaudeResultSettle({ hasError, pendingBackground: pending, sawBackground: state.bgStarted.size > 0 });
196
+ if (decision === 'settle') {
197
+ settleResult();
198
+ return;
179
199
  }
200
+ if (decision === 'hold') {
201
+ clearQuiet();
202
+ armHoldCap();
203
+ continue;
204
+ }
205
+ // 'quiet-settle': every known background task finished, but Claude may still be delivering
206
+ // wake-up turns whose delivery trails the completion status (with parallel agents the last
207
+ // one's completion can land before an earlier one's wake-up result). Don't exit here — wait
208
+ // for Claude to go quiet, then close gracefully so no in-flight wake-up is torn down. Keep
209
+ // the hold cap armed as an absolute backstop.
210
+ armHoldCap();
211
+ armQuiet();
180
212
  continue;
181
213
  }
182
- settleResult();
214
+ // Non-result activity: a still-streaming wake-up refreshes the quiet window; a newly-started
215
+ // background task pulls us back into the hold.
216
+ if (quietTimer) {
217
+ if (pending > 0) {
218
+ clearQuiet();
219
+ armHoldCap();
220
+ }
221
+ else
222
+ armQuiet();
223
+ }
183
224
  }
184
225
  });
185
226
  child.stderr.on('data', (c) => { stderr += c.toString('utf8'); });
@@ -424,10 +465,13 @@ export function handleClaudeEvent(ev, s, emit) {
424
465
  return;
425
466
  }
426
467
  if (t === 'user') {
468
+ // Background wake-up delivery: a `<task-notification>` tag (as a string or a text block) marks
469
+ // its background task terminal — an extra completion signal alongside the system task events.
470
+ markClaudeTaskNotificationTerminal(ev.message?.content, s);
427
471
  // Tool results: surface generated images as artifacts AND close out the tool call
428
472
  // (status done/failed + a result detail) so toolCalls is a faithful structured SSOT
429
473
  // and the runtime's activity projection can render the execution trail.
430
- const contents = ev.message?.content || [];
474
+ const contents = Array.isArray(ev.message?.content) ? ev.message.content : [];
431
475
  for (const b of contents) {
432
476
  if (b?.type !== 'tool_result')
433
477
  continue;
@@ -503,6 +547,18 @@ export function claudeBgHoldCapMs() {
503
547
  const raw = Number(process.env.PIKILOOM_CLAUDE_BG_HOLD_MS);
504
548
  return Number.isFinite(raw) && raw > 0 ? raw : CLAUDE_BG_HOLD_CAP_DEFAULT_MS;
505
549
  }
550
+ // Once every KNOWN background task has finished, how long Claude must stay quiet (no further
551
+ // output at all) before we close a background turn. A completed task's status races AHEAD of the
552
+ // wake-up turn that reports it — with N parallel agents finishing together, the last agent's
553
+ // completion can land before an earlier agent's wake-up result, so exiting at the first
554
+ // pending==0 result would kill the still-undelivered wake-ups (the "background was running when
555
+ // the process exited" failure). Refreshed on every event, so a still-streaming wake-up keeps it
556
+ // alive. Override with PIKILOOM_CLAUDE_BG_SETTLE_QUIET_MS.
557
+ const CLAUDE_BG_SETTLE_QUIET_DEFAULT_MS = 15_000;
558
+ export function claudeBgSettleQuietMs() {
559
+ const raw = Number(process.env.PIKILOOM_CLAUDE_BG_SETTLE_QUIET_MS);
560
+ return Number.isFinite(raw) && raw > 0 ? raw : CLAUDE_BG_SETTLE_QUIET_DEFAULT_MS;
561
+ }
506
562
  // After we settle a held turn gracefully (stdin closed, no kill), force-kill the lingering
507
563
  // process only if it hasn't exited on its own within this window. Backstop against leaks.
508
564
  const CLAUDE_EXIT_LEAK_GUARD_MS = 15_000;
@@ -524,6 +580,32 @@ export function trackClaudeBackgroundTask(ev, s) {
524
580
  if (isTerminalTaskStatus(ev?.patch?.status ?? ev?.status))
525
581
  (s.bgTerminal ||= new Set()).add(id);
526
582
  }
583
+ function claudeContentText(content) {
584
+ if (typeof content === 'string')
585
+ return content;
586
+ if (Array.isArray(content))
587
+ return content.filter((b) => b?.type === 'text' && typeof b.text === 'string').map((b) => b.text).join('\n');
588
+ return '';
589
+ }
590
+ // Extra completion signal (mirrors the legacy driver): Claude delivers a background wake-up as a
591
+ // `type:'user'` message carrying a `<task-notification>` tag (<task-id>/<tool-use-id>/<status>).
592
+ // Mark that task terminal too, so a missed/absent system task_notification still lets pending
593
+ // reach 0 (instead of the turn hanging to the hold cap).
594
+ export function markClaudeTaskNotificationTerminal(content, s) {
595
+ const text = claudeContentText(content);
596
+ if (!text || !text.includes('<task-notification>'))
597
+ return;
598
+ const tag = (name) => {
599
+ const m = text.match(new RegExp(`<${name}>\\s*([^<]*?)\\s*</${name}>`));
600
+ return m ? m[1].trim() : '';
601
+ };
602
+ const status = tag('status');
603
+ if (status && !isTerminalTaskStatus(status))
604
+ return;
605
+ for (const id of [tag('task-id'), tag('tool-use-id')])
606
+ if (id)
607
+ (s.bgTerminal ||= new Set()).add(id);
608
+ }
527
609
  export function pendingClaudeBackgroundTasks(s) {
528
610
  const started = s?.bgStarted;
529
611
  if (!started?.size)
@@ -535,12 +617,19 @@ export function pendingClaudeBackgroundTasks(s) {
535
617
  n++;
536
618
  return n;
537
619
  }
538
- // At a `result` event: settle the turn normally, unless background work is still running
539
- // (then hold the process open for the wake-up). Errors always settle.
620
+ // At a `result` event, decide how to end the turn:
621
+ // - error → 'settle' now (hard exit).
622
+ // - a background task is still running → 'hold' the process open for its wake-up.
623
+ // - background done BUT this turn launched background work → 'quiet-settle': do NOT exit at this
624
+ // result. Claude may still be DELIVERING wake-up turns whose delivery trails their task's
625
+ // completion status (see claudeBgSettleQuietMs); wait for it to go quiet, then close gracefully.
626
+ // - a plain turn (no background) → 'settle' now.
540
627
  export function decideClaudeResultSettle(input) {
541
628
  if (input.hasError)
542
629
  return 'settle';
543
- return input.pendingBackground > 0 ? 'hold' : 'settle';
630
+ if (input.pendingBackground > 0)
631
+ return 'hold';
632
+ return input.sawBackground ? 'quiet-settle' : 'settle';
544
633
  }
545
634
  // Claude vision input formats (matches the legacy driver / Anthropic API: png, jpeg, gif, webp).
546
635
  const CLAUDE_IMAGE_MIME = {
@@ -9,7 +9,7 @@ export type { SessionStore, CoreSessionRecord, ModelResolver, ModelInjection, To
9
9
  export type { LoomIO, PromptInput, Surface, SurfaceCapabilities, Plugin, SpawnContribution, } from './contracts/surface.js';
10
10
  export { FsSessionStore, NullModelResolver, NoopToolProvider, PassthroughSystemPromptBuilder, AutoCancelInteractionHandler, DeferToTerminalInteractionHandler, NoopCatalog, defaultBaseDir, } from './ports/defaults.js';
11
11
  export { EchoDriver } from './drivers/echo.js';
12
- export { ClaudeDriver, isTerminalTaskStatus, trackClaudeBackgroundTask, pendingClaudeBackgroundTasks, decideClaudeResultSettle, claudeBgHoldCapMs, type ClaudeResultSettleDecision, } from './drivers/claude.js';
12
+ export { ClaudeDriver, isTerminalTaskStatus, trackClaudeBackgroundTask, pendingClaudeBackgroundTasks, markClaudeTaskNotificationTerminal, decideClaudeResultSettle, claudeBgHoldCapMs, claudeBgSettleQuietMs, type ClaudeResultSettleDecision, } from './drivers/claude.js';
13
13
  export { CodexDriver } from './drivers/codex.js';
14
14
  export { GeminiDriver } from './drivers/gemini.js';
15
15
  export { AcpDriver, type AcpDriverConfig } from './drivers/acp.js';
@@ -19,7 +19,7 @@ export { attachTui } from './runtime/tui.js';
19
19
  export { FsSessionStore, NullModelResolver, NoopToolProvider, PassthroughSystemPromptBuilder, AutoCancelInteractionHandler, DeferToTerminalInteractionHandler, NoopCatalog, defaultBaseDir, } from './ports/defaults.js';
20
20
  // Drivers & surfaces (also available via subpath exports)
21
21
  export { EchoDriver } from './drivers/echo.js';
22
- export { ClaudeDriver, isTerminalTaskStatus, trackClaudeBackgroundTask, pendingClaudeBackgroundTasks, decideClaudeResultSettle, claudeBgHoldCapMs, } from './drivers/claude.js';
22
+ export { ClaudeDriver, isTerminalTaskStatus, trackClaudeBackgroundTask, pendingClaudeBackgroundTasks, markClaudeTaskNotificationTerminal, decideClaudeResultSettle, claudeBgHoldCapMs, claudeBgSettleQuietMs, } from './drivers/claude.js';
23
23
  export { CodexDriver } from './drivers/codex.js';
24
24
  export { GeminiDriver } from './drivers/gemini.js';
25
25
  export { AcpDriver } from './drivers/acp.js';
@@ -1 +0,0 @@
1
- import{r as t,j as n}from"./react-vendor-C7Sl8SE7.js";import{c as Ut,I as Ft,S as Ce,m as Pe,a as j,u as Ze,d as Ht,g as Bt,l as Dt,e as Qt,j as _t,f as $t,s as Kt,Y as zt}from"./index-CL5H13Cl.js";import{s as Wt,l as Yt,n as pt,m as Xt,a as Gt,o as Vt,d as Jt,b as Zt,p as er,c as et,e as tt,T as tr,R as rr,U as ht,f as nr,g as xt,h as sr,L as lr,I as ar}from"./index-DooLxbPX.js";import{M as St,a as bt}from"./Modal-DCwGz46r.js";import"./router-DHISdpPk.js";import"./Select-DC6zguGC.js";import"./DirBrowser-DbeAWYiL.js";import"./markdown-DxQYQFeH.js";import"./ExtensionsTab-BMS3PW9N.js";function or({snapshot:a}){const[r,f]=t.useState(a.currentIndex??0),[O,v]=t.useState(""),[k,g]=t.useState(!1),[C,S]=t.useState(null);t.useEffect(()=>{f(a.currentIndex??0),v(""),S(null)},[a.promptId,a.currentIndex]);const L=a.questions||[],y=L[r]||null,K=L.length,P=!!(y?.options&&y.options.length),M=P?!!y?.allowFreeform:!0,ae=u=>{u&&(f(c=>c+1),v(""))},Ie=async u=>{if(!k){g(!0),S(null);try{const c=await j.interactionSelectOption(a.promptId,u);if(!c.ok){S(c.error||"Failed to submit selection.");return}ae(c.advanced)}catch(c){S(c?.message||"Network error.")}finally{g(!1)}}},oe=async()=>{if(k)return;const u=O.trim();if(!u&&!y?.allowEmpty){S("Please enter a response.");return}g(!0),S(null);try{const c=await j.interactionSubmitText(a.promptId,u);if(!c.ok){S(c.error||"Failed to submit answer.");return}ae(c.advanced)}catch(c){S(c?.message||"Network error.")}finally{g(!1)}},p=async()=>{if(!k){g(!0),S(null);try{const u=await j.interactionSkip(a.promptId);if(!u.ok){S(u.error||"Failed to skip.");return}ae(u.advanced)}catch(u){S(u?.message||"Network error.")}finally{g(!1)}}},ue=async()=>{if(!k){g(!0);try{await j.interactionCancel(a.promptId)}catch{}}},ve=t.useMemo(()=>{const u=[];return a.hint&&u.push(a.hint),K>1&&u.push(`Question ${r+1} of ${K}`),u.join(" · ")||void 0},[a.hint,r,K]);return n.jsxs(St,{open:!0,onClose:ue,wide:P&&(y?.options?.length||0)>3,children:[n.jsx(bt,{title:a.title||"Pikiloom needs your input",description:ve,onClose:ue}),y?n.jsxs("div",{className:"space-y-4",children:[n.jsxs("div",{children:[n.jsx("div",{className:"text-xs font-medium uppercase tracking-wide text-fg-5",children:y.header||"Question"}),n.jsx("div",{className:"mt-1 whitespace-pre-wrap text-sm leading-relaxed text-fg",children:y.prompt})]}),P&&n.jsx("div",{className:"grid grid-cols-1 gap-2 sm:grid-cols-2",children:(y.options||[]).map(u=>n.jsxs("button",{type:"button",disabled:k,onClick:()=>Ie(u.value||u.label),className:Ut("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:[n.jsx("div",{className:"font-medium text-fg group-hover:text-fg",children:u.label}),u.description&&n.jsx("div",{className:"mt-0.5 text-xs leading-snug text-fg-4",children:u.description})]},u.value||u.label))}),M&&n.jsx("div",{children:n.jsx(Ft,{value:O,onChange:u=>v(u.target.value),onKeyDown:u=>{u.key==="Enter"&&!u.shiftKey&&!k&&(u.preventDefault(),oe())},placeholder:P?"Or type a custom answer…":"Type your answer…",disabled:k,autoFocus:!P})}),C&&n.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}),n.jsxs("div",{className:"flex items-center justify-between gap-3",children:[n.jsx("div",{className:"text-xs text-fg-5",children:k?n.jsxs("span",{className:"inline-flex items-center gap-2",children:[n.jsx(Ce,{})," Submitting…"]}):n.jsxs("span",{children:["Press ",n.jsx("kbd",{className:"rounded border border-edge bg-panel-alt px-1.5 py-0.5 text-[10px] uppercase",children:"Enter"})," to send"]})}),n.jsxs("div",{className:"flex items-center gap-2",children:[n.jsx(Pe,{variant:"ghost",size:"sm",onClick:p,disabled:k,children:"Skip"}),M&&n.jsx(Pe,{variant:"primary",size:"sm",onClick:oe,disabled:k||!O.trim()&&!y.allowEmpty,children:"Submit"})]})]})]}):n.jsxs("div",{className:"py-6 text-center text-sm text-fg-5",children:[n.jsx(Ce,{className:"mr-2 inline-block"})," Waiting for the agent…"]})]})}function ur(a){return a.isNull?a.localStreamPending||a.holdsActiveState?"reject-null":"apply":(typeof a.updatedAt=="number"?a.updatedAt:0)<a.lastAppliedUpdatedAt?"reject-stale":"apply"}function cr(a,r){return typeof r!="number"?a:r>a?r:a}function ir(a,r){return!a||!a.length?[]:r.size?a.filter(f=>!r.has(f)):a.slice()}function dr(a,r,f,O){if(!a.size)return a;const v=new Set(r);let k=!1;const g=new Map;for(const[C,S]of a){if(f-S>O||!v.has(C)){k=!0;continue}g.set(C,S)}return k?g:a}const rt=12,kt=160,fr=96,mr=[],gr=[],pr=[],hr=20,xr=6e4,le=new Map;function kr(a,r){return`${a}:${r}`}function Sr(a,r){for(le.delete(a),le.set(a,r);le.size>hr;)le.delete(le.keys().next().value)}const Ar=t.memo(function({session:r,workdir:f,active:O=!0,onSessionChange:v,initialPendingPrompt:k,initialPendingImageUrls:g,onPendingPromptConsumed:C}){const S=Ze(e=>e.locale),L=Ze(e=>e.agentStatus?.agents?.find(s=>s.agent===r.agent)??null),y=L?.selectedEffort??null,K=L?.selectedModel??null,P=Ze(e=>e.modelLayer),M=r.profileId?P?.profiles.find(e=>e.id===r.profileId)??null:null,ae=M?P?.providers.find(e=>e.id===M.providerId)??null:null,Ie=r.profileId===void 0?L?.byokProviderName??null:ae?.name??null,oe=r.profileId===void 0?L?.byokProfileName??null:M&&M.name.trim().toLowerCase()!==M.modelId.trim().toLowerCase()?M.name:null,p=t.useMemo(()=>Ht(S),[S]),ue=Bt(r.agent||""),ve=Dt(r),u=!!k||!!(g&&g.length),[c,qe]=t.useState(null),[Ue,ce]=t.useState(!u),[ie,nt]=t.useState(!1),[i,U]=t.useState(null),[de,fe]=t.useState(!1),[z,Fe]=t.useState(null),[It,st]=t.useState(0),[vt,He]=t.useState(null),[W,ye]=t.useState([]),[yt,Te]=t.useState([]),[me,Be]=t.useState([]),[h,Y]=t.useState(k||null),[E,X]=t.useState(g||[]),[Tt,G]=t.useState(null),F=t.useRef(null);F.current=Tt;const lt=t.useRef(h);lt.current=h;const[at,q]=t.useState([]),Re=t.useRef([]);Re.current=at;const ge=t.useRef(null),[Rt,ot]=t.useState(null),[je,pe]=t.useState(null),[he,De]=t.useState(""),[H,Qe]=t.useState(!1),jt=!!L?.capabilities?.fork,_e=t.useRef(null),A=t.useRef(g||[]),B=t.useRef(i),$e=t.useRef(de);B.current=i,$e.current=de;const Ke=t.useRef(W);Ke.current=W;const ut=t.useRef(z);ut.current=z;const D=t.useRef(null),we=t.useRef(null),V=t.useRef(!0),J=t.useRef(!1),Ne=t.useRef(null),ze=t.useRef(!1),Q=t.useRef(u),xe=t.useRef(!1),Z=t.useRef(!1),We=t.useRef(!1),Ye=t.useRef(!1),_=t.useRef(null),Ae=t.useRef(0),ke=t.useRef(new Map),ct=t.useRef({model:null,effort:null}),wt=t.useCallback(e=>{ct.current=e},[]);t.useEffect(()=>{We.current||!u||(We.current=!0,k&&!h&&Y(k),g&&g.length&&!E.length&&(X(g),A.current=g),ce(!1),st(e=>e+1),C?.())},[u,C]);const w=t.useCallback(()=>{Y(null),X(e=>{for(const s of e)URL.revokeObjectURL(s);return[]}),A.current=[],G(null)},[]),ee=t.useCallback(()=>{q(e=>{if(!e.length)return e;for(const s of e)for(const l of s.imageUrls)URL.revokeObjectURL(l);return[]}),ge.current=null},[]),it=t.useCallback((e,s)=>{const l=Wt({streaming:$e.current,liveStreamPhase:B.current?.phase??null,streamPhase:ut.current,queuedTaskCount:Ke.current.length,pendingQueuedCount:Re.current.length}),o=s||[];if(l){const d=`local-${Date.now().toString(36)}-${Math.random().toString(36).slice(2,8)}`;ge.current=d,q(x=>[...x,{localId:d,taskId:null,prompt:e||"",imageUrls:o}]);return}B.current?.phase==="done"&&U(null);for(const d of A.current)URL.revokeObjectURL(d);ge.current=null,Y(e||null),X(o),A.current=o,G(null)},[]),Nt=t.useCallback(e=>{const s=ge.current;if(s){ge.current=null,q(l=>{const o=l.findIndex(x=>x.localId===s);if(o<0)return l;const d=l.slice();return d[o]={...d[o],taskId:e},d});return}G(e)},[]),At=t.useCallback(async()=>{if(!je)return;const e=he.trim();if(e){Qe(!0);try{const s=await j.forkSession(f,r.agent||"",r.sessionId,je.atTurn,e,{});if(!s.ok||!s.sessionKey){Qe(!1);return}const[l,o]=s.sessionKey.split(":");pe(null),De(""),v?.({agent:l,sessionId:o,workdir:f})}finally{Qe(!1)}}},[je,he,f,r.agent,r.sessionId,v]);_e.current=At;const Oe=t.useCallback(async(e,s={})=>{try{const l=await Yt({workdir:f,agent:r.agent||"",sessionId:r.sessionId,rich:!0,turnOffset:e.turnOffset,turnLimit:e.turnLimit,lastNTurns:e.lastNTurns},{force:s.force});return l.ok?pt(l):null}catch{return null}},[f,r.agent,r.sessionId]),N=t.useCallback(async({keepOlder:e,force:s=!1,scrollToBottom:l=!1})=>{const o=r.sessionId;if(Ne.current===o)return!1;Ne.current=o;try{const d=await Oe({turnOffset:0,turnLimit:rt},{force:s});if(!d||r.sessionId!==o)return!1;if(l&&(J.current=!0),qe(x=>!x||!e?d:Xt(x,d)),ce(!1),xe.current&&(xe.current=!1,w()),Z.current){const x=Z.current;Z.current=!1;const re=x!==!0?x.taskId:null;B.current&&(x===!0||B.current.taskId===re)&&U(null)}return!0}finally{Ne.current===o&&(Ne.current=null)}},[Oe,w,r.sessionId]),Le=t.useCallback(async()=>{if(!c?.hasOlder||ze.current)return;const e=D.current;e&&(we.current={scrollHeight:e.scrollHeight,scrollTop:e.scrollTop}),ze.current=!0,nt(!0);try{const s=await Oe({turnOffset:Math.max(0,c.totalTurns-c.startTurn),turnLimit:rt});s?qe(l=>l?Gt(l,s):s):we.current=null}finally{ze.current=!1,nt(!1)}},[Oe,c]),Me=t.useRef(null),te=t.useCallback((e,s="ws")=>{if(ur({updatedAt:e?.updatedAt,isNull:!e,lastAppliedUpdatedAt:Ae.current,localStreamPending:Q.current,holdsActiveState:$e.current||Ke.current.length>0})!=="apply")return;if(e&&(Ae.current=cr(Ae.current,e.updatedAt)),e?.sessionId&&e.sessionId!==r.sessionId&&(Ye.current=!0,Se.current=`${r.agent}:${e.sessionId}`,v?.({agent:r.agent||"",sessionId:e.sessionId,workdir:f})),!e){const m=Me.current;fe(!1),m==="streaming"?(xe.current=!0,Z.current=!0,N({keepOlder:!0,force:!0,scrollToBottom:V.current})):U(null),Q.current&&m!=="streaming"?N({keepOlder:!0,force:!0}):(m==="done"&&(w(),ee()),m!==null&&(Q.current=!1)),He(null),Fe(null),ye([]),Te([]),Be([]),Me.current=null;return}Fe(e.phase),He(e.taskId||null);const o=[];e.taskId&&o.push(e.taskId),Array.isArray(e.queuedTaskIds)&&o.push(...e.queuedTaskIds),ke.current=dr(ke.current,o,Date.now(),xr);const d=ke.current,x=ir(e.queuedTaskIds,d),re=(Array.isArray(e.queuedTasks)?e.queuedTasks:[]).filter(m=>!d.has(m.taskId));if(ye(x.length?x:mr),Te(re.length?re:gr),Be(Array.isArray(e.interactions)&&e.interactions.length?e.interactions:pr),Vt({pendingTaskId:F.current,streamTaskId:e.taskId||null,queuedTaskIds:e.queuedTaskIds})){const m=F.current,R=lt.current||"",I=A.current;q(b=>b.some(se=>se.taskId===m)?b:[...b,{localId:`demote-${m}`,taskId:m,prompt:R,imageUrls:I}]),Y(null),X([]),A.current=[],G(null),F.current=null}if(e.phase==="streaming"){if(U({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}),fe(!0),e.taskId&&e.taskId!==F.current){const m=Re.current,R=m.findIndex(I=>I.taskId===e.taskId);if(R>=0){const I=m[R];for(const b of A.current)URL.revokeObjectURL(b);Y(I.prompt||null),X(I.imageUrls),A.current=I.imageUrls,G(e.taskId),q(b=>b.filter((se,$)=>$!==R))}}V.current&&(J.current=!0)}else if(e.phase==="queued")U(null),fe(!1);else if(e.phase==="done"){const m=Jt(B.current?.taskId??null,e.taskId||null),R=x.length>0;if(m){fe(!1),U($=>$?{...$,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}:$);const I=B.current,b=!!I&&Zt(I),se=!!e.incomplete&&b&&!R;if(Me.current!=="done"){R||(xe.current=!0),Z.current=se?!1:{taskId:e.taskId||null},N({keepOlder:!0,force:!0,scrollToBottom:V.current});const $=r.agent||"",Ct=r.sessionId,Pt=Se.current;_.current&&clearTimeout(_.current),_.current=setTimeout(()=>{_.current=null,j.getSessionStreamState($,Ct).then(qt=>{Se.current===Pt&&Xe.current(qt.state,"seed")}).catch(()=>{})},900)}}R||(Q.current=!1)}const ne=new Set;if(e.taskId&&ne.add(e.taskId),Array.isArray(e.queuedTaskIds))for(const m of e.queuedTaskIds)ne.add(m);q(m=>{let R=!1;const I=[];for(const b of m)if(!b.taskId||ne.has(b.taskId))I.push(b);else{for(const se of b.imageUrls)URL.revokeObjectURL(se);R=!0}return R?I:m}),Me.current=e.phase},[w,ee,N,r.sessionId,r.agent,v,f]),Xe=t.useRef(te);Xe.current=te;const dt=t.useCallback(()=>{Q.current=!0,st(e=>e+1)},[]);t.useEffect(()=>()=>{_.current&&(clearTimeout(_.current),_.current=null)},[]);const Ot=t.useCallback(async e=>{try{ke.current.set(e,Date.now()),await j.recallSessionMessage(e),F.current===e&&w(),q(s=>{let l=!1;const o=[];for(const d of s)if(d.taskId===e){for(const x of d.imageUrls)URL.revokeObjectURL(x);l=!0}else o.push(d);return l?o:s}),ye(s=>s.filter(l=>l!==e)),Te(s=>s.filter(l=>l.taskId!==e)),He(s=>s===e?null:s)}catch{}},[w]),Lt=t.useCallback(async e=>{const s=Re.current.find(l=>l.taskId===e)||null;if(s&&s.imageUrls.length>0){for(const l of A.current)URL.revokeObjectURL(l);Y(s.prompt||null),X(s.imageUrls),A.current=s.imageUrls,G(e),F.current=e,q(l=>l.filter(o=>o.taskId!==e))}try{await j.steerSession(e)}catch{}},[]),Mt=t.useCallback(async()=>{try{await j.stopSession(r.agent||"",r.sessionId)}catch{}},[r.agent,r.sessionId]),Ee=kr(r.agent||"",r.sessionId);t.useEffect(()=>{if(Ye.current){Ye.current=!1;let d=!1;return N({keepOlder:!0,force:!0}).finally(()=>{d||ce(!1)}),()=>{d=!0}}let e=!1;const s=er({workdir:f,agent:r.agent||"",sessionId:r.sessionId,rich:!0,turnOffset:0,turnLimit:rt},{allowStale:!0}),l=u&&!We.current,o=s?.ok?pt(s):le.get(Ee)||null;return ce(l?!1:!o),qe(o),U(null),fe(!1),Fe(null),ye([]),Te([]),Be([]),Ae.current=0,ke.current=new Map,l||(w(),ee(),Q.current=!1,xe.current=!1,Z.current=!1),V.current=!0,J.current=!0,l||N({keepOlder:!1,force:!0}).finally(()=>{e||ce(!1)}),()=>{e=!0}},[N,r.agent,r.sessionId,f,Ee,w,ee]),t.useEffect(()=>{c&&c.turns.length>0&&Sr(Ee,c)},[Ee,c]),t.useEffect(()=>{O&&N({keepOlder:!0,force:!0})},[O,N]);const Se=t.useRef(`${r.agent}:${r.sessionId}`);Se.current=`${r.agent}:${r.sessionId}`,Qt("stream-update",t.useCallback(e=>{e.key===Se.current&&te(e.snapshot??null)},[te])),t.useEffect(()=>{let e=!0;return j.getSessionStreamState(r.agent||"",r.sessionId).then(s=>{e&&Xe.current(s.state,"seed")}).catch(()=>{}),()=>{e=!1}},[r.agent,r.sessionId,It]),_t(t.useCallback(()=>{j.getSessionStreamState(r.agent||"",r.sessionId).then(e=>{te(e.state,"seed")}).catch(()=>{}),N({keepOlder:!0,force:!0})},[te,r.agent,r.sessionId,N])),t.useEffect(()=>{!Q.current&&ve!=="running"&&!de&&!i&&!z&&W.length===0&&(w(),ee())},[ve,de,i,z,W.length,w,ee]),t.useLayoutEffect(()=>{const e=we.current,s=D.current;!e||!s||(we.current=null,s.scrollTop=e.scrollTop+(s.scrollHeight-e.scrollHeight))},[c?.turns.length]),t.useLayoutEffect(()=>{if(!J.current)return;const e=D.current;e&&(J.current=!1,e.scrollTop=e.scrollHeight,requestAnimationFrame(()=>{V.current&&(e.scrollTop=e.scrollHeight)}))},[c,i]),t.useLayoutEffect(()=>{if(!h)return;const e=D.current;e&&(e.scrollTop=e.scrollHeight)},[h]),t.useEffect(()=>{if(!c?.hasOlder||Ue||ie)return;const e=D.current;e&&e.scrollHeight<=e.clientHeight+kt&&Le()},[c?.hasOlder,c?.turns.length,Le,Ue,ie]);const Et=t.useCallback(()=>{const e=D.current;if(!e)return;const s=e.scrollHeight-e.scrollTop-e.clientHeight;V.current=s<=fr,e.scrollTop<=kt&&Le()},[Le]),be=i?.model||r.model||K||null,Ge=$t(r.agent||"",i?.effort||r.thinkingEffort||y||null,r.workflowEnabled??L?.workflowEnabled)||null,ft=oe&&(!be||be===K)?oe:be?Kt(be):null,Ve=zt(r,{streaming:de,hasLiveStream:!!i,streamPhase:z,queuedTaskCount:W.length}),T=c?.turns||[],Je=t.useMemo(()=>{if(!E.length||!T.length)return!1;const e=T[T.length-1];return!e.user||!et(e.user.text,h)?!1:e.user.blocks.filter(l=>l.type==="image").length<E.length},[T,h,E.length]),mt=t.useMemo(()=>E.length?E.map(e=>({type:"image",content:e})):!h||!i?.questionBlocks?.length?[]:et(h,i.question)?i.questionBlocks:[],[E,h,i]),gt=t.useMemo(()=>{let e=T;if(Je){const ne=e[e.length-1];e=[...e.slice(0,-1),{...ne,user:null}]}if(!i||!e.length)return e;const s=e[e.length-1];if(!s.assistant)return e;const l=h??(i.question||null),o=(i.text||"").trim(),d=s.assistant.text?.trim()||"";if(!(l!=null?tt(s.user?.text,l):!!d&&!!o&&(o.startsWith(d)||d.startsWith(o))))return e;const re=s.user&&l&&!et(s.user.text,l)?{...s.user,text:l}:s.user;return[...e.slice(0,-1),{...s,user:re,assistant:null}]},[T,i,h,Je]);return n.jsxs("div",{className:"flex flex-col h-full overflow-hidden",children:[n.jsx("div",{ref:D,onScroll:Et,className:"flex-1 overflow-y-auto overscroll-contain",children:Ue&&!h&&!E.length&&!i?n.jsx("div",{className:"flex items-center justify-center py-20",children:n.jsx(Ce,{className:"h-5 w-5 text-fg-4"})}):gt.length===0&&!h&&!E.length&&!i&&!Ve?n.jsx("div",{className:"py-20 text-center text-[13px] text-fg-5",children:p("hub.noMessages")}):n.jsxs("div",{className:"max-w-[900px] mx-auto px-6 py-6 space-y-0",children:[(c?.hasOlder||ie)&&n.jsxs("div",{className:"mb-4 flex items-center justify-center gap-2 text-[11px] text-fg-5",children:[ie?n.jsx(Ce,{className:"h-3 w-3 text-fg-5"}):n.jsx("span",{className:"h-1.5 w-1.5 rounded-full bg-fg-5/35"}),n.jsx("span",{children:p(ie?"hub.loadingOlderTurns":"hub.loadOlderTurnsHint")})]}),r.migratedFrom?.kind==="fork"&&r.migratedFrom.sessionId&&n.jsxs("button",{type:"button",onClick:()=>v?.({agent:r.migratedFrom.agent||r.agent||"",sessionId:r.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:`#${r.migratedFrom.sessionId.slice(0,8)}`,children:[n.jsxs("svg",{width:"10",height:"10",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",children:[n.jsx("circle",{cx:"6",cy:"6",r:"2"}),n.jsx("circle",{cx:"18",cy:"6",r:"2"}),n.jsx("circle",{cx:"12",cy:"20",r:"2"}),n.jsx("path",{d:"M6 8v3a3 3 0 0 0 3 3h6a3 3 0 0 0 3-3V8"}),n.jsx("path",{d:"M12 14v4"})]}),n.jsx("span",{children:p("hub.forkBadge")}),n.jsxs("span",{className:"font-mono",children:["#",r.migratedFrom.sessionId.slice(0,8)]}),typeof r.migratedFrom.forkedAtTurn=="number"&&n.jsxs("span",{className:"text-fg-5/70",children:["· ",p("hub.forkBadgeAt").replace("{turn}",String(r.migratedFrom.forkedAtTurn+1))]})]}),gt.map((e,s)=>{const l=(c?.startTurn||0)+s;return n.jsx(tr,{turn:e,turnIndex:l,agent:r.agent||"",meta:ue,model:ft,effort:Ge,providerName:Ie,t:p,workdir:f,onResend:o=>{J.current=!0,it(o);const d=ct.current;j.sendSessionMessage(f,r.agent||"",r.sessionId,o,{model:d.model||be||void 0,effort:d.effort||Ge||void 0}).then(x=>{x.ok&&dt()}).catch(()=>{w()})},onEdit:o=>ot(o),onFork:jt?o=>{De(""),pe({atTurn:o})}:void 0},`${c?.startTurn||0}:${s}`)}),Ve&&n.jsx("div",{className:"mb-5 animate-in",children:n.jsx(rr,{detail:Ve,t:p})}),(h||mt.length>0)&&(Je||!(h&&T.length>0&&tt(T[T.length-1]?.user?.text,h)))&&n.jsxs("div",{className:"session-turn",children:[n.jsx(ht,{text:h||"",blocks:mt,t:p}),!i&&n.jsx("div",{className:"mt-3 mb-5 animate-in",children:n.jsx(nr,{className:"text-fg-5"})})]}),i&&xt(i)&&!h&&i.question&&!(T.length>0&&tt(T[T.length-1]?.user?.text,i.question))&&n.jsx("div",{className:"session-turn",children:n.jsx(ht,{text:i.question,blocks:i.questionBlocks||void 0,t:p})}),i&&xt(i)&&n.jsxs("div",{className:"mb-6",children:[n.jsx(sr,{agent:r.agent||"",meta:ue,model:ft,effort:Ge,providerName:Ie,previewMeta:i.previewMeta,hideContextUsage:!0}),n.jsx(lr,{stream:i,t:p,workdir:f})]}),n.jsx("div",{className:"h-4"})]})}),n.jsx(ar,{session:r,workdir:f,onStreamQueued:dt,onSendStart:it,onSendTaskAssigned:Nt,onSessionChange:v,t:p,streamPhase:z,streamTaskId:vt,queuedTaskIds:W,queuedTasks:yt,pendingQueuedSends:at,onRecall:Ot,onSteer:Lt,onStopAll:Mt,editDraft:Rt,onEditDraftConsumed:()=>ot(null),onSelectionChange:wt}),je&&n.jsxs(St,{open:!0,onClose:()=>{H||pe(null)},children:[n.jsx(bt,{title:p("hub.forkPromptTitle"),description:p("hub.forkPromptHint"),onClose:()=>{H||pe(null)}}),n.jsx("textarea",{autoFocus:!0,value:he,disabled:H,onChange:e=>De(e.target.value),onKeyDown:e=>{e.key==="Enter"&&(e.metaKey||e.ctrlKey)&&he.trim()&&!H&&(e.preventDefault(),_e.current?.())},placeholder:p("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"}),n.jsxs("div",{className:"mt-4 flex items-center justify-end gap-2",children:[n.jsx(Pe,{variant:"ghost",disabled:H,onClick:()=>pe(null),children:p("modal.cancel")}),n.jsx(Pe,{variant:"primary",disabled:H||!he.trim(),onClick:()=>{_e.current?.()},children:p(H?"hub.forkSubmitting":"hub.forkSubmit")})]})]}),O&&me.length>0&&n.jsx(or,{snapshot:me[me.length-1]},me[me.length-1].promptId)]})});export{Ar as SessionPanel};