march-cli 0.1.16 → 0.1.18
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/package.json
CHANGED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { getOpenAICodexWebSocketDebugStats } from "@earendil-works/pi-ai/openai-codex-responses";
|
|
2
|
+
|
|
3
|
+
export function getCodexTransportDebugSnapshot(session) {
|
|
4
|
+
if (!isCodexTransportDebugEnabled()) return null;
|
|
5
|
+
const sessionId = session?.sessionId;
|
|
6
|
+
return sessionId ? (getOpenAICodexWebSocketDebugStats(sessionId) ?? null) : null;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function dumpCodexTransportDebug({ before, session, ui, logger }) {
|
|
10
|
+
if (!isCodexTransportDebugEnabled()) return;
|
|
11
|
+
const sessionId = session?.sessionId;
|
|
12
|
+
const after = sessionId ? (getOpenAICodexWebSocketDebugStats(sessionId) ?? null) : null;
|
|
13
|
+
const fields = formatCodexTransportDebugFields(sessionId, before, after);
|
|
14
|
+
logger?.event("codex.transport", fields);
|
|
15
|
+
writeCodexTransportDebug(ui, formatCodexTransportDebugLines(fields));
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function isCodexTransportDebugEnabled() {
|
|
19
|
+
const value = process.env.MARCH_CODEX_TRANSPORT_DEBUG;
|
|
20
|
+
return value === "1" || value === "true" || value === "yes";
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function formatCodexTransportDebugFields(sessionId, before, after) {
|
|
24
|
+
const delta = (key) => (after?.[key] ?? 0) - (before?.[key] ?? 0);
|
|
25
|
+
return {
|
|
26
|
+
sessionId: sessionId ?? "unknown",
|
|
27
|
+
requests: delta("requests"),
|
|
28
|
+
totalRequests: after?.requests ?? 0,
|
|
29
|
+
connectionsCreated: delta("connectionsCreated"),
|
|
30
|
+
connectionsReused: delta("connectionsReused"),
|
|
31
|
+
cachedContextRequests: delta("cachedContextRequests"),
|
|
32
|
+
storeTrueRequests: delta("storeTrueRequests"),
|
|
33
|
+
fullContextRequests: delta("fullContextRequests"),
|
|
34
|
+
deltaRequests: delta("deltaRequests"),
|
|
35
|
+
websocketFailures: delta("websocketFailures"),
|
|
36
|
+
sseFallbacks: delta("sseFallbacks"),
|
|
37
|
+
websocketFallbackActive: Boolean(after?.websocketFallbackActive),
|
|
38
|
+
lastInputItems: after?.lastInputItems ?? 0,
|
|
39
|
+
lastDeltaInputItems: after?.lastDeltaInputItems ?? 0,
|
|
40
|
+
lastWebSocketError: after?.lastWebSocketError ?? null,
|
|
41
|
+
hasStats: Boolean(after),
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function formatCodexTransportDebugLines(fields) {
|
|
46
|
+
if (!fields.hasStats) return [`[codex-transport] sessionId=${fields.sessionId} no Codex WebSocket stats`];
|
|
47
|
+
return [
|
|
48
|
+
`[codex-transport] sessionId=${fields.sessionId}`,
|
|
49
|
+
` requests=${fields.requests} totalRequests=${fields.totalRequests}`,
|
|
50
|
+
` wsConnections created=${fields.connectionsCreated} reused=${fields.connectionsReused}`,
|
|
51
|
+
` modes full=${fields.fullContextRequests} delta=${fields.deltaRequests} cached=${fields.cachedContextRequests} storeTrue=${fields.storeTrueRequests}`,
|
|
52
|
+
` fallback websocketFailures=${fields.websocketFailures} sseFallbacks=${fields.sseFallbacks} active=${fields.websocketFallbackActive}`,
|
|
53
|
+
` lastInputItems=${fields.lastInputItems} lastDeltaInputItems=${fields.lastDeltaInputItems}`,
|
|
54
|
+
...(fields.lastWebSocketError ? [` lastWebSocketError=${fields.lastWebSocketError}`] : []),
|
|
55
|
+
];
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function writeCodexTransportDebug(ui, lines) {
|
|
59
|
+
if (ui?.debugLines) {
|
|
60
|
+
ui.debugLines(lines);
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
if (!ui?.writeln) return;
|
|
64
|
+
for (const line of lines) ui.writeln(line);
|
|
65
|
+
}
|
package/src/agent/runner.mjs
CHANGED
|
@@ -5,14 +5,14 @@ import { createMarchLifecycleAdapter } from "../extensions/lifecycle-adapter.mjs
|
|
|
5
5
|
import { syncPiSessionSidecar } from "../session/sidecar-sync.mjs";
|
|
6
6
|
import { LspService } from "../lsp/service.mjs";
|
|
7
7
|
import { formatLspServiceEvent } from "../lsp/status-message.mjs";
|
|
8
|
-
import {
|
|
9
|
-
import { appendProviderUserMessage, estimateProviderPayloadTokens, installModelPayloadDumper, replaceProviderContextMessages } from "./model-payload-dumper.mjs";
|
|
8
|
+
import { estimateProviderPayloadTokens, installModelPayloadDumper, replaceProviderContextMessages } from "./model-payload-dumper.mjs";
|
|
10
9
|
import { resolveInitialModel, resolveRunnerSessionManager } from "./runner/runner-init.mjs";
|
|
11
10
|
import { runRunnerCleanup } from "./runner/runner-cleanup.mjs";
|
|
12
11
|
import { createRunnerRuntimeHost } from "./runtime/runner-runtime-host.mjs";
|
|
13
12
|
import { createRuntimeUiBridge } from "./runtime/ui-event-bridge.mjs";
|
|
14
13
|
import { getRunnerSessionStats, syncEngineSessionState } from "./runner/runner-session-state.mjs";
|
|
15
14
|
import { notifyTurnEndBestEffort, notifyTurnEndDetached, providerContextToPayload } from "./runner/runner-utils.mjs";
|
|
15
|
+
import { dumpCodexTransportDebug, getCodexTransportDebugSnapshot } from "./runner/codex-transport-debug.mjs";
|
|
16
16
|
import { resolveRunnerSessionOptions } from "./session/session-options.mjs";
|
|
17
17
|
import { createSessionBinding } from "./session/session-binding.mjs";
|
|
18
18
|
import { maybeAutoNameSession } from "./session/session-auto-name.mjs";
|
|
@@ -55,7 +55,6 @@ export async function createRunner({ cwd, modelId = null, provider = null, provi
|
|
|
55
55
|
let currentModelCallKind = "model", currentTurnId = null, currentPromptForContext = "";
|
|
56
56
|
let currentTurnContextMode = "rebuild";
|
|
57
57
|
let nextTurnContextMode = "rebuild";
|
|
58
|
-
let pendingMidTurnRecallHints = [];
|
|
59
58
|
let lastNotificationResult = null, runtimeHost = null, lifecycleAdapter = null;
|
|
60
59
|
let _currentFastEntry = null;
|
|
61
60
|
if (useRuntimeHost) {
|
|
@@ -111,8 +110,8 @@ export async function createRunner({ cwd, modelId = null, provider = null, provi
|
|
|
111
110
|
const contextMode = nextTurnContextMode;
|
|
112
111
|
currentTurnContextMode = contextMode;
|
|
113
112
|
nextTurnContextMode = "rebuild";
|
|
114
|
-
pendingMidTurnRecallHints = [];
|
|
115
113
|
const turnStartedAt = Date.now();
|
|
114
|
+
const codexTransportStatsBefore = getCodexTransportDebugSnapshot(sessionBinding.get());
|
|
116
115
|
const turnLog = beginLoggedTurn({ logger, engine, modelId, provider, contextMode, userMessage, userRecallHints, startedAt: turnStartedAt }); currentTurnId = turnLog.turnId;
|
|
117
116
|
try {
|
|
118
117
|
const result = await runRunnerTurn({
|
|
@@ -121,7 +120,6 @@ export async function createRunner({ cwd, modelId = null, provider = null, provi
|
|
|
121
120
|
setModelCallKind: (kind) => { currentModelCallKind = kind; },
|
|
122
121
|
logger: turnLog.logger,
|
|
123
122
|
setPhase: turnLog.setPhase,
|
|
124
|
-
onMidTurnRecallHints: (hints) => { pendingMidTurnRecallHints.push(...hints); },
|
|
125
123
|
syncCurrentPiSidecar,
|
|
126
124
|
autoNameSession,
|
|
127
125
|
contextMode,
|
|
@@ -144,6 +142,7 @@ export async function createRunner({ cwd, modelId = null, provider = null, provi
|
|
|
144
142
|
turnLog.endError(err);
|
|
145
143
|
throw err;
|
|
146
144
|
} finally {
|
|
145
|
+
dumpCodexTransportDebug({ before: codexTransportStatsBefore, session: sessionBinding.get(), ui: runtimeUi, logger });
|
|
147
146
|
currentTurnId = null;
|
|
148
147
|
currentTurnContextMode = "rebuild";
|
|
149
148
|
}
|
|
@@ -289,10 +288,6 @@ export async function createRunner({ cwd, modelId = null, provider = null, provi
|
|
|
289
288
|
: replaceProviderContextMessages(payload, engine.buildProviderContext(currentPromptForContext));
|
|
290
289
|
nextPayload = injectHostedTools(nextPayload, model, hostedTools);
|
|
291
290
|
if (_currentFastEntry) nextPayload = { ...nextPayload, service_tier: "priority" };
|
|
292
|
-
if (pendingMidTurnRecallHints.length > 0) {
|
|
293
|
-
nextPayload = appendProviderUserMessage(nextPayload, formatRecallHints("assistant", pendingMidTurnRecallHints));
|
|
294
|
-
pendingMidTurnRecallHints = [];
|
|
295
|
-
}
|
|
296
291
|
return nextPayload;
|
|
297
292
|
}
|
|
298
293
|
}
|
|
@@ -12,6 +12,7 @@ export function createRemoteRuntimeUiClient(peer) {
|
|
|
12
12
|
retryStart: (event) => peer.notify("uiEvent", { type: "retry_start", ...event }),
|
|
13
13
|
retryEnd: (event) => peer.notify("uiEvent", { type: "retry_end", ...event }),
|
|
14
14
|
status: (text) => peer.notify("uiEvent", { type: "status", text }),
|
|
15
|
+
debugLines: (lines) => peer.notify("uiEvent", { type: "debug_lines", lines }),
|
|
15
16
|
memoryHint: ({ source, hints }) => peer.notify("uiEvent", { type: "memory_hint", source, hints }),
|
|
16
17
|
editDiff: (path, diffLines) => peer.notify("uiEvent", { type: "edit_diff", path, diffLines }),
|
|
17
18
|
requestPermission: (request) => peer.call("uiRequest", { type: "permission_request", ...request }),
|
|
@@ -49,6 +49,7 @@ export function createRuntimeUiClient(eventBus) {
|
|
|
49
49
|
retryStart: (event) => eventBus.emit({ type: "retry_start", ...event }),
|
|
50
50
|
retryEnd: (event) => eventBus.emit({ type: "retry_end", ...event }),
|
|
51
51
|
status: (text) => eventBus.emit({ type: "status", text }),
|
|
52
|
+
debugLines: (lines) => eventBus.emit({ type: "debug_lines", lines }),
|
|
52
53
|
memoryHint: ({ source, hints }) => eventBus.emit({ type: "memory_hint", source, hints }),
|
|
53
54
|
editDiff: (path, diffLines) => eventBus.emit({ type: "edit_diff", path, diffLines }),
|
|
54
55
|
requestPermission: (request) => eventBus.request({ type: "permission_request", ...request }),
|
|
@@ -69,6 +70,7 @@ export function dispatchRuntimeUiEvent(ui, event) {
|
|
|
69
70
|
case "retry_start": return ui.retryStart?.(pickRetryStart(event));
|
|
70
71
|
case "retry_end": return ui.retryEnd?.(pickRetryEnd(event));
|
|
71
72
|
case "status": return ui.status?.(event.text);
|
|
73
|
+
case "debug_lines": return writeDebugLines(ui, event.lines);
|
|
72
74
|
case "memory_hint": return ui.memoryHint?.({ source: event.source, hints: event.hints });
|
|
73
75
|
case "edit_diff": return ui.editDiff?.(event.path, event.diffLines);
|
|
74
76
|
case "permission_request": return ui.requestPermission?.({ toolName: event.toolName, params: event.params, category: event.category });
|
|
@@ -76,6 +78,14 @@ export function dispatchRuntimeUiEvent(ui, event) {
|
|
|
76
78
|
}
|
|
77
79
|
}
|
|
78
80
|
|
|
81
|
+
function writeDebugLines(ui, lines) {
|
|
82
|
+
if (!Array.isArray(lines)) return undefined;
|
|
83
|
+
if (ui?.debugLines) return ui.debugLines(lines);
|
|
84
|
+
if (!ui?.writeln) return undefined;
|
|
85
|
+
for (const line of lines) ui.writeln(line);
|
|
86
|
+
return undefined;
|
|
87
|
+
}
|
|
88
|
+
|
|
79
89
|
function pickRetryStart({ attempt, maxAttempts, delayMs, errorMessage }) {
|
|
80
90
|
return { attempt, maxAttempts, delayMs, errorMessage };
|
|
81
91
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { formatRecallHints } from "../../memory/markdown-store.mjs";
|
|
1
2
|
import { resolveImageAttachmentReferences } from "../../session/attachment-references.mjs";
|
|
2
3
|
import { closeAssistantReply, compactAssistantContext, createTurnEventState, handleRunnerSessionEvent } from "./turn-events.mjs";
|
|
3
4
|
|
|
@@ -13,7 +14,6 @@ export async function runRunnerTurn({
|
|
|
13
14
|
setModelCallKind,
|
|
14
15
|
logger = null,
|
|
15
16
|
setPhase = null,
|
|
16
|
-
onMidTurnRecallHints,
|
|
17
17
|
syncCurrentPiSidecar,
|
|
18
18
|
autoNameSession,
|
|
19
19
|
contextMode = "rebuild",
|
|
@@ -41,7 +41,7 @@ export async function runRunnerTurn({
|
|
|
41
41
|
const hints = flushAssistantRecall({ memoryStore, engine, turnState, currentProject });
|
|
42
42
|
if (hints.length > 0) {
|
|
43
43
|
midTurnRecallHints.push(...hints);
|
|
44
|
-
|
|
44
|
+
queueMidTurnRecallHints(activeSession, hints, logger);
|
|
45
45
|
ui.memoryHint?.({ source: "assistant", hints });
|
|
46
46
|
}
|
|
47
47
|
}
|
|
@@ -89,6 +89,20 @@ export async function runRunnerTurn({
|
|
|
89
89
|
}
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
+
function queueMidTurnRecallHints(session, hints, logger) {
|
|
93
|
+
const content = formatRecallHints("assistant", hints);
|
|
94
|
+
if (!content) return;
|
|
95
|
+
const injected = session.sendCustomMessage?.({
|
|
96
|
+
customType: "march.memory_hint",
|
|
97
|
+
content,
|
|
98
|
+
display: false,
|
|
99
|
+
details: { source: "assistant" },
|
|
100
|
+
}, { deliverAs: "steer" });
|
|
101
|
+
void injected?.catch?.((err) => {
|
|
102
|
+
logger?.debug("memory.mid_turn_recall.inject_failed", { errorMessage: err?.message ?? String(err) });
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
|
|
92
106
|
function logSessionEvent(logger, event) {
|
|
93
107
|
if (!logger) return;
|
|
94
108
|
if (event.type === "message_update") {
|