glad-web 1.0.28 → 1.0.29
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/lib/codex/structured-session.js +18 -4
- package/lib/web/index.html +62 -0
- package/package.json +1 -1
|
@@ -167,6 +167,7 @@ class CodexStructuredSession extends EventEmitter {
|
|
|
167
167
|
this.currentTurnId = null;
|
|
168
168
|
this.currentTurnStartedAt = null;
|
|
169
169
|
this.threadTurns = new Map();
|
|
170
|
+
this.providerItemContexts = new Map();
|
|
170
171
|
this.tokenUsage = null;
|
|
171
172
|
this.permissionMode = normalizePermissionMode(options.permissionMode);
|
|
172
173
|
this.sandboxMode = normalizeSandboxMode(options.sandboxMode);
|
|
@@ -481,17 +482,27 @@ class CodexStructuredSession extends EventEmitter {
|
|
|
481
482
|
if (method === 'item/plan/delta') {
|
|
482
483
|
const providerId = String(params.itemId || '');
|
|
483
484
|
const target = this.messages.find(item => item.providerId === providerId && item.kind === 'reasoning');
|
|
484
|
-
|
|
485
|
-
|
|
485
|
+
const known = this.providerItemContexts.get(providerId) || {};
|
|
486
|
+
const threadId = params.threadId || target?.threadId || known.threadId || null;
|
|
487
|
+
const turnId = params.turnId || target?.turnId || known.turnId
|
|
488
|
+
|| (threadId ? this.threadTurns.get(threadId)?.turnId : null) || this.currentTurnId;
|
|
489
|
+
if (providerId && (threadId || turnId)) this.providerItemContexts.set(providerId, { threadId, turnId });
|
|
490
|
+
if (target) this.patch(target.id, { text: String(target.text || '') + String(params.delta || ''), threadId, turnId });
|
|
491
|
+
else this.append({ kind: 'reasoning', providerId, text: String(params.delta || ''), threadId, turnId, streaming: true });
|
|
486
492
|
return;
|
|
487
493
|
}
|
|
488
494
|
if (method.includes('agentMessage/delta') || method.includes('reasoning/textDelta') || method.includes('reasoning/summaryTextDelta')) {
|
|
489
495
|
const kind = method.includes('agentMessage') ? 'assistant' : 'reasoning';
|
|
490
496
|
const itemId = String(params.itemId || params.id || '');
|
|
491
497
|
const target = this.messages.find(item => item.providerId === itemId && item.kind === kind);
|
|
498
|
+
const known = this.providerItemContexts.get(itemId) || {};
|
|
499
|
+
const threadId = params.threadId || target?.threadId || known.threadId || null;
|
|
500
|
+
const turnId = params.turnId || target?.turnId || known.turnId
|
|
501
|
+
|| (threadId ? this.threadTurns.get(threadId)?.turnId : null) || this.currentTurnId;
|
|
492
502
|
const delta = String(params.delta || '');
|
|
493
|
-
if (
|
|
494
|
-
|
|
503
|
+
if (itemId && (threadId || turnId)) this.providerItemContexts.set(itemId, { threadId, turnId });
|
|
504
|
+
if (target) this.patch(target.id, { text: (target.text || '') + delta, threadId, turnId });
|
|
505
|
+
else this.append({ kind, providerId: itemId, text: delta, threadId, turnId, streaming: true });
|
|
495
506
|
return;
|
|
496
507
|
}
|
|
497
508
|
if (method.startsWith('item/')) {
|
|
@@ -519,6 +530,7 @@ class CodexStructuredSession extends EventEmitter {
|
|
|
519
530
|
const threadId = raw.threadId || context.threadId || null;
|
|
520
531
|
const trackedTurnId = threadId ? this.threadTurns.get(threadId)?.turnId : null;
|
|
521
532
|
const turnId = raw.turnId || context.turnId || trackedTurnId || this.currentTurnId;
|
|
533
|
+
if (providerId && (threadId || turnId)) this.providerItemContexts.set(providerId, { threadId, turnId });
|
|
522
534
|
const existingStartedAtMs = existing?.startedAtMs || existing?.createdAt || null;
|
|
523
535
|
const startedAtMs = Number(context.startedAtMs || raw.startedAtMs || 0)
|
|
524
536
|
|| toTimestampMs(raw.startedAt || raw.createdAt) || existingStartedAtMs;
|
|
@@ -836,6 +848,7 @@ class CodexStructuredSession extends EventEmitter {
|
|
|
836
848
|
this.tokenUsage = thread?.tokenUsage || thread?.token_usage || this.tokenUsage;
|
|
837
849
|
this.messages = [];
|
|
838
850
|
this.completedPermissions = [];
|
|
851
|
+
this.providerItemContexts.clear();
|
|
839
852
|
for (const turn of thread?.turns || []) {
|
|
840
853
|
const status = turn.status === 'failed' ? 'failed' : turn.status === 'interrupted' ? 'cancelled' : 'completed';
|
|
841
854
|
const startedAt = Number(turn.startedAt || turn.createdAt || 0);
|
|
@@ -846,6 +859,7 @@ class CodexStructuredSession extends EventEmitter {
|
|
|
846
859
|
this.append({ kind: 'turn-start', turnId: turn.id, ...(startedAtMs ? { createdAt: startedAtMs } : {}) });
|
|
847
860
|
for (const item of turn.items || []) {
|
|
848
861
|
this.applyProviderItem({ ...item, turnId: turn.id }, status === 'failed' ? 'failed' : 'completed', {
|
|
862
|
+
threadId: this.threadId,
|
|
849
863
|
startedAtMs,
|
|
850
864
|
completedAtMs
|
|
851
865
|
});
|
package/lib/web/index.html
CHANGED
|
@@ -131,6 +131,11 @@
|
|
|
131
131
|
.codex-work-group > summary::before { content: '›'; width: 12px; color: #8e8e93; font-size: 17px; transform-origin: center; }
|
|
132
132
|
.codex-work-group[open] > summary::before { transform: rotate(90deg); }
|
|
133
133
|
.codex-work-group-body { padding-left: 2px; }
|
|
134
|
+
.codex-subagent-group { border-left-color: rgba(100,210,255,.24); }
|
|
135
|
+
.codex-subagent-group > summary { color: #8e9aa6; }
|
|
136
|
+
.codex-subagent-group > summary::before { color: #64a9d1; }
|
|
137
|
+
.codex-subagent-message { margin: 7px 0; padding: 7px 9px; border-left: 1px solid rgba(255,255,255,.1); color: #c7c7cc; font-size: 12px; line-height: 1.42; overflow-wrap: anywhere; }
|
|
138
|
+
.codex-subagent-message.task { color: #8e8e93; font-style: italic; }
|
|
134
139
|
.codex-patch-file { border-top: 1px solid rgba(255,255,255,.08); }
|
|
135
140
|
.codex-patch-file:first-child { border-top: 0; }
|
|
136
141
|
.codex-patch-file > summary { display: flex; align-items: center; gap: 8px; padding: 8px 10px; color: #d1d5db; font: 12px/1.35 ui-monospace, SFMono-Regular, Menlo, monospace; }
|
|
@@ -2203,6 +2208,46 @@
|
|
|
2203
2208
|
const key = items.map(item => item.id || item.providerId || '').join('-');
|
|
2204
2209
|
return `<details class="codex-work-group" data-codex-key="group-${escapeHtml(key)}"><summary>${label} · ${items.length} ${items.length === 1 ? 'tool' : 'tools'}</summary><div class="codex-work-group-body">${tools}</div></details>`;
|
|
2205
2210
|
}
|
|
2211
|
+
function isCodexSubagentItem(item) {
|
|
2212
|
+
return Boolean(item?.threadId && codexState.threadId && item.threadId !== codexState.threadId);
|
|
2213
|
+
}
|
|
2214
|
+
function renderCodexSubagentGroup(threadId, items, permissionById, usedPermissions) {
|
|
2215
|
+
const turnEnds = items.filter(item => item.kind === 'turn-end');
|
|
2216
|
+
const content = items.filter(item => !['reasoning', 'turn-start', 'turn-end'].includes(item.kind));
|
|
2217
|
+
const tools = content.filter(item => item.kind === 'tool');
|
|
2218
|
+
const messages = content.filter(item => item.kind === 'assistant' || item.kind === 'user');
|
|
2219
|
+
const running = tools.some(item => codexToolStatus(item) === 'running')
|
|
2220
|
+
|| items.filter(item => item.kind === 'turn-start').length > turnEnds.length;
|
|
2221
|
+
const startedAt = Math.min(...items.map(item => Number(item.startedAtMs || item.createdAt || Infinity)));
|
|
2222
|
+
const completedAt = Math.max(...turnEnds.map(item => Number(item.createdAt || 0)),
|
|
2223
|
+
...content.map(item => Number(item.completedAtMs || item.updatedAt || 0)));
|
|
2224
|
+
const duration = formatCodexDuration(Number.isFinite(startedAt) && completedAt >= startedAt
|
|
2225
|
+
? completedAt - startedAt : 0);
|
|
2226
|
+
const counts = [];
|
|
2227
|
+
if (tools.length) counts.push(`${tools.length} ${tools.length === 1 ? 'tool' : 'tools'}`);
|
|
2228
|
+
if (messages.length) counts.push(`${messages.length} ${messages.length === 1 ? 'message' : 'messages'}`);
|
|
2229
|
+
const label = running ? 'Subagent working' : duration ? `Subagent worked for ${duration}` : 'Subagent worked';
|
|
2230
|
+
const body = [];
|
|
2231
|
+
for (let i = 0; i < content.length;) {
|
|
2232
|
+
const item = content[i];
|
|
2233
|
+
if (item.kind === 'tool') {
|
|
2234
|
+
const group = [];
|
|
2235
|
+
const turnId = item.turnId;
|
|
2236
|
+
while (i < content.length && content[i].kind === 'tool' && content[i].turnId === turnId) group.push(content[i++]);
|
|
2237
|
+
const turnEnd = turnEnds.find(candidate => candidate.turnId === turnId) || null;
|
|
2238
|
+
body.push(renderCodexToolGroup(group, permissionById, usedPermissions, turnEnd));
|
|
2239
|
+
continue;
|
|
2240
|
+
}
|
|
2241
|
+
if (item.kind === 'assistant' || item.kind === 'user') {
|
|
2242
|
+
body.push(`<div class="codex-subagent-message${item.kind === 'user' ? ' task' : ''}">${renderMarkdown(item.text || '')}</div>`);
|
|
2243
|
+
} else if (item.text) {
|
|
2244
|
+
body.push(`<div class="codex-subagent-message">${codexText(item.text)}</div>`);
|
|
2245
|
+
}
|
|
2246
|
+
i += 1;
|
|
2247
|
+
}
|
|
2248
|
+
const suffix = counts.length ? ` · ${counts.join(' · ')}` : '';
|
|
2249
|
+
return `<details class="codex-work-group codex-subagent-group" data-codex-key="subagent-${escapeHtml(threadId)}"><summary>${escapeHtml(label + suffix)}</summary><div class="codex-work-group-body">${body.join('')}</div></details>`;
|
|
2250
|
+
}
|
|
2206
2251
|
function renderCodexMessageTime(item, finalOnly = false) {
|
|
2207
2252
|
if (!item || (finalOnly && item.streaming)) return '';
|
|
2208
2253
|
const timestamp = Number(finalOnly ? (item.completedAtMs || item.updatedAt || item.createdAt) : item.createdAt);
|
|
@@ -2265,9 +2310,26 @@
|
|
|
2265
2310
|
const usedPermissions = new Set();
|
|
2266
2311
|
const turnEndById = new Map(codexMessages.filter(item => item.kind === 'turn-end' && item.turnId)
|
|
2267
2312
|
.map(item => [String(item.turnId), item]));
|
|
2313
|
+
const subagentItems = new Map();
|
|
2314
|
+
for (const item of codexMessages) {
|
|
2315
|
+
if (!isCodexSubagentItem(item)) continue;
|
|
2316
|
+
const threadId = String(item.threadId);
|
|
2317
|
+
if (!subagentItems.has(threadId)) subagentItems.set(threadId, []);
|
|
2318
|
+
subagentItems.get(threadId).push(item);
|
|
2319
|
+
}
|
|
2320
|
+
const renderedSubagents = new Set();
|
|
2268
2321
|
const visible = codexMessages.filter(item => !['reasoning', 'turn-start', 'turn-end'].includes(item.kind));
|
|
2269
2322
|
for (let i = 0; i < visible.length;) {
|
|
2270
2323
|
const item = visible[i];
|
|
2324
|
+
if (isCodexSubagentItem(item)) {
|
|
2325
|
+
const threadId = String(item.threadId);
|
|
2326
|
+
if (!renderedSubagents.has(threadId)) {
|
|
2327
|
+
renderedSubagents.add(threadId);
|
|
2328
|
+
parts.push(renderCodexSubagentGroup(threadId, subagentItems.get(threadId) || [], permissionById, usedPermissions));
|
|
2329
|
+
}
|
|
2330
|
+
i += 1;
|
|
2331
|
+
continue;
|
|
2332
|
+
}
|
|
2271
2333
|
if (item.kind === 'tool') {
|
|
2272
2334
|
const tools = [];
|
|
2273
2335
|
const turnId = item.turnId;
|