@pikiloom/kernel 0.3.6 → 0.3.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/drivers/claude.d.ts +1 -1
- package/dist/drivers/claude.js +16 -9
- package/dist/drivers/codex.d.ts +3 -0
- package/dist/drivers/codex.js +149 -11
- package/package.json +1 -1
package/dist/drivers/claude.d.ts
CHANGED
|
@@ -24,7 +24,7 @@ export declare function claudeBgAgentHoldCapMs(): number;
|
|
|
24
24
|
export declare function claudeTurnHasAgentBackground(s: any): boolean;
|
|
25
25
|
export declare function claudeBgHoldRecheckMs(): number;
|
|
26
26
|
export declare function claudeBgSettleQuietMs(): number;
|
|
27
|
-
export declare function claudeModelStallMs(): number;
|
|
27
|
+
export declare function claudeModelStallMs(effort?: string | null): number;
|
|
28
28
|
export declare const CLAUDE_TRUNCATED_RECOVERY_PROMPT: string;
|
|
29
29
|
export declare function claudeTruncatedRecoveryEnabled(): boolean;
|
|
30
30
|
export declare function isClaudeSyntheticResumeNoise(text: string): boolean;
|
package/dist/drivers/claude.js
CHANGED
|
@@ -193,7 +193,7 @@ export class ClaudeDriver {
|
|
|
193
193
|
return;
|
|
194
194
|
}
|
|
195
195
|
settleResult({ stopReason: 'stalled', kill: false, ok: false });
|
|
196
|
-
}, claudeModelStallMs());
|
|
196
|
+
}, claudeModelStallMs(input.effort));
|
|
197
197
|
unref(modelStallTimer);
|
|
198
198
|
};
|
|
199
199
|
try {
|
|
@@ -801,15 +801,22 @@ export function claudeBgSettleQuietMs() {
|
|
|
801
801
|
return Number.isFinite(raw) && raw > 0 ? raw : CLAUDE_BG_SETTLE_QUIET_DEFAULT_MS;
|
|
802
802
|
}
|
|
803
803
|
// How long the model may stay COMPLETELY silent after a tool_result (control handed back to it,
|
|
804
|
-
// no background pending) before the driver gives up and settles the turn as 'stalled'.
|
|
805
|
-
// generous:
|
|
806
|
-
//
|
|
807
|
-
//
|
|
808
|
-
//
|
|
809
|
-
|
|
810
|
-
|
|
804
|
+
// no background pending) before the driver gives up and settles the turn as 'stalled'. Must be
|
|
805
|
+
// generous: subscription accounts stream NO events during extended thinking, and at the reasoning
|
|
806
|
+
// rungs a legitimate silent think regularly exceeds two minutes — the original 120s default
|
|
807
|
+
// misfired on exactly that (settling a LIVE turn as 'stalled' and then killing its still-running
|
|
808
|
+
// tool via the leak-guard; mirasim#111). A too-long window only means a truly hung turn shows its
|
|
809
|
+
// dead spinner longer, so the costs are asymmetric — err long. Effort-laddered: the deep-reasoning
|
|
810
|
+
// rungs (high and up) think the longest. A still-running tool never trips this (it has no
|
|
811
|
+
// tool_result yet). Override with PIKILOOM_CLAUDE_MODEL_STALL_MS (wins over the ladder).
|
|
812
|
+
const CLAUDE_MODEL_STALL_DEFAULT_MS = 300_000;
|
|
813
|
+
const CLAUDE_MODEL_STALL_DEEP_MS = 600_000;
|
|
814
|
+
const CLAUDE_DEEP_REASONING_EFFORTS = new Set(['high', 'xhigh', 'max', 'ultra']);
|
|
815
|
+
export function claudeModelStallMs(effort) {
|
|
811
816
|
const raw = Number(process.env.PIKILOOM_CLAUDE_MODEL_STALL_MS);
|
|
812
|
-
|
|
817
|
+
if (Number.isFinite(raw) && raw > 0)
|
|
818
|
+
return raw;
|
|
819
|
+
return effort && CLAUDE_DEEP_REASONING_EFFORTS.has(effort) ? CLAUDE_MODEL_STALL_DEEP_MS : CLAUDE_MODEL_STALL_DEFAULT_MS;
|
|
813
820
|
}
|
|
814
821
|
// In-process self-heal for a truncated turn: when a clean result lands while the tool loop is
|
|
815
822
|
// still dangling (the model's closing round came back empty), the stdin is still open — inject
|
package/dist/drivers/codex.d.ts
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import type { AgentDriver, AgentTurnInput, DriverContext, DriverEvent, DriverResult, TuiInput, TuiSpec, NativeSessionInfo } from '../contracts/driver.js';
|
|
2
|
+
import type { UniversalToolCall } from '../protocol/index.js';
|
|
2
3
|
export declare function codexToolSummary(item: any): {
|
|
3
4
|
id: string;
|
|
4
5
|
name: string;
|
|
5
6
|
summary: string;
|
|
6
7
|
} | null;
|
|
8
|
+
/** Project one app-server item into the kernel's rich, expandable tool-call shape. */
|
|
9
|
+
export declare function codexToolCall(item: any, fallbackStatus: UniversalToolCall['status']): UniversalToolCall | null;
|
|
7
10
|
export interface CodexContentState {
|
|
8
11
|
text: string;
|
|
9
12
|
reasoning: string;
|
package/dist/drivers/codex.js
CHANGED
|
@@ -34,6 +34,89 @@ const CODEX_TOOL_CALL_TYPES = new Set(['dynamicToolCall', 'mcpToolCall', 'collab
|
|
|
34
34
|
// Field-less placeholder summaries — a completed item with only one of these never overrides
|
|
35
35
|
// a more specific summary cached at item/started.
|
|
36
36
|
const CODEX_GENERIC_TOOL_SUMMARIES = new Set(['Search web', 'Run shell command', 'Edit files', 'Use tool']);
|
|
37
|
+
const CODEX_TOOL_INPUT_MAX = 4 * 1024;
|
|
38
|
+
const CODEX_TOOL_RESULT_MAX = 12 * 1024;
|
|
39
|
+
function codexToolText(value, max) {
|
|
40
|
+
if (value == null)
|
|
41
|
+
return null;
|
|
42
|
+
let text;
|
|
43
|
+
if (typeof value === 'string')
|
|
44
|
+
text = value;
|
|
45
|
+
else {
|
|
46
|
+
try {
|
|
47
|
+
text = JSON.stringify(value, null, 2);
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
text = String(value);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
text = text.replace(/\r\n/g, '\n').trim();
|
|
54
|
+
if (!text)
|
|
55
|
+
return null;
|
|
56
|
+
return text.length <= max ? text : `${text.slice(0, max).trimEnd()}\n… (truncated)`;
|
|
57
|
+
}
|
|
58
|
+
function codexToolInput(item) {
|
|
59
|
+
switch (item?.type) {
|
|
60
|
+
case 'commandExecution': {
|
|
61
|
+
const command = Array.isArray(item.command) ? item.command.join(' ') : item.command;
|
|
62
|
+
if (!command)
|
|
63
|
+
return null;
|
|
64
|
+
const detail = { command };
|
|
65
|
+
if (typeof item.cwd === 'string' && item.cwd.trim())
|
|
66
|
+
detail.cwd = item.cwd;
|
|
67
|
+
return codexToolText(detail, CODEX_TOOL_INPUT_MAX);
|
|
68
|
+
}
|
|
69
|
+
case 'fileChange':
|
|
70
|
+
case 'patch':
|
|
71
|
+
return codexToolText(item.changes ?? item.patch ?? item.diff, CODEX_TOOL_INPUT_MAX);
|
|
72
|
+
case 'mcpToolCall':
|
|
73
|
+
case 'dynamicToolCall':
|
|
74
|
+
return codexToolText(item.arguments ?? item.input, CODEX_TOOL_INPUT_MAX);
|
|
75
|
+
case 'collabAgentToolCall':
|
|
76
|
+
return codexToolText({
|
|
77
|
+
prompt: item.prompt ?? undefined,
|
|
78
|
+
model: item.model ?? undefined,
|
|
79
|
+
reasoningEffort: item.reasoningEffort ?? item.reasoning_effort ?? undefined,
|
|
80
|
+
receiverThreadIds: item.receiverThreadIds ?? item.receiver_thread_ids ?? undefined,
|
|
81
|
+
}, CODEX_TOOL_INPUT_MAX);
|
|
82
|
+
case 'webSearch':
|
|
83
|
+
return codexToolText(item.action ?? item.query, CODEX_TOOL_INPUT_MAX);
|
|
84
|
+
default:
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
function codexToolResult(item) {
|
|
89
|
+
if (item?.type === 'commandExecution') {
|
|
90
|
+
const output = codexToolText(item.aggregatedOutput ?? item.aggregated_output, CODEX_TOOL_RESULT_MAX);
|
|
91
|
+
const exitCode = item.exitCode ?? item.exit_code;
|
|
92
|
+
if (output && typeof exitCode === 'number' && exitCode !== 0)
|
|
93
|
+
return `${output}\n\n(exit code ${exitCode})`;
|
|
94
|
+
if (output)
|
|
95
|
+
return output;
|
|
96
|
+
return typeof exitCode === 'number' && exitCode !== 0 ? `exit code ${exitCode}` : null;
|
|
97
|
+
}
|
|
98
|
+
if (item?.type === 'mcpToolCall') {
|
|
99
|
+
const error = item.error?.message ?? item.error;
|
|
100
|
+
if (error)
|
|
101
|
+
return codexToolText(error, CODEX_TOOL_RESULT_MAX);
|
|
102
|
+
return codexToolText(item.result, CODEX_TOOL_RESULT_MAX);
|
|
103
|
+
}
|
|
104
|
+
if (item?.type === 'dynamicToolCall') {
|
|
105
|
+
return codexToolText(item.contentItems ?? item.content_items, CODEX_TOOL_RESULT_MAX);
|
|
106
|
+
}
|
|
107
|
+
if (item?.type === 'collabAgentToolCall') {
|
|
108
|
+
return codexToolText(item.agentsStates ?? item.agents_states, CODEX_TOOL_RESULT_MAX);
|
|
109
|
+
}
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
function codexToolStatus(item, fallback) {
|
|
113
|
+
const raw = String(item?.status || '').toLowerCase();
|
|
114
|
+
if (raw === 'failed' || raw === 'declined' || item?.success === false || item?.error)
|
|
115
|
+
return 'failed';
|
|
116
|
+
if (raw === 'completed' || raw === 'done' || item?.success === true)
|
|
117
|
+
return 'done';
|
|
118
|
+
return fallback;
|
|
119
|
+
}
|
|
37
120
|
export function codexToolSummary(item) {
|
|
38
121
|
const id = String(item?.id || '');
|
|
39
122
|
if (!id)
|
|
@@ -66,6 +149,27 @@ export function codexToolSummary(item) {
|
|
|
66
149
|
}
|
|
67
150
|
return null;
|
|
68
151
|
}
|
|
152
|
+
/** Project one app-server item into the kernel's rich, expandable tool-call shape. */
|
|
153
|
+
export function codexToolCall(item, fallbackStatus) {
|
|
154
|
+
const base = codexToolSummary(item);
|
|
155
|
+
if (!base)
|
|
156
|
+
return null;
|
|
157
|
+
return {
|
|
158
|
+
...base,
|
|
159
|
+
input: codexToolInput(item),
|
|
160
|
+
result: codexToolResult(item),
|
|
161
|
+
status: codexToolStatus(item, fallbackStatus),
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
function appendCodexToolOutput(previous, delta) {
|
|
165
|
+
if (typeof delta !== 'string' || !delta)
|
|
166
|
+
return previous ?? null;
|
|
167
|
+
const next = `${previous ?? ''}${delta}`.replace(/\r\n/g, '\n');
|
|
168
|
+
if (next.length <= CODEX_TOOL_RESULT_MAX)
|
|
169
|
+
return next;
|
|
170
|
+
const marker = '… (earlier output truncated)\n';
|
|
171
|
+
return marker + next.slice(-(CODEX_TOOL_RESULT_MAX - marker.length));
|
|
172
|
+
}
|
|
69
173
|
// codex `item/tool/requestUserInput` params -> a normalized UniversalInteraction
|
|
70
174
|
// (faithful to the legacy codex driver's toAgentInteraction shape).
|
|
71
175
|
function codexUserInputToInteraction(params, promptId) {
|
|
@@ -153,7 +257,7 @@ export class CodexDriver {
|
|
|
153
257
|
const srv = new StdioRpcClient({ command: this.bin, args, env: input.env, label: 'codex app-server' });
|
|
154
258
|
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 };
|
|
155
259
|
const phases = new Map();
|
|
156
|
-
const
|
|
260
|
+
const toolCalls = new Map();
|
|
157
261
|
const deltaItems = new Set();
|
|
158
262
|
let lastTextItemId = null;
|
|
159
263
|
let steerRegistered = false;
|
|
@@ -218,13 +322,35 @@ export class CodexDriver {
|
|
|
218
322
|
const item = params?.item || {};
|
|
219
323
|
if (item.type === 'agentMessage' && item.id)
|
|
220
324
|
phases.set(item.id, item.phase || 'final_answer');
|
|
221
|
-
const
|
|
222
|
-
if (
|
|
223
|
-
|
|
224
|
-
ctx.emit({ type: 'tool', call
|
|
325
|
+
const call = codexToolCall(item, 'running');
|
|
326
|
+
if (call && !toolCalls.has(call.id)) {
|
|
327
|
+
toolCalls.set(call.id, call);
|
|
328
|
+
ctx.emit({ type: 'tool', call });
|
|
225
329
|
}
|
|
226
330
|
break;
|
|
227
331
|
}
|
|
332
|
+
case 'item/commandExecution/outputDelta':
|
|
333
|
+
case 'item/fileChange/outputDelta': {
|
|
334
|
+
const id = String(params?.itemId || '');
|
|
335
|
+
const previous = toolCalls.get(id);
|
|
336
|
+
if (!previous)
|
|
337
|
+
break;
|
|
338
|
+
const call = { ...previous, result: appendCodexToolOutput(previous.result, params?.delta) };
|
|
339
|
+
toolCalls.set(id, call);
|
|
340
|
+
ctx.emit({ type: 'tool', call });
|
|
341
|
+
break;
|
|
342
|
+
}
|
|
343
|
+
case 'item/fileChange/patchUpdated': {
|
|
344
|
+
const id = String(params?.itemId || '');
|
|
345
|
+
const projected = codexToolCall({ type: 'fileChange', id, changes: params?.changes }, 'running');
|
|
346
|
+
if (!projected)
|
|
347
|
+
break;
|
|
348
|
+
const previous = toolCalls.get(id);
|
|
349
|
+
const call = previous ? { ...previous, ...projected, result: projected.result ?? previous.result } : projected;
|
|
350
|
+
toolCalls.set(id, call);
|
|
351
|
+
ctx.emit({ type: 'tool', call });
|
|
352
|
+
break;
|
|
353
|
+
}
|
|
228
354
|
case 'item/agentMessage/delta': {
|
|
229
355
|
if (!params?.delta)
|
|
230
356
|
break;
|
|
@@ -259,14 +385,26 @@ export class CodexDriver {
|
|
|
259
385
|
captureCodexAgentMessage(item, state, deltaItems, phases, ctx.emit);
|
|
260
386
|
else if (item.type === 'reasoning')
|
|
261
387
|
captureCodexReasoning(codexReasoningItemText(item), state, ctx.emit);
|
|
262
|
-
const
|
|
263
|
-
if (
|
|
388
|
+
const projected = codexToolCall(item, 'done');
|
|
389
|
+
if (projected) {
|
|
264
390
|
// Prefer the completed item's summary when it is specific — webSearch carries its
|
|
265
391
|
// query only at completion (item/started may be query-less or absent entirely,
|
|
266
|
-
// so
|
|
267
|
-
const
|
|
268
|
-
|
|
269
|
-
|
|
392
|
+
// so a completed-only tool still gets its row).
|
|
393
|
+
const previous = toolCalls.get(projected.id);
|
|
394
|
+
const summary = !CODEX_GENERIC_TOOL_SUMMARIES.has(projected.summary)
|
|
395
|
+
? projected.summary
|
|
396
|
+
: (previous?.summary || projected.summary);
|
|
397
|
+
const call = {
|
|
398
|
+
...previous,
|
|
399
|
+
...projected,
|
|
400
|
+
summary,
|
|
401
|
+
input: projected.input ?? previous?.input ?? null,
|
|
402
|
+
// Some app-server versions stream output deltas but omit aggregatedOutput on the
|
|
403
|
+
// terminal item. Preserve the accumulated live result in that case.
|
|
404
|
+
result: projected.result ?? previous?.result ?? null,
|
|
405
|
+
};
|
|
406
|
+
toolCalls.set(call.id, call);
|
|
407
|
+
ctx.emit({ type: 'tool', call });
|
|
270
408
|
}
|
|
271
409
|
break;
|
|
272
410
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pikiloom/kernel",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.7",
|
|
4
4
|
"description": "Heterogeneous coding agents (Claude / Codex / Gemini / ACP) -> an interaction-friendly, accumulating session snapshot + control handle, over pluggable surfaces (IM, Web, tunnel, TUI). The reusable core pikiloom itself is built on.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|