pikiloom 0.4.39 → 0.4.40
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-Ds8D6yrl.js → AgentTab-Cj7sekcS.js} +1 -1
- package/dashboard/dist/assets/{ConnectionModal-Buj2d5L5.js → ConnectionModal-g_6IHAWE.js} +1 -1
- package/dashboard/dist/assets/{DirBrowser-BTv7rH8E.js → DirBrowser-DVe6q12N.js} +1 -1
- package/dashboard/dist/assets/{ExtensionsTab-BnGwxS9U.js → ExtensionsTab-GqxD61Pp.js} +1 -1
- package/dashboard/dist/assets/{IMAccessTab-DjQnpOmF.js → IMAccessTab-DIqTzZJ9.js} +1 -1
- package/dashboard/dist/assets/{Modal-DpuinsE3.js → Modal-CIYrMwm0.js} +1 -1
- package/dashboard/dist/assets/{Modals-Bs842H3n.js → Modals-B-Afu2rD.js} +1 -1
- package/dashboard/dist/assets/{Select-Dvia29HZ.js → Select-B1UL27gw.js} +1 -1
- package/dashboard/dist/assets/SessionPanel-BHuG5hxj.js +1 -0
- package/dashboard/dist/assets/{SystemTab-BzPtwDxq.js → SystemTab-Bv1uT5-h.js} +1 -1
- package/dashboard/dist/assets/{index-S0NmlDEH.js → index-BOEW0RIx.js} +13 -13
- package/dashboard/dist/assets/{index-yZ-iG1qk.js → index-qKexKdJl.js} +3 -3
- package/dashboard/dist/assets/{shared-p3kZpiD4.js → shared-624PaUfm.js} +1 -1
- package/dashboard/dist/index.html +1 -1
- package/dist/agent/drivers/codex.js +5 -3
- package/dist/agent/index.js +1 -1
- package/dist/agent/stream.js +13 -1
- package/dist/dashboard/routes/agents.js +8 -4
- package/package.json +1 -1
- package/packages/kernel/dist/drivers/claude.js +17 -0
- package/packages/kernel/dist/drivers/codex.d.ts +18 -1
- package/packages/kernel/dist/drivers/codex.js +83 -7
- package/dashboard/dist/assets/SessionPanel-CVItEgcH.js +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
import{j as s}from"./react-vendor-C7Sl8SE7.js";import{N as t,m as i,S as a}from"./index-
|
|
1
|
+
import{j as s}from"./react-vendor-C7Sl8SE7.js";import{N as t,m as i,S as a}from"./index-qKexKdJl.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-qKexKdJl.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-Bthwt6K_.css">
|
|
@@ -34,9 +34,11 @@ export class CodexAppServer {
|
|
|
34
34
|
return new Promise((resolve) => {
|
|
35
35
|
const timer = setTimeout(() => { this.kill(); resolve(false); }, CODEX_APPSERVER_SPAWN_TIMEOUT_MS);
|
|
36
36
|
const args = ['app-server'];
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
// Do NOT force model_reasoning_summary — reasoning summaries stay OFF by default (respecting
|
|
38
|
+
// ~/.codex/config.toml = original behavior). A caller wanting thinking passes it via configOverrides.
|
|
39
|
+
const overrides = [...this.configOverrides];
|
|
40
|
+
if (!overrides.some(entry => /^features\.goals\s*=/.test(entry)))
|
|
41
|
+
overrides.push('features.goals=true');
|
|
40
42
|
for (const c of overrides)
|
|
41
43
|
args.push('-c', c);
|
|
42
44
|
agentLog(`[codex-rpc] spawning: codex ${args.join(' ')}`);
|
package/dist/agent/index.js
CHANGED
|
@@ -7,7 +7,7 @@ export { attachAgentImage, attachInlineImage, materializeImage, rewriteAttachmen
|
|
|
7
7
|
export { deliverArtifact, readDeliveredArtifacts, deliveredArtifactBlocks, tailDeliveredBlocks, latestDeliveredTaskId, mimeForArtifact, } from './artifacts.js';
|
|
8
8
|
export { Q, agentLog, agentWarn, agentError, dedupeStrings, numberOrNull, normalizeStreamPreviewPlan, parseTodoWriteAsPlan, normalizeActivityLine, pushRecentActivity, detectClaudeApiError, isRetryableClaudeApiError, detectClaudeModelError, claudeModelErrorMessage, firstNonEmptyLine, shortValue, normalizeErrorMessage, joinErrorMessages, appendSystemPrompt, mimeForExt, computeContext, buildStreamPreviewMeta, summarizeClaudeToolUse, summarizeClaudeToolResult, previewToolCallInput, previewToolCallResult, roundPercent, toIsoFromEpochSeconds, normalizeUsageStatus, labelFromWindowMinutes, usageWindowFromRateLimit, parseJsonTail, modelFamily, normalizeClaudeModelId, emptyUsage, readTailLines, stripInjectedPrompts, sanitizeSessionUserPreviewText, SESSION_PREVIEW_IMAGE_PLACEHOLDER_RE, CLAUDE_AT_MENTION_IMAGE_RE, extractClaudeAtMentionImagePaths, stripClaudeAtMentionImages, isPendingSessionId, emitSessionIdUpdate, sessionListDisplayTitle, } from './utils.js';
|
|
9
9
|
export { updateSessionMeta, promoteSessionId, recordFork, resolveCanonicalSessionId, getSessionPromotions, listPikiloomSessions, findPikiloomSession, getSessionStoredConfig, ensureManagedSession, findManagedThreadSession, stageSessionFiles, mergeManagedAndNativeSessions, managedRecordToSessionInfo, getSessions, getSessionTail, getSessionMessages, applyTurnWindow, applyTurnFilter, classifySession, deriveUserStatus, exportSession, importSession, deleteAgentSession, isProcessAlive, isRunningSessionStale, reconcileOrphanedRunningSessions, } from './session.js';
|
|
10
|
-
export { detectAgentBin, listAgents, resolveDefaultAgent, run, doStream, recoverProfileIdForModel, listModels, resolveAgentModels, getUsage, getAgentBoundModelId, setAgentBoundModelId, } from './stream.js';
|
|
10
|
+
export { detectAgentBin, listAgents, resolveDefaultAgent, run, doStream, recoverProfileIdForModel, listModels, resolveAgentModels, dropNativeShadowedByProfiles, getUsage, getAgentBoundModelId, setAgentBoundModelId, } from './stream.js';
|
|
11
11
|
export { registerDriver, getDriver, getDriverCapabilities, allDrivers, allDriverIds, hasDriver, shutdownAllDrivers, } from './driver.js';
|
|
12
12
|
export { getProjectSkillPaths, initializeProjectSkills, listSkills, getGlobalSkillsRoot, collapseSkillPrompt, } from './skills.js';
|
|
13
13
|
export { readGoal, writeGoal, clearGoal, setGoal, pauseGoal, resumeGoal, completeGoal, accountTurn, bumpContinuationCount, shouldContinueAfterTurn, renderContinuationPrompt, renderBudgetLimitPrompt, sessionGoalPath, DEFAULT_MAX_CONTINUATIONS, } from './goal.js';
|
package/dist/agent/stream.js
CHANGED
|
@@ -658,6 +658,17 @@ export function listModels(agent, opts = {}) {
|
|
|
658
658
|
function isLocalProviderBaseURL(baseURL) {
|
|
659
659
|
return /^https?:\/\/(localhost|127\.0\.0\.1|0\.0\.0\.0|\[::1\])(?::|\/|$)/i.test(baseURL);
|
|
660
660
|
}
|
|
661
|
+
// A model surfaced as a BYOK profile must NOT also appear under the native group. Drivers seed
|
|
662
|
+
// their native list with the active model (via opts.currentModel) so it stays visible — but when
|
|
663
|
+
// a BYOK profile is active that "current model" is the profile's third-party model (e.g. a 豆包 /
|
|
664
|
+
// deepseek id), which then wrongly shows up as an "official / 官方 / Native" model. The profile row
|
|
665
|
+
// already represents it, so drop any native entry shadowed by a profile id.
|
|
666
|
+
export function dropNativeShadowedByProfiles(native, profileRows) {
|
|
667
|
+
if (!profileRows.length)
|
|
668
|
+
return native;
|
|
669
|
+
const shadowed = new Set(profileRows.map(m => m.id.trim().toLowerCase()).filter(Boolean));
|
|
670
|
+
return native.filter(m => !shadowed.has(m.id.trim().toLowerCase()));
|
|
671
|
+
}
|
|
661
672
|
export async function resolveAgentModels(agent, opts = {}) {
|
|
662
673
|
const driver = getDriver(agent);
|
|
663
674
|
let nativeResult;
|
|
@@ -667,7 +678,7 @@ export async function resolveAgentModels(agent, opts = {}) {
|
|
|
667
678
|
catch {
|
|
668
679
|
nativeResult = { agent, models: [], sources: [], note: null };
|
|
669
680
|
}
|
|
670
|
-
const
|
|
681
|
+
const nativeRaw = nativeResult.models.map(m => ({
|
|
671
682
|
id: m.id,
|
|
672
683
|
alias: m.alias,
|
|
673
684
|
group: 'native',
|
|
@@ -693,6 +704,7 @@ export async function resolveAgentModels(agent, opts = {}) {
|
|
|
693
704
|
(isLocal ? local : cloud).push(entry);
|
|
694
705
|
}
|
|
695
706
|
}
|
|
707
|
+
const native = dropNativeShadowedByProfiles(nativeRaw, [...cloud, ...local]);
|
|
696
708
|
const sources = [...nativeResult.sources];
|
|
697
709
|
if (cloud.length)
|
|
698
710
|
sources.push(`${cloud.length} cloud profile${cloud.length === 1 ? '' : 's'}`);
|
|
@@ -137,6 +137,11 @@ async function buildAgentStatusResponse(config = loadUserConfig(), agentOptions
|
|
|
137
137
|
}
|
|
138
138
|
const runtimeSelectedModel = runtime.getRuntimeModel(agentId, config);
|
|
139
139
|
const runtimeSelectedEffort = runtime.getRuntimeEffort(agentId, config);
|
|
140
|
+
const activeProfile = getActiveProfile(agentId);
|
|
141
|
+
// runtimeSelectedModel is the model that will RUN (profile-aware): when a BYOK profile is
|
|
142
|
+
// bound it is the profile's third-party model. The NATIVE model list must not be seeded with
|
|
143
|
+
// it, else it shows under the "官方 / Native" group (it is surfaced separately via byokModels).
|
|
144
|
+
const nativeRuntimeModel = activeProfile ? '' : runtimeSelectedModel;
|
|
140
145
|
let models = [];
|
|
141
146
|
let usage = emptyUsage(agentId, 'Agent not installed.');
|
|
142
147
|
let nativeConfig = null;
|
|
@@ -149,10 +154,10 @@ async function buildAgentStatusResponse(config = loadUserConfig(), agentOptions
|
|
|
149
154
|
}
|
|
150
155
|
catch { }
|
|
151
156
|
}
|
|
152
|
-
const modelFallback =
|
|
157
|
+
const modelFallback = nativeRuntimeModel ? [{ id: nativeRuntimeModel, alias: null }] : [];
|
|
153
158
|
const cachedUsage = driver.getUsage({ agent: agentId, model: runtimeSelectedModel });
|
|
154
159
|
const [resolvedModels, resolvedUsage] = await Promise.all([
|
|
155
|
-
withTimeoutFallback(driver.listModels({ workdir, currentModel:
|
|
160
|
+
withTimeoutFallback(driver.listModels({ workdir, currentModel: nativeRuntimeModel || undefined }).then(result => dedupeModels([
|
|
156
161
|
...modelFallback,
|
|
157
162
|
...result.models,
|
|
158
163
|
])), AGENT_STATUS_MODELS_TIMEOUT_MS, modelFallback),
|
|
@@ -169,14 +174,13 @@ async function buildAgentStatusResponse(config = loadUserConfig(), agentOptions
|
|
|
169
174
|
}
|
|
170
175
|
}
|
|
171
176
|
const updateState = getAgentUpdateState(agentId);
|
|
172
|
-
const activeProfile = getActiveProfile(agentId);
|
|
173
177
|
const byokProvider = activeProfile ? getProvider(activeProfile.providerId) : null;
|
|
174
178
|
const byokProviderName = byokProvider?.name || null;
|
|
175
179
|
const byokProfileName = activeProfile
|
|
176
180
|
&& activeProfile.name.trim().toLowerCase() !== activeProfile.modelId.trim().toLowerCase()
|
|
177
181
|
? activeProfile.name
|
|
178
182
|
: null;
|
|
179
|
-
const nativeSelectedModel =
|
|
183
|
+
const nativeSelectedModel = nativeRuntimeModel || nativeConfig?.model || null;
|
|
180
184
|
const nativeSelectedEffort = runtimeSelectedEffort || nativeConfig?.effort || null;
|
|
181
185
|
const selectedModel = activeProfile?.modelId || nativeSelectedModel;
|
|
182
186
|
const selectedEffort = activeProfile?.effort || nativeSelectedEffort;
|
package/package.json
CHANGED
|
@@ -232,6 +232,23 @@ export function handleClaudeEvent(ev, s, emit) {
|
|
|
232
232
|
s.cacheCreation = u?.cache_creation_input_tokens ?? 0;
|
|
233
233
|
s.output = 0;
|
|
234
234
|
}
|
|
235
|
+
else if (inner.type === 'content_block_start') {
|
|
236
|
+
// Claude emits multiple text/thinking blocks per turn (one set per tool-use round). Insert a
|
|
237
|
+
// paragraph break before a NEW block when prior content exists, so the live preview shows
|
|
238
|
+
// breaks between segments instead of running them together. Mirrors the legacy driver; the
|
|
239
|
+
// separator is emitted as a delta so the runtime's accumulated snapshot stays in sync with s.
|
|
240
|
+
const bt = inner.content_block?.type;
|
|
241
|
+
if (bt === 'text' && s.text && !s.text.endsWith('\n\n')) {
|
|
242
|
+
const sep = s.text.endsWith('\n') ? '\n' : '\n\n';
|
|
243
|
+
s.text += sep;
|
|
244
|
+
emit({ type: 'text', delta: sep });
|
|
245
|
+
}
|
|
246
|
+
else if (bt === 'thinking' && s.reasoning && !s.reasoning.endsWith('\n\n')) {
|
|
247
|
+
const sep = s.reasoning.endsWith('\n') ? '\n' : '\n\n';
|
|
248
|
+
s.reasoning += sep;
|
|
249
|
+
emit({ type: 'reasoning', delta: sep });
|
|
250
|
+
}
|
|
251
|
+
}
|
|
235
252
|
else if (inner.type === 'content_block_delta') {
|
|
236
253
|
const d = inner.delta || {};
|
|
237
254
|
if (d.type === 'text_delta' && d.text) {
|
|
@@ -1,5 +1,22 @@
|
|
|
1
|
-
import type { AgentDriver, AgentTurnInput, DriverContext, DriverResult, TuiInput, TuiSpec } from '../contracts/driver.js';
|
|
1
|
+
import type { AgentDriver, AgentTurnInput, DriverContext, DriverEvent, DriverResult, TuiInput, TuiSpec } from '../contracts/driver.js';
|
|
2
2
|
import type { UniversalUsage } from '../protocol/index.js';
|
|
3
|
+
export declare function codexToolSummary(item: any): {
|
|
4
|
+
id: string;
|
|
5
|
+
name: string;
|
|
6
|
+
summary: string;
|
|
7
|
+
} | null;
|
|
8
|
+
export interface CodexContentState {
|
|
9
|
+
text: string;
|
|
10
|
+
reasoning: string;
|
|
11
|
+
streamedReasoning: boolean;
|
|
12
|
+
msgs: string[];
|
|
13
|
+
thinkParts: string[];
|
|
14
|
+
}
|
|
15
|
+
export declare function codexReasoningItemText(item: any): string;
|
|
16
|
+
export declare function captureCodexAgentMessage(item: any, s: CodexContentState, deltaItems: Set<string>, phases: Map<string, string>, emit: (e: DriverEvent) => void): void;
|
|
17
|
+
export declare function captureCodexReasoning(text: string, s: CodexContentState, emit: (e: DriverEvent) => void): void;
|
|
18
|
+
export declare function codexFinalText(s: CodexContentState): string;
|
|
19
|
+
export declare function codexFinalReasoning(s: CodexContentState): string;
|
|
3
20
|
export declare class CodexDriver implements AgentDriver {
|
|
4
21
|
private readonly bin;
|
|
5
22
|
readonly id = "codex";
|
|
@@ -20,7 +20,12 @@ class AppServer {
|
|
|
20
20
|
onServerRequest(cb) { this.requestResponder = cb; }
|
|
21
21
|
async start() {
|
|
22
22
|
const args = ['app-server'];
|
|
23
|
-
|
|
23
|
+
// Do NOT force model_reasoning_summary — codex reasoning summaries stay OFF by default
|
|
24
|
+
// (respecting ~/.codex/config.toml, which is the original behavior). A caller that wants
|
|
25
|
+
// thinking can pass `model_reasoning_summary=...` via configOverrides; we never inject it.
|
|
26
|
+
const overrides = [...this.configOverrides];
|
|
27
|
+
if (!overrides.some(c => /^features\.goals\s*=/.test(c)))
|
|
28
|
+
overrides.push('features.goals=true');
|
|
24
29
|
for (const c of overrides)
|
|
25
30
|
args.push('-c', c);
|
|
26
31
|
try {
|
|
@@ -126,7 +131,12 @@ function codexFileChangeSummary(item) {
|
|
|
126
131
|
}
|
|
127
132
|
// Normalize a codex app-server item -> {id, name, summary}. The summary mirrors pikiloom's
|
|
128
133
|
// vocabulary ("Run shell: <cmd>", "Edit <path>") so the activity projection reads naturally.
|
|
129
|
-
|
|
134
|
+
// Only ACTUAL tool calls become Activity rows. agentMessage (the answer text) and reasoning
|
|
135
|
+
// (thinking) are CONTENT — they render below as message text / thinking, never as tools. The old
|
|
136
|
+
// fallback to `item.type` wrongly turned every item (incl. agentMessage/reasoning) into a bogus
|
|
137
|
+
// "tool" in the Activity card. Mirrors the legacy driver's isCodexToolCallItem whitelist.
|
|
138
|
+
const CODEX_TOOL_CALL_TYPES = new Set(['dynamicToolCall', 'mcpToolCall', 'collabAgentToolCall']);
|
|
139
|
+
export function codexToolSummary(item) {
|
|
130
140
|
const id = String(item?.id || '');
|
|
131
141
|
if (!id)
|
|
132
142
|
return null;
|
|
@@ -136,8 +146,13 @@ function codexToolSummary(item) {
|
|
|
136
146
|
}
|
|
137
147
|
if (item.type === 'fileChange' || item.type === 'patch')
|
|
138
148
|
return { id, name: 'edit', summary: codexFileChangeSummary(item) };
|
|
139
|
-
|
|
140
|
-
|
|
149
|
+
if (CODEX_TOOL_CALL_TYPES.has(item.type)) {
|
|
150
|
+
const raw = typeof item.tool === 'string' && item.tool.trim() ? item.tool.trim()
|
|
151
|
+
: typeof item.name === 'string' && item.name.trim() ? item.name.trim() : '';
|
|
152
|
+
const name = raw ? (raw.split('.').pop() || raw) : 'tool';
|
|
153
|
+
return { id, name, summary: raw ? `Use ${name}` : 'Use tool' };
|
|
154
|
+
}
|
|
155
|
+
return null;
|
|
141
156
|
}
|
|
142
157
|
// codex `item/tool/requestUserInput` params -> a normalized UniversalInteraction
|
|
143
158
|
// (faithful to the legacy codex driver's toAgentInteraction shape).
|
|
@@ -160,6 +175,51 @@ function codexUserInputToInteraction(params, promptId) {
|
|
|
160
175
|
return null;
|
|
161
176
|
return { promptId, kind: 'user-input', title: 'User Input Required', hint: 'Use the buttons when available, or reply with text.', questions };
|
|
162
177
|
}
|
|
178
|
+
// Reasoning text from a completed `reasoning` item (item/completed or rawResponseItem/completed):
|
|
179
|
+
// summary/content arrays of plain strings or {text} objects.
|
|
180
|
+
export function codexReasoningItemText(item) {
|
|
181
|
+
const parts = [
|
|
182
|
+
...(Array.isArray(item?.summary) ? item.summary : []),
|
|
183
|
+
...(Array.isArray(item?.content) ? item.content : []),
|
|
184
|
+
];
|
|
185
|
+
return parts.map((p) => (typeof p === 'string' ? p : p?.text || '')).filter(Boolean).join('\n').trim();
|
|
186
|
+
}
|
|
187
|
+
// A completed final_answer agentMessage that did NOT stream deltas: append + emit it live.
|
|
188
|
+
// deltaItems holds the ids already streamed, so a completed item echoing a streamed one is
|
|
189
|
+
// not double-counted (matches the legacy driver's deltaSeenForItem guard).
|
|
190
|
+
export function captureCodexAgentMessage(item, s, deltaItems, phases, emit) {
|
|
191
|
+
const phase = item?.phase || (item?.id ? phases.get(item.id) : null) || 'final_answer';
|
|
192
|
+
if (phase !== 'final_answer')
|
|
193
|
+
return;
|
|
194
|
+
const text = typeof item?.text === 'string' ? item.text.trim() : '';
|
|
195
|
+
if (!text)
|
|
196
|
+
return;
|
|
197
|
+
s.msgs.push(text);
|
|
198
|
+
if (item.id && deltaItems.has(item.id))
|
|
199
|
+
return;
|
|
200
|
+
const delta = s.text.trim() ? `\n\n${text}` : text;
|
|
201
|
+
s.text += delta;
|
|
202
|
+
emit({ type: 'text', delta });
|
|
203
|
+
}
|
|
204
|
+
// A completed reasoning item: keep it for the end-of-turn fallback, and stream it live only
|
|
205
|
+
// when nothing arrived as reasoning deltas (so the streamed path is never double-emitted).
|
|
206
|
+
export function captureCodexReasoning(text, s, emit) {
|
|
207
|
+
if (!text)
|
|
208
|
+
return;
|
|
209
|
+
s.thinkParts.push(text);
|
|
210
|
+
if (s.streamedReasoning)
|
|
211
|
+
return;
|
|
212
|
+
const delta = s.reasoning.trim() ? `\n\n${text}` : text;
|
|
213
|
+
s.reasoning += delta;
|
|
214
|
+
emit({ type: 'reasoning', delta });
|
|
215
|
+
}
|
|
216
|
+
// End-of-turn finalizers: prefer streamed text/reasoning, fall back to completed-item parts.
|
|
217
|
+
export function codexFinalText(s) {
|
|
218
|
+
return s.text.trim() ? s.text : s.msgs.join('\n\n');
|
|
219
|
+
}
|
|
220
|
+
export function codexFinalReasoning(s) {
|
|
221
|
+
return s.reasoning.trim() ? s.reasoning : s.thinkParts.join('\n\n');
|
|
222
|
+
}
|
|
163
223
|
export class CodexDriver {
|
|
164
224
|
bin;
|
|
165
225
|
id = 'codex';
|
|
@@ -173,9 +233,10 @@ export class CodexDriver {
|
|
|
173
233
|
// to the native account.
|
|
174
234
|
const config = [...(input.configOverrides || [])];
|
|
175
235
|
const srv = new AppServer(this.bin, config, input.env);
|
|
176
|
-
const state = { text: '', reasoning: '', sessionId: input.sessionId ?? null, input: null, output: null, cached: null, contextUsed: null, contextWindow: null, status: null, error: null, turnId: null };
|
|
236
|
+
const state = { text: '', reasoning: '', streamedReasoning: false, msgs: [], thinkParts: [], sessionId: input.sessionId ?? null, input: null, output: null, cached: null, contextUsed: null, contextWindow: null, status: null, error: null, turnId: null };
|
|
177
237
|
const phases = new Map();
|
|
178
238
|
const toolSummaries = new Map();
|
|
239
|
+
const deltaItems = new Set();
|
|
179
240
|
let steerRegistered = false;
|
|
180
241
|
const ok = await srv.start();
|
|
181
242
|
if (!ok)
|
|
@@ -239,6 +300,8 @@ export class CodexDriver {
|
|
|
239
300
|
const phase = params?.itemId ? (phases.get(params.itemId) || 'final_answer') : 'final_answer';
|
|
240
301
|
if (phase === 'final_answer' && params?.delta) {
|
|
241
302
|
state.text += params.delta;
|
|
303
|
+
if (params.itemId)
|
|
304
|
+
deltaItems.add(params.itemId);
|
|
242
305
|
ctx.emit({ type: 'text', delta: params.delta });
|
|
243
306
|
}
|
|
244
307
|
break;
|
|
@@ -247,16 +310,28 @@ export class CodexDriver {
|
|
|
247
310
|
case 'item/reasoning/summaryTextDelta':
|
|
248
311
|
if (params?.delta) {
|
|
249
312
|
state.reasoning += params.delta;
|
|
313
|
+
state.streamedReasoning = true;
|
|
250
314
|
ctx.emit({ type: 'reasoning', delta: params.delta });
|
|
251
315
|
}
|
|
252
316
|
break;
|
|
253
317
|
case 'item/completed': {
|
|
254
318
|
const item = params?.item || {};
|
|
319
|
+
// Final answer / reasoning delivered as a completed item (no preceding deltas).
|
|
320
|
+
if (item.type === 'agentMessage')
|
|
321
|
+
captureCodexAgentMessage(item, state, deltaItems, phases, ctx.emit);
|
|
322
|
+
else if (item.type === 'reasoning')
|
|
323
|
+
captureCodexReasoning(codexReasoningItemText(item), state, ctx.emit);
|
|
255
324
|
const t = codexToolSummary(item);
|
|
256
325
|
if (t && toolSummaries.has(t.id))
|
|
257
326
|
ctx.emit({ type: 'tool', call: { id: t.id, name: t.name, summary: toolSummaries.get(t.id) || t.summary, status: item.status === 'failed' ? 'failed' : 'done' } });
|
|
258
327
|
break;
|
|
259
328
|
}
|
|
329
|
+
case 'rawResponseItem/completed': {
|
|
330
|
+
const item = params?.item || {};
|
|
331
|
+
if (item?.type === 'reasoning')
|
|
332
|
+
captureCodexReasoning(codexReasoningItemText(item), state, ctx.emit);
|
|
333
|
+
break;
|
|
334
|
+
}
|
|
260
335
|
case 'turn/plan/updated': {
|
|
261
336
|
const plan = planFromUpdate(params);
|
|
262
337
|
if (plan)
|
|
@@ -307,10 +382,11 @@ export class CodexDriver {
|
|
|
307
382
|
await turnDone;
|
|
308
383
|
const usage = codexUsageOf(state);
|
|
309
384
|
const ok2 = (state.status === 'completed' || state.status == null) && !state.error && !ctx.signal.aborted;
|
|
385
|
+
const finalReasoning = codexFinalReasoning(state);
|
|
310
386
|
return {
|
|
311
387
|
ok: ok2,
|
|
312
|
-
text: state
|
|
313
|
-
reasoning:
|
|
388
|
+
text: codexFinalText(state),
|
|
389
|
+
reasoning: finalReasoning || undefined,
|
|
314
390
|
error: state.error || (ctx.signal.aborted ? 'Interrupted by user.' : null),
|
|
315
391
|
stopReason: ctx.signal.aborted ? 'interrupted' : (state.status || 'end_turn'),
|
|
316
392
|
sessionId: state.sessionId,
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{r as t,j as n}from"./react-vendor-C7Sl8SE7.js";import{c as Lt,I as Ct,S as Le,m as Ce,a as w,u as ct,d as Pt,g as Ut,l as qt,e as Ft,j as Ht,f as Dt,s as Qt,X as _t}from"./index-yZ-iG1qk.js";import{s as $t,l as Bt,n as it,m as Kt,a as zt,o as Wt,d as Xt,b as Yt,p as Gt,c as dt,e as Ge,T as Vt,R as Jt,U as ft,f as Zt,g as mt,h as er,L as tr,I as rr}from"./index-S0NmlDEH.js";import{M as pt,a as ht}from"./Modal-DpuinsE3.js";import"./router-DHISdpPk.js";import"./Select-Dvia29HZ.js";import"./DirBrowser-BTv7rH8E.js";import"./markdown-DxQYQFeH.js";import"./ExtensionsTab-BnGwxS9U.js";function nr({snapshot:a}){const[r,d]=t.useState(a.currentIndex??0),[M,v]=t.useState(""),[k,p]=t.useState(!1),[L,S]=t.useState(null);t.useEffect(()=>{d(a.currentIndex??0),v(""),S(null)},[a.promptId,a.currentIndex]);const E=a.questions||[],T=E[r]||null,z=E.length,C=!!(T?.options&&T.options.length),oe=C?!!T?.allowFreeform:!0,f=u=>{u&&(d(h=>h+1),v(""))},ye=async u=>{if(!k){p(!0),S(null);try{const h=await w.interactionSelectOption(a.promptId,u);if(!h.ok){S(h.error||"Failed to submit selection.");return}f(h.advanced)}catch(h){S(h?.message||"Network error.")}finally{p(!1)}}},ue=async()=>{if(k)return;const u=M.trim();if(!u&&!T?.allowEmpty){S("Please enter a response.");return}p(!0),S(null);try{const h=await w.interactionSubmitText(a.promptId,u);if(!h.ok){S(h.error||"Failed to submit answer.");return}f(h.advanced)}catch(h){S(h?.message||"Network error.")}finally{p(!1)}},q=async()=>{if(!k){p(!0),S(null);try{const u=await w.interactionSkip(a.promptId);if(!u.ok){S(u.error||"Failed to skip.");return}f(u.advanced)}catch(u){S(u?.message||"Network error.")}finally{p(!1)}}},m=async()=>{if(!k){p(!0);try{await w.interactionCancel(a.promptId)}catch{}}},ce=t.useMemo(()=>{const u=[];return a.hint&&u.push(a.hint),z>1&&u.push(`Question ${r+1} of ${z}`),u.join(" · ")||void 0},[a.hint,r,z]);return n.jsxs(pt,{open:!0,onClose:m,wide:C&&(T?.options?.length||0)>3,children:[n.jsx(ht,{title:a.title||"Pikiloom needs your input",description:ce,onClose:m}),T?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:T.header||"Question"}),n.jsx("div",{className:"mt-1 whitespace-pre-wrap text-sm leading-relaxed text-fg",children:T.prompt})]}),C&&n.jsx("div",{className:"grid grid-cols-1 gap-2 sm:grid-cols-2",children:(T.options||[]).map(u=>n.jsxs("button",{type:"button",disabled:k,onClick:()=>ye(u.value||u.label),className:Lt("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))}),oe&&n.jsx("div",{children:n.jsx(Ct,{value:M,onChange:u=>v(u.target.value),onKeyDown:u=>{u.key==="Enter"&&!u.shiftKey&&!k&&(u.preventDefault(),ue())},placeholder:C?"Or type a custom answer…":"Type your answer…",disabled:k,autoFocus:!C})}),L&&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:L}),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(Le,{})," 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(Ce,{variant:"ghost",size:"sm",onClick:q,disabled:k,children:"Skip"}),oe&&n.jsx(Ce,{variant:"primary",size:"sm",onClick:ue,disabled:k||!M.trim()&&!T.allowEmpty,children:"Submit"})]})]})]}):n.jsxs("div",{className:"py-6 text-center text-sm text-fg-5",children:[n.jsx(Le,{className:"mr-2 inline-block"})," Waiting for the agent…"]})]})}function sr(a){return a.isNull?a.localStreamPending||a.holdsActiveState?"reject-null":"apply":(typeof a.updatedAt=="number"?a.updatedAt:0)<a.lastAppliedUpdatedAt?"reject-stale":"apply"}function lr(a,r){return typeof r!="number"?a:r>a?r:a}function ar(a,r){return!a||!a.length?[]:r.size?a.filter(d=>!r.has(d)):a.slice()}function or(a,r,d,M){if(!a.size)return a;const v=new Set(r);let k=!1;const p=new Map;for(const[L,S]of a){if(d-S>M||!v.has(L)){k=!0;continue}p.set(L,S)}return k?p:a}const Ve=12,gt=160,ur=96,cr=[],ir=[],dr=[],fr=20,mr=6e4,ae=new Map;function gr(a,r){return`${a}:${r}`}function pr(a,r){for(ae.delete(a),ae.set(a,r);ae.size>fr;)ae.delete(ae.keys().next().value)}const Rr=t.memo(function({session:r,workdir:d,active:M=!0,onSessionChange:v,initialPendingPrompt:k,initialPendingImageUrls:p,onPendingPromptConsumed:L}){const S=ct(e=>e.locale),E=ct(e=>e.agentStatus?.agents?.find(s=>s.agent===r.agent)??null),T=E?.selectedEffort??null,z=E?.selectedModel??null,C=E?.byokProviderName??null,oe=E?.byokProfileName??null,f=t.useMemo(()=>Pt(S),[S]),ye=Ut(r.agent||""),ue=qt(r),q=!!k||!!(p&&p.length),[m,ce]=t.useState(null),[u,h]=t.useState(!q),[ie,Je]=t.useState(!1),[i,F]=t.useState(null),[de,fe]=t.useState(!1),[W,Pe]=t.useState(null),[xt,Ze]=t.useState(0),[kt,Ue]=t.useState(null),[X,Ie]=t.useState([]),[St,ve]=t.useState([]),[me,qe]=t.useState([]),[b,Y]=t.useState(k||null),[P,G]=t.useState(p||[]),[bt,V]=t.useState(null),H=t.useRef(null);H.current=bt;const et=t.useRef(b);et.current=b;const[tt,U]=t.useState([]),Te=t.useRef([]);Te.current=tt;const ge=t.useRef(null),[yt,rt]=t.useState(null),[Re,pe]=t.useState(null),[he,Fe]=t.useState(""),[D,He]=t.useState(!1),It=!!E?.capabilities?.fork,De=t.useRef(null),O=t.useRef(p||[]),Q=t.useRef(i),Qe=t.useRef(de);Q.current=i,Qe.current=de;const _e=t.useRef(X);_e.current=X;const nt=t.useRef(W);nt.current=W;const _=t.useRef(null),je=t.useRef(null),J=t.useRef(!0),Z=t.useRef(!1),we=t.useRef(null),$e=t.useRef(!1),$=t.useRef(q),xe=t.useRef(!1),ee=t.useRef(!1),Be=t.useRef(!1),Ke=t.useRef(!1),B=t.useRef(null),Ne=t.useRef(0),ke=t.useRef(new Map),st=t.useRef({model:null,effort:null}),vt=t.useCallback(e=>{st.current=e},[]);t.useEffect(()=>{Be.current||!q||(Be.current=!0,k&&!b&&Y(k),p&&p.length&&!P.length&&(G(p),O.current=p),h(!1),Ze(e=>e+1),L?.())},[q,L]);const N=t.useCallback(()=>{Y(null),G(e=>{for(const s of e)URL.revokeObjectURL(s);return[]}),O.current=[],V(null)},[]),te=t.useCallback(()=>{U(e=>{if(!e.length)return e;for(const s of e)for(const l of s.imageUrls)URL.revokeObjectURL(l);return[]}),ge.current=null},[]),lt=t.useCallback((e,s)=>{const l=$t({streaming:Qe.current,liveStreamPhase:Q.current?.phase??null,streamPhase:nt.current,queuedTaskCount:_e.current.length,pendingQueuedCount:Te.current.length}),o=s||[];if(l){const c=`local-${Date.now().toString(36)}-${Math.random().toString(36).slice(2,8)}`;ge.current=c,U(x=>[...x,{localId:c,taskId:null,prompt:e||"",imageUrls:o}]);return}Q.current?.phase==="done"&&F(null);for(const c of O.current)URL.revokeObjectURL(c);ge.current=null,Y(e||null),G(o),O.current=o,V(null)},[]),Tt=t.useCallback(e=>{const s=ge.current;if(s){ge.current=null,U(l=>{const o=l.findIndex(x=>x.localId===s);if(o<0)return l;const c=l.slice();return c[o]={...c[o],taskId:e},c});return}V(e)},[]),Rt=t.useCallback(async()=>{if(!Re)return;const e=he.trim();if(e){He(!0);try{const s=await w.forkSession(d,r.agent||"",r.sessionId,Re.atTurn,e,{});if(!s.ok||!s.sessionKey){He(!1);return}const[l,o]=s.sessionKey.split(":");pe(null),Fe(""),v?.({agent:l,sessionId:o,workdir:d})}finally{He(!1)}}},[Re,he,d,r.agent,r.sessionId,v]);De.current=Rt;const Ae=t.useCallback(async(e,s={})=>{try{const l=await Bt({workdir:d,agent:r.agent||"",sessionId:r.sessionId,rich:!0,turnOffset:e.turnOffset,turnLimit:e.turnLimit,lastNTurns:e.lastNTurns},{force:s.force});return l.ok?it(l):null}catch{return null}},[d,r.agent,r.sessionId]),A=t.useCallback(async({keepOlder:e,force:s=!1,scrollToBottom:l=!1})=>{const o=r.sessionId;if(we.current===o)return!1;we.current=o;try{const c=await Ae({turnOffset:0,turnLimit:Ve},{force:s});if(!c||r.sessionId!==o)return!1;if(l&&(Z.current=!0),ce(x=>!x||!e?c:Kt(x,c)),h(!1),xe.current&&(xe.current=!1,N()),ee.current){const x=ee.current;ee.current=!1;const ne=x!==!0?x.taskId:null;Q.current&&(x===!0||Q.current.taskId===ne)&&F(null)}return!0}finally{we.current===o&&(we.current=null)}},[Ae,N,r.sessionId]),Oe=t.useCallback(async()=>{if(!m?.hasOlder||$e.current)return;const e=_.current;e&&(je.current={scrollHeight:e.scrollHeight,scrollTop:e.scrollTop}),$e.current=!0,Je(!0);try{const s=await Ae({turnOffset:Math.max(0,m.totalTurns-m.startTurn),turnLimit:Ve});s?ce(l=>l?zt(l,s):s):je.current=null}finally{$e.current=!1,Je(!1)}},[Ae,m]),Me=t.useRef(null),re=t.useCallback((e,s="ws")=>{if(sr({updatedAt:e?.updatedAt,isNull:!e,lastAppliedUpdatedAt:Ne.current,localStreamPending:$.current,holdsActiveState:Qe.current||_e.current.length>0})!=="apply")return;if(e&&(Ne.current=lr(Ne.current,e.updatedAt)),e?.sessionId&&e.sessionId!==r.sessionId&&(Ke.current=!0,Se.current=`${r.agent}:${e.sessionId}`,v?.({agent:r.agent||"",sessionId:e.sessionId,workdir:d})),!e){const g=Me.current;fe(!1),g==="streaming"?(xe.current=!0,ee.current=!0,A({keepOlder:!0,force:!0,scrollToBottom:J.current})):F(null),$.current&&g!=="streaming"?A({keepOlder:!0,force:!0}):(g==="done"&&(N(),te()),g!==null&&($.current=!1)),Ue(null),Pe(null),Ie([]),ve([]),qe([]),Me.current=null;return}Pe(e.phase),Ue(e.taskId||null);const o=[];e.taskId&&o.push(e.taskId),Array.isArray(e.queuedTaskIds)&&o.push(...e.queuedTaskIds),ke.current=or(ke.current,o,Date.now(),mr);const c=ke.current,x=ar(e.queuedTaskIds,c),ne=(Array.isArray(e.queuedTasks)?e.queuedTasks:[]).filter(g=>!c.has(g.taskId));if(Ie(x.length?x:cr),ve(ne.length?ne:ir),qe(Array.isArray(e.interactions)&&e.interactions.length?e.interactions:dr),Wt({pendingTaskId:H.current,streamTaskId:e.taskId||null,queuedTaskIds:e.queuedTaskIds})){const g=H.current,j=et.current||"",I=O.current;U(y=>y.some(le=>le.taskId===g)?y:[...y,{localId:`demote-${g}`,taskId:g,prompt:j,imageUrls:I}]),Y(null),G([]),O.current=[],V(null),H.current=null}if(e.phase==="streaming"){if(F({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}),fe(!0),e.taskId&&e.taskId!==H.current){const g=Te.current,j=g.findIndex(I=>I.taskId===e.taskId);if(j>=0){const I=g[j];for(const y of O.current)URL.revokeObjectURL(y);Y(I.prompt||null),G(I.imageUrls),O.current=I.imageUrls,V(e.taskId),U(y=>y.filter((le,K)=>K!==j))}}J.current&&(Z.current=!0)}else if(e.phase==="queued")F(null),fe(!1);else if(e.phase==="done"){const g=Xt(Q.current?.taskId??null,e.taskId||null),j=x.length>0;if(g){fe(!1),F(K=>K?{...K,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}:K);const I=Q.current,y=!!I&&Yt(I),le=!!e.incomplete&&y&&!j;if(Me.current!=="done"){j||(xe.current=!0),ee.current=le?!1:{taskId:e.taskId||null},A({keepOlder:!0,force:!0,scrollToBottom:J.current});const K=r.agent||"",Ot=r.sessionId,Mt=Se.current;B.current&&clearTimeout(B.current),B.current=setTimeout(()=>{B.current=null,w.getSessionStreamState(K,Ot).then(Et=>{Se.current===Mt&&ze.current(Et.state,"seed")}).catch(()=>{})},900)}}j||($.current=!1)}const se=new Set;if(e.taskId&&se.add(e.taskId),Array.isArray(e.queuedTaskIds))for(const g of e.queuedTaskIds)se.add(g);U(g=>{let j=!1;const I=[];for(const y of g)if(!y.taskId||se.has(y.taskId))I.push(y);else{for(const le of y.imageUrls)URL.revokeObjectURL(le);j=!0}return j?I:g}),Me.current=e.phase},[N,te,A,r.sessionId,r.agent,v,d]),ze=t.useRef(re);ze.current=re;const at=t.useCallback(()=>{$.current=!0,Ze(e=>e+1)},[]);t.useEffect(()=>()=>{B.current&&(clearTimeout(B.current),B.current=null)},[]);const jt=t.useCallback(async e=>{try{ke.current.set(e,Date.now()),await w.recallSessionMessage(e),H.current===e&&N(),U(s=>{let l=!1;const o=[];for(const c of s)if(c.taskId===e){for(const x of c.imageUrls)URL.revokeObjectURL(x);l=!0}else o.push(c);return l?o:s}),Ie(s=>s.filter(l=>l!==e)),ve(s=>s.filter(l=>l.taskId!==e)),Ue(s=>s===e?null:s)}catch{}},[N]),wt=t.useCallback(async e=>{const s=Te.current.find(l=>l.taskId===e)||null;if(s&&s.imageUrls.length>0){for(const l of O.current)URL.revokeObjectURL(l);Y(s.prompt||null),G(s.imageUrls),O.current=s.imageUrls,V(e),H.current=e,U(l=>l.filter(o=>o.taskId!==e))}try{await w.steerSession(e)}catch{}},[]),Nt=t.useCallback(async()=>{try{await w.stopSession(r.agent||"",r.sessionId)}catch{}},[r.agent,r.sessionId]),Ee=gr(r.agent||"",r.sessionId);t.useEffect(()=>{if(Ke.current){Ke.current=!1;let c=!1;return A({keepOlder:!0,force:!0}).finally(()=>{c||h(!1)}),()=>{c=!0}}let e=!1;const s=Gt({workdir:d,agent:r.agent||"",sessionId:r.sessionId,rich:!0,turnOffset:0,turnLimit:Ve},{allowStale:!0}),l=q&&!Be.current,o=s?.ok?it(s):ae.get(Ee)||null;return h(l?!1:!o),ce(o),F(null),fe(!1),Pe(null),Ie([]),ve([]),qe([]),Ne.current=0,ke.current=new Map,l||(N(),te(),$.current=!1,xe.current=!1,ee.current=!1),J.current=!0,Z.current=!0,l||A({keepOlder:!1,force:!0}).finally(()=>{e||h(!1)}),()=>{e=!0}},[A,r.agent,r.sessionId,d,Ee,N,te]),t.useEffect(()=>{m&&m.turns.length>0&&pr(Ee,m)},[Ee,m]),t.useEffect(()=>{M&&A({keepOlder:!0,force:!0})},[M,A]);const Se=t.useRef(`${r.agent}:${r.sessionId}`);Se.current=`${r.agent}:${r.sessionId}`,Ft("stream-update",t.useCallback(e=>{e.key===Se.current&&re(e.snapshot??null)},[re])),t.useEffect(()=>{let e=!0;return w.getSessionStreamState(r.agent||"",r.sessionId).then(s=>{e&&ze.current(s.state,"seed")}).catch(()=>{}),()=>{e=!1}},[r.agent,r.sessionId,xt]),Ht(t.useCallback(()=>{w.getSessionStreamState(r.agent||"",r.sessionId).then(e=>{re(e.state,"seed")}).catch(()=>{}),A({keepOlder:!0,force:!0})},[re,r.agent,r.sessionId,A])),t.useEffect(()=>{!$.current&&ue!=="running"&&!de&&!i&&!W&&X.length===0&&(N(),te())},[ue,de,i,W,X.length,N,te]),t.useLayoutEffect(()=>{const e=je.current,s=_.current;!e||!s||(je.current=null,s.scrollTop=e.scrollTop+(s.scrollHeight-e.scrollHeight))},[m?.turns.length]),t.useLayoutEffect(()=>{if(!Z.current)return;const e=_.current;e&&(Z.current=!1,e.scrollTop=e.scrollHeight,requestAnimationFrame(()=>{J.current&&(e.scrollTop=e.scrollHeight)}))},[m,i]),t.useLayoutEffect(()=>{if(!b)return;const e=_.current;e&&(e.scrollTop=e.scrollHeight)},[b]),t.useEffect(()=>{if(!m?.hasOlder||u||ie)return;const e=_.current;e&&e.scrollHeight<=e.clientHeight+gt&&Oe()},[m?.hasOlder,m?.turns.length,Oe,u,ie]);const At=t.useCallback(()=>{const e=_.current;if(!e)return;const s=e.scrollHeight-e.scrollTop-e.clientHeight;J.current=s<=ur,e.scrollTop<=gt&&Oe()},[Oe]),be=i?.model||r.model||z||null,We=Dt(r.agent||"",i?.effort||r.thinkingEffort||T||null,r.workflowEnabled??E?.workflowEnabled)||null,ot=oe&&(!be||be===z)?oe:be?Qt(be):null,Xe=_t(r,{streaming:de,hasLiveStream:!!i,streamPhase:W,queuedTaskCount:X.length}),R=m?.turns||[],Ye=t.useMemo(()=>{if(!P.length||!R.length)return!1;const e=R[R.length-1];return!e.user||!dt(e.user.text,b)?!1:e.user.blocks.filter(l=>l.type==="image").length<P.length},[R,b,P.length]),ut=t.useMemo(()=>{let e=R;if(Ye){const se=e[e.length-1];e=[...e.slice(0,-1),{...se,user:null}]}if(!i||!e.length)return e;const s=e[e.length-1];if(!s.assistant)return e;const l=b??(i.question||null),o=(i.text||"").trim(),c=s.assistant.text?.trim()||"";if(!(l!=null?Ge(s.user?.text,l):!!c&&!!o&&(o.startsWith(c)||c.startsWith(o))))return e;const ne=s.user&&l&&!dt(s.user.text,l)?{...s.user,text:l}:s.user;return[...e.slice(0,-1),{...s,user:ne,assistant:null}]},[R,i,b,Ye]);return n.jsxs("div",{className:"flex flex-col h-full overflow-hidden",children:[n.jsx("div",{ref:_,onScroll:At,className:"flex-1 overflow-y-auto overscroll-contain",children:u&&!b&&!P.length&&!i?n.jsx("div",{className:"flex items-center justify-center py-20",children:n.jsx(Le,{className:"h-5 w-5 text-fg-4"})}):ut.length===0&&!b&&!P.length&&!i&&!Xe?n.jsx("div",{className:"py-20 text-center text-[13px] text-fg-5",children:f("hub.noMessages")}):n.jsxs("div",{className:"max-w-[900px] mx-auto px-6 py-6 space-y-0",children:[(m?.hasOlder||ie)&&n.jsxs("div",{className:"mb-4 flex items-center justify-center gap-2 text-[11px] text-fg-5",children:[ie?n.jsx(Le,{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:f(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:d}),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:f("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:["· ",f("hub.forkBadgeAt").replace("{turn}",String(r.migratedFrom.forkedAtTurn+1))]})]}),ut.map((e,s)=>{const l=(m?.startTurn||0)+s;return n.jsx(Vt,{turn:e,turnIndex:l,agent:r.agent||"",meta:ye,model:ot,effort:We,providerName:C,t:f,workdir:d,onResend:o=>{Z.current=!0,lt(o);const c=st.current;w.sendSessionMessage(d,r.agent||"",r.sessionId,o,{model:c.model||be||void 0,effort:c.effort||We||void 0}).then(x=>{x.ok&&at()}).catch(()=>{N()})},onEdit:o=>rt(o),onFork:It?o=>{Fe(""),pe({atTurn:o})}:void 0},`${m?.startTurn||0}:${s}`)}),Xe&&n.jsx("div",{className:"mb-5 animate-in",children:n.jsx(Jt,{detail:Xe,t:f})}),(b||P.length>0)&&(Ye||!(b&&R.length>0&&Ge(R[R.length-1]?.user?.text,b)))&&n.jsxs("div",{className:"session-turn",children:[n.jsx(ft,{text:b||"",blocks:P.map(e=>({type:"image",content:e})),t:f}),!i&&n.jsx("div",{className:"mt-3 mb-5 animate-in",children:n.jsx(Zt,{className:"text-fg-5"})})]}),i&&mt(i)&&!b&&i.question&&!(R.length>0&&Ge(R[R.length-1]?.user?.text,i.question))&&n.jsx("div",{className:"session-turn",children:n.jsx(ft,{text:i.question,t:f})}),i&&mt(i)&&n.jsxs("div",{className:"mb-6",children:[n.jsx(er,{agent:r.agent||"",meta:ye,model:ot,effort:We,providerName:C,previewMeta:i.previewMeta,hideContextUsage:!0}),n.jsx(tr,{stream:i,t:f,workdir:d})]}),n.jsx("div",{className:"h-4"})]})}),n.jsx(rr,{session:r,workdir:d,onStreamQueued:at,onSendStart:lt,onSendTaskAssigned:Tt,onSessionChange:v,t:f,streamPhase:W,streamTaskId:kt,queuedTaskIds:X,queuedTasks:St,pendingQueuedSends:tt,onRecall:jt,onSteer:wt,onStopAll:Nt,editDraft:yt,onEditDraftConsumed:()=>rt(null),onSelectionChange:vt}),Re&&n.jsxs(pt,{open:!0,onClose:()=>{D||pe(null)},children:[n.jsx(ht,{title:f("hub.forkPromptTitle"),description:f("hub.forkPromptHint"),onClose:()=>{D||pe(null)}}),n.jsx("textarea",{autoFocus:!0,value:he,disabled:D,onChange:e=>Fe(e.target.value),onKeyDown:e=>{e.key==="Enter"&&(e.metaKey||e.ctrlKey)&&he.trim()&&!D&&(e.preventDefault(),De.current?.())},placeholder:f("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(Ce,{variant:"ghost",disabled:D,onClick:()=>pe(null),children:f("modal.cancel")}),n.jsx(Ce,{variant:"primary",disabled:D||!he.trim(),onClick:()=>{De.current?.()},children:f(D?"hub.forkSubmitting":"hub.forkSubmit")})]})]}),M&&me.length>0&&n.jsx(nr,{snapshot:me[me.length-1]},me[me.length-1].promptId)]})});export{Rr as SessionPanel};
|