@nextclaw/nextclaw-ncp-runtime-stdio-client 0.2.17 → 0.3.0

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.
@@ -1 +1 @@
1
- {"version":3,"file":"stdio-runtime.service.d.ts","names":[],"sources":["../src/stdio-runtime.service.ts"],"mappings":";;;;KAkCY,iCAAA,GAAoC,0BAAA;EAC9C,YAAA,GAAe,gCAAA;EACf,YAAA,IAAgB,KAAA,EAAO,gBAAA,KAAqB,aAAA,CAAc,UAAA;EAC1D,oBAAA,IAAwB,KAAA,EAAO,gBAAA,KAAqB,uBAAA;AAAA;AAAA,cA8tBzC,2BAAA,YAAuC,eAAA;EAAA,iBAGrB,MAAA;EAAA,iBAFZ,OAAA;cAEY,MAAA,EAAQ,iCAAA;EAIrC,GAAA,GACE,IAAA,EAAM,2BAAA,EACN,KAAA,EAAO,gBAAA,EACP,OAAA,GAAU,kBAAA,KACT,cAAA,CAAe,gBAAA;EAelB,OAAA,QAAoB,OAAA;AAAA"}
1
+ {"version":3,"file":"stdio-runtime.service.d.ts","names":[],"sources":["../src/stdio-runtime.service.ts"],"mappings":";;;;KAoCY,iCAAA,GAAoC,0BAAA;EAC9C,YAAA,GAAe,gCAAA;EACf,YAAA,IAAgB,KAAA,EAAO,gBAAA,KAAqB,aAAA,CAAc,UAAA;EAC1D,oBAAA,IAAwB,KAAA,EAAO,gBAAA,KAAqB,uBAAA;AAAA;AAAA,cAyuBzC,2BAAA,YAAuC,eAAA;EAAA,iBAGrB,MAAA;EAAA,iBAFZ,OAAA;cAEY,MAAA,EAAQ,iCAAA;EAIrC,GAAA,GACE,IAAA,EAAM,2BAAA,EACN,KAAA,EAAO,gBAAA,EACP,OAAA,GAAU,kBAAA,KACT,cAAA,CAAe,gBAAA;EAelB,OAAA,QAAoB,OAAA;AAAA"}
@@ -1,13 +1,13 @@
1
1
  import { NARP_STDIO_PROMPT_META_KEY, buildStdioRuntimeLaunchEnv } from "./stdio-runtime-config.utils.js";
2
2
  import { buildSpawnFailureMessage, isAbortLikeRuntimeError, normalizeRuntimeError } from "./stdio-runtime-error.utils.js";
3
- import { SESSION_METADATA_PATCH_KIND, createPromptTimeoutRecoveryEvents } from "./utils/stdio-runtime-recovery.utils.js";
3
+ import { SESSION_METADATA_PATCH_KIND, createPromptTimeoutRecoveryEvents, readSessionMetadataPatch } from "./utils/stdio-runtime-recovery.utils.js";
4
4
  import { extractPromptText, resolveModelId } from "./utils/stdio-runtime-input.utils.js";
5
5
  import { resolveToolNameFromAcpUpdate } from "./stdio-runtime-tool-name.utils.js";
6
6
  import { randomUUID } from "node:crypto";
7
7
  import { spawn } from "node:child_process";
8
8
  import { Readable, Writable } from "node:stream";
9
9
  import * as acp from "@agentclientprotocol/sdk";
10
- import { NcpEventType } from "@nextclaw/ncp";
10
+ import { NcpEventType, createNcpEndpointEvent } from "@nextclaw/ncp";
11
11
  import { DefaultNcpAgentConversationStateManager } from "@nextclaw/ncp-toolkit";
12
12
  //#region src/stdio-runtime.service.ts
13
13
  const HERMES_ACP_ROUTE_BRIDGE_ENV = "NEXTCLAW_HERMES_ACP_ROUTE_BRIDGE";
@@ -200,6 +200,7 @@ var StdioRuntimeRunController = class {
200
200
  resolvedTools;
201
201
  resolvedProviderRoute;
202
202
  runId;
203
+ runStartedAt;
203
204
  constructor(session, input, stateManager, resolveTools, resolveProviderRoute) {
204
205
  this.session = session;
205
206
  this.input = input;
@@ -265,14 +266,16 @@ var StdioRuntimeRunController = class {
265
266
  ...this.input.correlationId ? { correlationId: this.input.correlationId } : {}
266
267
  }
267
268
  });
269
+ this.runStartedAt = (/* @__PURE__ */ new Date()).toISOString();
268
270
  yield* this.emitEvent({
269
271
  type: NcpEventType.RunStarted,
270
272
  payload: {
271
273
  sessionId: this.input.sessionId,
272
274
  messageId: assistantMessageId,
273
- runId: this.runId
275
+ runId: this.runId,
276
+ startedAt: this.runStartedAt
274
277
  }
275
- });
278
+ }, this.runStartedAt);
276
279
  };
277
280
  drainPromptUpdates = async function* (assistantMessageId, promptState) {
278
281
  while (!promptState.settled || this.buffer.hasItems()) {
@@ -297,14 +300,17 @@ var StdioRuntimeRunController = class {
297
300
  message: completedMessage
298
301
  }
299
302
  });
303
+ const endedAt = (/* @__PURE__ */ new Date()).toISOString();
300
304
  yield* this.emitEvent({
301
305
  type: NcpEventType.RunFinished,
302
306
  payload: {
303
307
  sessionId: this.input.sessionId,
304
308
  messageId: assistantMessageId,
305
- runId: this.runId
309
+ runId: this.runId,
310
+ startedAt: this.runStartedAt,
311
+ endedAt
306
312
  }
307
- });
313
+ }, endedAt);
308
314
  };
309
315
  emitFailureEvents = async function* (assistantMessageId, error) {
310
316
  const ncpError = normalizeRuntimeError(error, { stderr: this.session.readStderr() });
@@ -325,19 +331,23 @@ var StdioRuntimeRunController = class {
325
331
  error: ncpError
326
332
  }
327
333
  });
334
+ const endedAt = (/* @__PURE__ */ new Date()).toISOString();
328
335
  yield* this.emitEvent({
329
336
  type: NcpEventType.RunError,
330
337
  payload: {
331
338
  sessionId: this.input.sessionId,
332
339
  messageId: assistantMessageId,
333
340
  runId: this.runId,
334
- error: ncpError.message
341
+ error: ncpError.message,
342
+ startedAt: this.runStartedAt,
343
+ endedAt
335
344
  }
336
- });
345
+ }, endedAt);
337
346
  };
338
- emitEvent = async function* (event) {
339
- await this.conversationStateManager.dispatch(event);
340
- yield event;
347
+ emitEvent = async function* (event, occurredAt) {
348
+ const stampedEvent = createNcpEndpointEvent(event, occurredAt);
349
+ await this.conversationStateManager.dispatch(stampedEvent);
350
+ yield stampedEvent;
341
351
  };
342
352
  buildCompletedAssistantMessage = (assistantMessageId) => {
343
353
  const snapshot = this.conversationStateManager.getSnapshot();
@@ -426,7 +436,7 @@ var StdioRuntimeRunController = class {
426
436
  return events;
427
437
  };
428
438
  emitToolCallStart = (update, messageId) => {
429
- const toolName = resolveToolName(update);
439
+ const toolName = resolveToolNameFromAcpUpdate(update);
430
440
  const args = serializeToolArgs(update.rawInput);
431
441
  this.toolStates.set(update.toolCallId, {
432
442
  toolName,
@@ -542,17 +552,6 @@ var StdioRuntimeNcpAgentRuntime = class {
542
552
  await this.session.dispose();
543
553
  };
544
554
  };
545
- function readSessionMetadataPatch(meta) {
546
- const narpMeta = isRecord(meta) ? meta[NARP_STDIO_PROMPT_META_KEY] : void 0;
547
- const patch = isRecord(narpMeta) ? narpMeta.sessionMetadataPatch : void 0;
548
- return isRecord(patch) && Object.keys(patch).length > 0 ? structuredClone(patch) : null;
549
- }
550
- function isRecord(value) {
551
- return typeof value === "object" && value !== null && !Array.isArray(value);
552
- }
553
- function resolveToolName(update) {
554
- return resolveToolNameFromAcpUpdate(update);
555
- }
556
555
  function createAssistantMessageId(requestMessageId) {
557
556
  return `assistant:${requestMessageId.trim() || "request"}:${randomUUID()}`;
558
557
  }
@@ -1 +1 @@
1
- {"version":3,"file":"stdio-runtime.service.js","names":[],"sources":["../src/stdio-runtime.service.ts"],"sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { spawn, type ChildProcessWithoutNullStreams } from \"node:child_process\";\nimport { Readable, Writable } from \"node:stream\";\nimport * as acp from \"@agentclientprotocol/sdk\";\nimport {\n NcpEventType,\n type NcpAgentConversationStateManager,\n type NcpAgentRunInput,\n type NcpAgentRunOptions,\n type NcpAgentRuntime,\n type NcpEndpointEvent,\n type NcpMessage,\n type NcpProviderRuntimeRoute,\n type OpenAITool,\n} from \"@nextclaw/ncp\";\nimport { DefaultNcpAgentConversationStateManager } from \"@nextclaw/ncp-toolkit\";\nimport type { StdioRuntimeResolvedConfig, NarpStdioPromptMeta } from \"./stdio-runtime-config.utils.js\";\nimport {\n NARP_STDIO_PROMPT_META_KEY,\n buildStdioRuntimeLaunchEnv,\n} from \"./stdio-runtime-config.utils.js\";\nimport {\n buildSpawnFailureMessage,\n isAbortLikeRuntimeError,\n normalizeRuntimeError,\n} from \"./stdio-runtime-error.utils.js\";\nimport {\n createPromptTimeoutRecoveryEvents,\n SESSION_METADATA_PATCH_KIND,\n} from \"./utils/stdio-runtime-recovery.utils.js\";\nimport { extractPromptText, resolveModelId } from \"./utils/stdio-runtime-input.utils.js\";\nimport { resolveToolNameFromAcpUpdate } from \"./stdio-runtime-tool-name.utils.js\";\ntype AcpClientUpdate = acp.SessionUpdate;\nconst HERMES_ACP_ROUTE_BRIDGE_ENV = \"NEXTCLAW_HERMES_ACP_ROUTE_BRIDGE\";\nexport type StdioRuntimeNcpAgentRuntimeConfig = StdioRuntimeResolvedConfig & {\n stateManager?: NcpAgentConversationStateManager;\n resolveTools?: (input: NcpAgentRunInput) => ReadonlyArray<OpenAITool> | undefined;\n resolveProviderRoute?: (input: NcpAgentRunInput) => NcpProviderRuntimeRoute | undefined;\n};\ntype AcpToolState = {\n toolName: string;\n args?: string;\n completed: boolean;\n};\n\ntype PromptExecutionState = { settled: boolean; error: unknown };\n\nclass UpdateBuffer {\n private readonly updates: AcpClientUpdate[] = [];\n private waiters = new Set<() => void>();\n\n push = (update: AcpClientUpdate): void => {\n this.updates.push(update);\n this.flush();\n };\n\n shift = (): AcpClientUpdate | undefined => this.updates.shift();\n\n hasItems = (): boolean => this.updates.length > 0;\n\n waitForChange = async (): Promise<void> => {\n if (this.updates.length > 0) {\n return;\n }\n await new Promise<void>((resolve) => {\n this.waiters.add(resolve);\n });\n };\n\n notify = (): void => {\n this.flush();\n };\n\n private flush = (): void => {\n if (this.waiters.size === 0) {\n return;\n }\n const waiters = [...this.waiters];\n this.waiters.clear();\n for (const waiter of waiters) {\n waiter();\n }\n };\n}\n\nclass StdioRuntimeClientBridge {\n private activeSessionId: string | null = null;\n private updateHandler: ((update: AcpClientUpdate) => void) | null = null;\n\n attach = (params: {\n sessionId: string;\n onUpdate: (update: AcpClientUpdate) => void;\n }): (() => void) => {\n this.activeSessionId = params.sessionId;\n this.updateHandler = params.onUpdate;\n return () => {\n if (this.activeSessionId !== params.sessionId) {\n return;\n }\n this.activeSessionId = null;\n this.updateHandler = null;\n };\n };\n\n sessionUpdate = async (params: { sessionId: string; update: AcpClientUpdate }): Promise<void> => {\n if (params.sessionId !== this.activeSessionId) {\n return;\n }\n this.updateHandler?.(params.update);\n };\n\n requestPermission = async (): Promise<{\n outcome: { outcome: \"cancelled\" };\n }> => ({\n outcome: { outcome: \"cancelled\" },\n });\n\n readTextFile = async (): Promise<{ content: string }> => ({ content: \"\" });\n\n writeTextFile = async (): Promise<Record<string, never>> => ({});\n}\n\nclass StdioRuntimeSession {\n private child: ChildProcessWithoutNullStreams | null = null;\n private connection: acp.ClientSideConnection | null = null;\n private promptInFlight = false;\n private remoteSessionId: string | null = null;\n private remoteSessionCwd: string | null = null;\n private readonly clientBridge = new StdioRuntimeClientBridge();\n private stderr = \"\";\n private pendingProviderRoute: NcpProviderRuntimeRoute | undefined;\n\n constructor(private readonly config: StdioRuntimeNcpAgentRuntimeConfig) {}\n\n ensureStarted = async (params: {\n cwd?: string;\n providerRoute?: NcpProviderRuntimeRoute;\n }): Promise<void> => {\n const { cwd, providerRoute } = params;\n this.pendingProviderRoute = providerRoute;\n if (this.connection && this.remoteSessionId) {\n if (this.remoteSessionCwd === cwd) {\n return;\n }\n await this.dispose();\n }\n if (!cwd) {\n throw new Error(\"[narp-stdio] missing execution cwd for stdio runtime session\");\n }\n\n const env = buildStdioRuntimeLaunchEnv({\n configEnv: this.config.env,\n providerRoute: this.pendingProviderRoute,\n });\n\n this.child = spawn(this.config.command, this.config.args, {\n cwd: this.config.cwd,\n env,\n stdio: [\"pipe\", \"pipe\", \"pipe\"], windowsHide: true,\n });\n const spawnErrorPromise = new Promise<never>((_, reject) => {\n this.child?.once(\"error\", (error) => {\n reject(\n new Error(\n buildSpawnFailureMessage({\n command: this.config.command,\n cwd: this.config.cwd,\n error,\n }),\n ),\n );\n });\n });\n this.child.stderr.setEncoding(\"utf8\");\n this.child.stderr.on(\"data\", (chunk: string) => {\n this.stderr = `${this.stderr}${chunk}`.slice(-4000);\n });\n\n const stream = acp.ndJsonStream(\n Writable.toWeb(this.child.stdin),\n Readable.toWeb(this.child.stdout),\n );\n this.connection = new acp.ClientSideConnection(() => this.clientBridge, stream);\n\n const session = await Promise.race([\n (async () => {\n await withTimeout(\n this.connection?.initialize({\n protocolVersion: acp.PROTOCOL_VERSION,\n clientCapabilities: {},\n }) ?? Promise.reject(new Error(\"[narp-stdio] stdio runtime connection not started\")),\n this.config.startupTimeoutMs,\n \"[narp-stdio] timed out initializing stdio runtime\",\n );\n\n return withTimeout(\n this.connection?.newSession({\n cwd,\n mcpServers: [],\n }) ?? Promise.reject(new Error(\"[narp-stdio] stdio runtime connection not started\")),\n this.config.startupTimeoutMs,\n \"[narp-stdio] timed out creating remote stdio session\",\n );\n })(),\n spawnErrorPromise,\n ]);\n this.remoteSessionId = session.sessionId;\n this.remoteSessionCwd = cwd;\n };\n\n runPrompt = async (params: {\n sessionId: string;\n text: string;\n meta: NarpStdioPromptMeta;\n modelId?: string;\n signal?: AbortSignal;\n onUpdate: (update: AcpClientUpdate) => void;\n }): Promise<acp.PromptResponse> => {\n const { meta, modelId, onUpdate, sessionId, signal, text } = params;\n if (!this.connection || !this.remoteSessionId) {\n throw new Error(\"[narp-stdio] stdio runtime connection not started\");\n }\n if (this.promptInFlight) {\n throw new Error(\"[narp-stdio] concurrent prompt is not supported for one stdio session\");\n }\n\n this.promptInFlight = true;\n const detach = this.clientBridge.attach({\n sessionId: this.remoteSessionId,\n onUpdate,\n });\n const releaseAbort = this.bindAbortSignal(signal);\n\n try {\n if (modelId && this.config.env?.[HERMES_ACP_ROUTE_BRIDGE_ENV] !== \"1\") {\n try {\n // Hermes ACP must switch on prompt-scoped providerRoute, not modelId alone.\n await this.connection.unstable_setSessionModel({\n sessionId: this.remoteSessionId,\n modelId,\n });\n } catch {\n // Not all ACP agents implement unstable session model switching.\n }\n }\n\n return await withTimeout(\n this.connection.prompt({\n sessionId: this.remoteSessionId,\n prompt: [{ type: \"text\", text }],\n _meta: {\n [NARP_STDIO_PROMPT_META_KEY]: meta,\n },\n }),\n this.config.requestTimeoutMs,\n `[narp-stdio] prompt timed out for session ${sessionId}`,\n );\n } finally {\n releaseAbort();\n detach();\n this.promptInFlight = false;\n }\n };\n\n cancel = async (): Promise<void> => {\n if (!this.connection || !this.remoteSessionId) {\n return;\n }\n try {\n await this.connection.cancel({\n sessionId: this.remoteSessionId,\n });\n } catch {\n // Best effort.\n }\n };\n\n private bindAbortSignal = (signal?: AbortSignal): (() => void) => {\n if (!signal) {\n return () => undefined;\n }\n\n const onAbort = (): void => {\n void this.cancel();\n };\n\n if (signal.aborted) {\n onAbort();\n return () => undefined;\n }\n\n signal.addEventListener(\"abort\", onAbort, { once: true });\n return () => {\n signal.removeEventListener(\"abort\", onAbort);\n };\n };\n\n readStderr = (): string => this.stderr;\n\n readPromptTimeoutMetadataResetKeys = (): readonly string[] | undefined =>\n this.config.resetSessionMetadataOnPromptTimeout;\n\n dispose = async (): Promise<void> => {\n await this.cancel();\n const child = this.child;\n this.connection = null;\n this.remoteSessionId = null;\n this.remoteSessionCwd = null;\n this.child = null;\n if (!child || child.killed || child.exitCode !== null || child.signalCode !== null) {\n return;\n }\n\n const exited = new Promise<void>((resolve) => {\n child.once(\"exit\", () => resolve());\n child.once(\"error\", () => resolve());\n });\n const forceKill = setTimeout(() => {\n child.kill(\"SIGKILL\");\n }, 3_000);\n forceKill.unref();\n child.kill(\"SIGTERM\");\n await exited;\n clearTimeout(forceKill);\n };\n}\n\nclass StdioRuntimeRunController {\n private readonly buffer = new UpdateBuffer();\n private readonly conversationStateManager: NcpAgentConversationStateManager;\n private readonly toolStates = new Map<string, AcpToolState>();\n private textStarted = false;\n private reasoningStarted = false;\n private readonly resolvedTools: ReadonlyArray<OpenAITool>;\n private readonly resolvedProviderRoute: NcpProviderRuntimeRoute | undefined;\n private readonly runId: string;\n\n constructor(\n private readonly session: StdioRuntimeSession,\n private readonly input: NcpAgentRunInput,\n stateManager?: NcpAgentConversationStateManager,\n private readonly resolveTools?: (input: NcpAgentRunInput) => ReadonlyArray<OpenAITool> | undefined,\n private readonly resolveProviderRoute?: (input: NcpAgentRunInput) => NcpProviderRuntimeRoute | undefined,\n ) {\n this.conversationStateManager =\n stateManager ?? new DefaultNcpAgentConversationStateManager();\n this.resolvedTools = resolveTools?.(input) ?? [];\n this.resolvedProviderRoute = resolveProviderRoute?.(input);\n this.runId = (input as NcpAgentRunInput & { runId?: string }).runId ?? `narp-stdio:${input.sessionId}:${randomUUID()}`;\n }\n execute = async function* (\n this: StdioRuntimeRunController,\n options?: NcpAgentRunOptions,\n ): AsyncGenerator<NcpEndpointEvent> {\n const requestMessage = this.input.messages.at(-1);\n if (!requestMessage) {\n throw new Error(\"[narp-stdio] runtime.run requires at least one input message\");\n }\n\n const assistantMessageId = createAssistantMessageId(requestMessage.id);\n const promptPromise = this.session.runPrompt({\n sessionId: this.input.sessionId,\n text: extractPromptText(requestMessage),\n meta: {\n ...(this.input.correlationId ? { correlationId: this.input.correlationId } : {}),\n ...(this.resolvedProviderRoute ? { providerRoute: this.resolvedProviderRoute } : {}),\n ...(this.input.metadata ? { sessionMetadata: this.input.metadata } : {}),\n ...(this.resolvedTools.length > 0 ? { tools: this.resolvedTools } : {}),\n },\n modelId: resolveModelId({\n providerRoute: this.resolvedProviderRoute,\n metadata: this.input.metadata,\n }),\n signal: options?.signal,\n onUpdate: (update) => this.buffer.push(update),\n });\n const promptState = this.trackPromptState(promptPromise);\n\n yield* this.emitRunStartedEvents(assistantMessageId);\n\n try {\n yield* this.drainPromptUpdates(assistantMessageId, promptState);\n if (this.shouldExitForAbort(options, promptState.error)) {\n return;\n }\n if (promptState.error) throw promptState.error;\n yield* this.emitCompletionEvents(assistantMessageId);\n } catch (error) {\n if (this.shouldExitForAbort(options, error)) {\n return;\n }\n yield* this.emitFailureEvents(assistantMessageId, error);\n }\n };\n private trackPromptState = (\n promptPromise: Promise<acp.PromptResponse>,\n ): PromptExecutionState => {\n const promptState: PromptExecutionState = {\n settled: false,\n error: null,\n };\n\n promptPromise\n .then(() => {\n promptState.settled = true;\n this.buffer.notify();\n })\n .catch((error) => {\n promptState.settled = true;\n promptState.error = error;\n this.buffer.notify();\n });\n\n return promptState;\n };\n private emitRunStartedEvents = async function* (\n this: StdioRuntimeRunController,\n assistantMessageId: string,\n ): AsyncGenerator<NcpEndpointEvent> {\n yield* this.emitEvent({\n type: NcpEventType.MessageAccepted,\n payload: {\n messageId: assistantMessageId,\n ...(this.input.correlationId ? { correlationId: this.input.correlationId } : {}),\n },\n });\n yield* this.emitEvent({\n type: NcpEventType.RunStarted,\n payload: {\n sessionId: this.input.sessionId,\n messageId: assistantMessageId,\n runId: this.runId,\n },\n });\n };\n private drainPromptUpdates = async function* (\n this: StdioRuntimeRunController,\n assistantMessageId: string,\n promptState: PromptExecutionState,\n ): AsyncGenerator<NcpEndpointEvent> {\n while (!promptState.settled || this.buffer.hasItems()) {\n const update = this.buffer.shift();\n if (!update) {\n await this.buffer.waitForChange();\n continue;\n }\n for (const event of this.translateUpdate(update, assistantMessageId)) {\n yield* this.emitEvent(event);\n }\n }\n };\n private shouldExitForAbort = (\n options: NcpAgentRunOptions | undefined,\n error: unknown,\n ): boolean => options?.signal?.aborted === true || isAbortLikeRuntimeError(error);\n private emitCompletionEvents = async function* (\n this: StdioRuntimeRunController,\n assistantMessageId: string,\n ): AsyncGenerator<NcpEndpointEvent> {\n for (const terminalEvent of this.createTerminalEvents(assistantMessageId)) {\n yield* this.emitEvent(terminalEvent);\n }\n\n const completedMessage = this.buildCompletedAssistantMessage(assistantMessageId);\n if (!completedMessage.parts.length) {\n throw new Error(\n `[narp-stdio] ACP prompt completed without any assistant content for session ${this.input.sessionId}. stderr=${this.session.readStderr()}`,\n );\n }\n\n yield* this.emitEvent({\n type: NcpEventType.MessageCompleted,\n payload: {\n sessionId: this.input.sessionId,\n correlationId: this.input.correlationId,\n message: completedMessage,\n },\n });\n yield* this.emitEvent({\n type: NcpEventType.RunFinished,\n payload: {\n sessionId: this.input.sessionId,\n messageId: assistantMessageId,\n runId: this.runId,\n },\n });\n };\n private emitFailureEvents = async function* (\n this: StdioRuntimeRunController,\n assistantMessageId: string,\n error: unknown,\n ): AsyncGenerator<NcpEndpointEvent> {\n const ncpError = normalizeRuntimeError(error, { stderr: this.session.readStderr() });\n for (const recoveryEvent of createPromptTimeoutRecoveryEvents({\n correlationId: this.input.correlationId,\n error,\n messageId: assistantMessageId,\n resetKeys: this.session.readPromptTimeoutMetadataResetKeys(),\n runId: this.runId,\n sessionId: this.input.sessionId,\n })) {\n yield* this.emitEvent(recoveryEvent);\n }\n yield* this.emitEvent({\n type: NcpEventType.MessageFailed,\n payload: {\n sessionId: this.input.sessionId,\n messageId: assistantMessageId,\n correlationId: this.input.correlationId,\n error: ncpError,\n },\n });\n yield* this.emitEvent({\n type: NcpEventType.RunError,\n payload: {\n sessionId: this.input.sessionId,\n messageId: assistantMessageId,\n runId: this.runId,\n error: ncpError.message,\n },\n });\n };\n private emitEvent = async function* (\n this: StdioRuntimeRunController,\n event: NcpEndpointEvent,\n ): AsyncGenerator<NcpEndpointEvent> {\n await this.conversationStateManager.dispatch(event);\n yield event;\n };\n private buildCompletedAssistantMessage = (assistantMessageId: string): NcpMessage => {\n const snapshot = this.conversationStateManager.getSnapshot();\n const message = snapshot.streamingMessage?.id === assistantMessageId\n ? snapshot.streamingMessage\n : snapshot.messages.find((candidate) => candidate.id === assistantMessageId);\n return message\n ? { ...structuredClone(message), status: \"final\" }\n : {\n id: assistantMessageId,\n sessionId: this.input.sessionId,\n role: \"assistant\",\n status: \"final\",\n parts: [],\n timestamp: new Date().toISOString(),\n };\n };\n private translateUpdate = (\n update: AcpClientUpdate,\n messageId: string,\n ): NcpEndpointEvent[] => {\n switch (update.sessionUpdate) {\n case \"agent_message_chunk\":\n return this.emitTextDelta(update.content, messageId);\n case \"agent_thought_chunk\":\n return this.emitReasoningDelta(update.content, messageId);\n case \"tool_call\":\n return this.emitToolCallStart(update, messageId);\n case \"tool_call_update\":\n return this.emitToolCallUpdate(update);\n case \"session_info_update\":\n return this.emitSessionInfoUpdate(update, messageId);\n default:\n return [];\n }\n };\n\n private emitSessionInfoUpdate = (\n update: Extract<AcpClientUpdate, { sessionUpdate: \"session_info_update\" }>,\n messageId: string,\n ): NcpEndpointEvent[] => {\n const patch = readSessionMetadataPatch(update._meta);\n if (!patch) {\n return [];\n }\n return [\n {\n type: NcpEventType.RunMetadata,\n payload: {\n sessionId: this.input.sessionId,\n messageId,\n runId: this.runId,\n ...(this.input.correlationId ? { correlationId: this.input.correlationId } : {}),\n metadata: {\n kind: SESSION_METADATA_PATCH_KIND,\n sessionMetadataPatch: patch,\n },\n },\n },\n ];\n };\n\n private emitTextDelta = (\n content: { type: string; text?: string },\n messageId: string,\n ): NcpEndpointEvent[] => this.emitContentDelta({\n content,\n messageId,\n started: this.textStarted,\n markStarted: () => {\n this.textStarted = true;\n },\n startType: NcpEventType.MessageTextStart,\n deltaType: NcpEventType.MessageTextDelta,\n });\n\n private emitReasoningDelta = (\n content: { type: string; text?: string },\n messageId: string,\n ): NcpEndpointEvent[] => this.emitContentDelta({\n content,\n messageId,\n started: this.reasoningStarted,\n markStarted: () => {\n this.reasoningStarted = true;\n },\n startType: NcpEventType.MessageReasoningStart,\n deltaType: NcpEventType.MessageReasoningDelta,\n });\n\n private emitContentDelta = (params: {\n content: { type: string; text?: string };\n messageId: string;\n started: boolean;\n markStarted: () => void;\n startType: NcpEventType.MessageTextStart | NcpEventType.MessageReasoningStart;\n deltaType: NcpEventType.MessageTextDelta | NcpEventType.MessageReasoningDelta;\n }): NcpEndpointEvent[] => {\n const { content, deltaType, markStarted, messageId, started, startType } = params;\n if (content.type !== \"text\" || !content.text) {\n return [];\n }\n const events: NcpEndpointEvent[] = [];\n if (!started) {\n markStarted();\n events.push({\n type: startType,\n payload: {\n sessionId: this.input.sessionId,\n messageId,\n },\n });\n }\n events.push({\n type: deltaType,\n payload: {\n sessionId: this.input.sessionId,\n messageId,\n delta: content.text,\n },\n });\n return events;\n };\n\n private emitToolCallStart = (\n update: Extract<AcpClientUpdate, { sessionUpdate: \"tool_call\" }>,\n messageId: string,\n ): NcpEndpointEvent[] => {\n const toolName = resolveToolName(update);\n const args = serializeToolArgs(update.rawInput);\n this.toolStates.set(update.toolCallId, {\n toolName,\n args,\n completed: false,\n });\n return [\n {\n type: NcpEventType.MessageToolCallStart,\n payload: {\n sessionId: this.input.sessionId,\n messageId,\n toolCallId: update.toolCallId,\n toolName,\n },\n },\n {\n type: NcpEventType.MessageToolCallArgs,\n payload: {\n sessionId: this.input.sessionId,\n toolCallId: update.toolCallId,\n args,\n },\n },\n ];\n };\n\n private emitToolCallUpdate = (\n update: Extract<AcpClientUpdate, { sessionUpdate: \"tool_call_update\" }>,\n ): NcpEndpointEvent[] => {\n const existing = this.toolStates.get(update.toolCallId);\n if (!existing) {\n return [];\n }\n\n const nextArgs = serializeToolArgs(update.rawInput);\n const argsChanged = typeof update.rawInput !== \"undefined\" && nextArgs !== existing.args;\n const events: NcpEndpointEvent[] = [];\n if (argsChanged) {\n existing.args = nextArgs;\n events.push({\n type: NcpEventType.MessageToolCallArgs,\n payload: {\n sessionId: this.input.sessionId,\n toolCallId: update.toolCallId,\n args: nextArgs,\n },\n });\n }\n\n if (update.status === \"completed\" || update.status === \"failed\") {\n if (!existing.completed) {\n existing.completed = true;\n events.push({\n type: NcpEventType.MessageToolCallEnd,\n payload: {\n sessionId: this.input.sessionId,\n toolCallId: update.toolCallId,\n },\n });\n }\n if (typeof update.rawOutput !== \"undefined\") {\n events.push({\n type: NcpEventType.MessageToolCallResult,\n payload: {\n sessionId: this.input.sessionId,\n toolCallId: update.toolCallId,\n content: update.rawOutput,\n },\n });\n }\n }\n return events;\n };\n\n private createTerminalEvents = (messageId: string): NcpEndpointEvent[] => {\n const events: NcpEndpointEvent[] = [];\n if (this.textStarted) {\n events.push({\n type: NcpEventType.MessageTextEnd,\n payload: {\n sessionId: this.input.sessionId,\n messageId,\n },\n });\n this.textStarted = false;\n }\n if (this.reasoningStarted) {\n events.push({\n type: NcpEventType.MessageReasoningEnd,\n payload: {\n sessionId: this.input.sessionId,\n messageId,\n },\n });\n this.reasoningStarted = false;\n }\n for (const [toolCallId, state] of this.toolStates.entries()) {\n if (state.completed) {\n continue;\n }\n events.push({\n type: NcpEventType.MessageToolCallEnd,\n payload: {\n sessionId: this.input.sessionId,\n toolCallId,\n },\n });\n state.completed = true;\n }\n return events;\n };\n}\n\nexport class StdioRuntimeNcpAgentRuntime implements NcpAgentRuntime {\n private readonly session: StdioRuntimeSession;\n\n constructor(private readonly config: StdioRuntimeNcpAgentRuntimeConfig) {\n this.session = new StdioRuntimeSession(config);\n }\n\n run = async function* (\n this: StdioRuntimeNcpAgentRuntime,\n input: NcpAgentRunInput,\n options?: NcpAgentRunOptions,\n ): AsyncGenerator<NcpEndpointEvent> {\n await this.session.ensureStarted({\n cwd: input.executionContext?.cwd,\n providerRoute: this.config.resolveProviderRoute?.(input),\n });\n const controller = new StdioRuntimeRunController(\n this.session,\n input,\n this.config.stateManager,\n this.config.resolveTools,\n this.config.resolveProviderRoute,\n );\n yield* controller.execute(options);\n };\n\n dispose = async (): Promise<void> => {\n await this.session.dispose();\n };\n}\n\nfunction readSessionMetadataPatch(meta: unknown): Record<string, unknown> | null {\n const narpMeta = isRecord(meta)\n ? meta[NARP_STDIO_PROMPT_META_KEY]\n : undefined;\n const patch = isRecord(narpMeta)\n ? narpMeta.sessionMetadataPatch\n : undefined;\n return isRecord(patch) && Object.keys(patch).length > 0\n ? structuredClone(patch)\n : null;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction resolveToolName(\n update: Extract<AcpClientUpdate, { sessionUpdate: \"tool_call\" }>,\n): string {\n return resolveToolNameFromAcpUpdate(update);\n}\n\nfunction createAssistantMessageId(requestMessageId: string): string {\n const normalizedRequestId = requestMessageId.trim() || \"request\";\n return `assistant:${normalizedRequestId}:${randomUUID()}`;\n}\n\nfunction serializeToolArgs(value: unknown): string {\n if (typeof value === \"string\") {\n return value;\n }\n if (typeof value === \"undefined\") {\n return \"{}\";\n }\n return JSON.stringify(value);\n}\n\nasync function withTimeout<T>(\n promise: Promise<T>,\n timeoutMs: number,\n message: string,\n): Promise<T> {\n let timeoutHandle: ReturnType<typeof setTimeout> | null = null;\n try {\n return await Promise.race([\n promise,\n new Promise<T>((_, reject) => {\n timeoutHandle = setTimeout(() => {\n reject(new Error(message));\n }, timeoutMs);\n }),\n ]);\n } finally {\n if (timeoutHandle) {\n clearTimeout(timeoutHandle);\n }\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"stdio-runtime.service.js","names":[],"sources":["../src/stdio-runtime.service.ts"],"sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { spawn, type ChildProcessWithoutNullStreams } from \"node:child_process\";\nimport { Readable, Writable } from \"node:stream\";\nimport * as acp from \"@agentclientprotocol/sdk\";\nimport {\n createNcpEndpointEvent,\n NcpEventType,\n type NcpAgentConversationStateManager,\n type NcpAgentRunInput,\n type NcpAgentRunOptions,\n type NcpAgentRuntime,\n type NcpEndpointEvent,\n type NcpMessage,\n type NcpProviderRuntimeRoute,\n type OpenAITool,\n} from \"@nextclaw/ncp\";\nimport { DefaultNcpAgentConversationStateManager } from \"@nextclaw/ncp-toolkit\";\nimport type { StdioRuntimeResolvedConfig, NarpStdioPromptMeta } from \"./stdio-runtime-config.utils.js\";\nimport {\n NARP_STDIO_PROMPT_META_KEY,\n buildStdioRuntimeLaunchEnv,\n} from \"./stdio-runtime-config.utils.js\";\nimport {\n buildSpawnFailureMessage,\n isAbortLikeRuntimeError,\n normalizeRuntimeError,\n} from \"./stdio-runtime-error.utils.js\";\nimport {\n createPromptTimeoutRecoveryEvents,\n readSessionMetadataPatch,\n SESSION_METADATA_PATCH_KIND,\n} from \"./utils/stdio-runtime-recovery.utils.js\";\nimport { extractPromptText, resolveModelId } from \"./utils/stdio-runtime-input.utils.js\";\nimport { resolveToolNameFromAcpUpdate } from \"./stdio-runtime-tool-name.utils.js\";\ntype AcpClientUpdate = acp.SessionUpdate;\nconst HERMES_ACP_ROUTE_BRIDGE_ENV = \"NEXTCLAW_HERMES_ACP_ROUTE_BRIDGE\";\nexport type StdioRuntimeNcpAgentRuntimeConfig = StdioRuntimeResolvedConfig & {\n stateManager?: NcpAgentConversationStateManager;\n resolveTools?: (input: NcpAgentRunInput) => ReadonlyArray<OpenAITool> | undefined;\n resolveProviderRoute?: (input: NcpAgentRunInput) => NcpProviderRuntimeRoute | undefined;\n};\ntype AcpToolState = {\n toolName: string;\n args?: string;\n completed: boolean;\n};\n\ntype PromptExecutionState = { settled: boolean; error: unknown };\n\nclass UpdateBuffer {\n private readonly updates: AcpClientUpdate[] = [];\n private waiters = new Set<() => void>();\n\n push = (update: AcpClientUpdate): void => {\n this.updates.push(update);\n this.flush();\n };\n\n shift = (): AcpClientUpdate | undefined => this.updates.shift();\n\n hasItems = (): boolean => this.updates.length > 0;\n\n waitForChange = async (): Promise<void> => {\n if (this.updates.length > 0) {\n return;\n }\n await new Promise<void>((resolve) => {\n this.waiters.add(resolve);\n });\n };\n\n notify = (): void => {\n this.flush();\n };\n\n private flush = (): void => {\n if (this.waiters.size === 0) {\n return;\n }\n const waiters = [...this.waiters];\n this.waiters.clear();\n for (const waiter of waiters) {\n waiter();\n }\n };\n}\n\nclass StdioRuntimeClientBridge {\n private activeSessionId: string | null = null;\n private updateHandler: ((update: AcpClientUpdate) => void) | null = null;\n\n attach = (params: {\n sessionId: string;\n onUpdate: (update: AcpClientUpdate) => void;\n }): (() => void) => {\n this.activeSessionId = params.sessionId;\n this.updateHandler = params.onUpdate;\n return () => {\n if (this.activeSessionId !== params.sessionId) {\n return;\n }\n this.activeSessionId = null;\n this.updateHandler = null;\n };\n };\n\n sessionUpdate = async (params: { sessionId: string; update: AcpClientUpdate }): Promise<void> => {\n if (params.sessionId !== this.activeSessionId) {\n return;\n }\n this.updateHandler?.(params.update);\n };\n\n requestPermission = async (): Promise<{\n outcome: { outcome: \"cancelled\" };\n }> => ({\n outcome: { outcome: \"cancelled\" },\n });\n\n readTextFile = async (): Promise<{ content: string }> => ({ content: \"\" });\n\n writeTextFile = async (): Promise<Record<string, never>> => ({});\n}\n\nclass StdioRuntimeSession {\n private child: ChildProcessWithoutNullStreams | null = null;\n private connection: acp.ClientSideConnection | null = null;\n private promptInFlight = false;\n private remoteSessionId: string | null = null;\n private remoteSessionCwd: string | null = null;\n private readonly clientBridge = new StdioRuntimeClientBridge();\n private stderr = \"\";\n private pendingProviderRoute: NcpProviderRuntimeRoute | undefined;\n\n constructor(private readonly config: StdioRuntimeNcpAgentRuntimeConfig) {}\n\n ensureStarted = async (params: {\n cwd?: string;\n providerRoute?: NcpProviderRuntimeRoute;\n }): Promise<void> => {\n const { cwd, providerRoute } = params;\n this.pendingProviderRoute = providerRoute;\n if (this.connection && this.remoteSessionId) {\n if (this.remoteSessionCwd === cwd) {\n return;\n }\n await this.dispose();\n }\n if (!cwd) {\n throw new Error(\"[narp-stdio] missing execution cwd for stdio runtime session\");\n }\n\n const env = buildStdioRuntimeLaunchEnv({\n configEnv: this.config.env,\n providerRoute: this.pendingProviderRoute,\n });\n\n this.child = spawn(this.config.command, this.config.args, {\n cwd: this.config.cwd,\n env,\n stdio: [\"pipe\", \"pipe\", \"pipe\"], windowsHide: true,\n });\n const spawnErrorPromise = new Promise<never>((_, reject) => {\n this.child?.once(\"error\", (error) => {\n reject(\n new Error(\n buildSpawnFailureMessage({\n command: this.config.command,\n cwd: this.config.cwd,\n error,\n }),\n ),\n );\n });\n });\n this.child.stderr.setEncoding(\"utf8\");\n this.child.stderr.on(\"data\", (chunk: string) => {\n this.stderr = `${this.stderr}${chunk}`.slice(-4000);\n });\n\n const stream = acp.ndJsonStream(\n Writable.toWeb(this.child.stdin),\n Readable.toWeb(this.child.stdout),\n );\n this.connection = new acp.ClientSideConnection(() => this.clientBridge, stream);\n\n const session = await Promise.race([\n (async () => {\n await withTimeout(\n this.connection?.initialize({\n protocolVersion: acp.PROTOCOL_VERSION,\n clientCapabilities: {},\n }) ?? Promise.reject(new Error(\"[narp-stdio] stdio runtime connection not started\")),\n this.config.startupTimeoutMs,\n \"[narp-stdio] timed out initializing stdio runtime\",\n );\n\n return withTimeout(\n this.connection?.newSession({\n cwd,\n mcpServers: [],\n }) ?? Promise.reject(new Error(\"[narp-stdio] stdio runtime connection not started\")),\n this.config.startupTimeoutMs,\n \"[narp-stdio] timed out creating remote stdio session\",\n );\n })(),\n spawnErrorPromise,\n ]);\n this.remoteSessionId = session.sessionId;\n this.remoteSessionCwd = cwd;\n };\n\n runPrompt = async (params: {\n sessionId: string;\n text: string;\n meta: NarpStdioPromptMeta;\n modelId?: string;\n signal?: AbortSignal;\n onUpdate: (update: AcpClientUpdate) => void;\n }): Promise<acp.PromptResponse> => {\n const { meta, modelId, onUpdate, sessionId, signal, text } = params;\n if (!this.connection || !this.remoteSessionId) {\n throw new Error(\"[narp-stdio] stdio runtime connection not started\");\n }\n if (this.promptInFlight) {\n throw new Error(\"[narp-stdio] concurrent prompt is not supported for one stdio session\");\n }\n\n this.promptInFlight = true;\n const detach = this.clientBridge.attach({\n sessionId: this.remoteSessionId,\n onUpdate,\n });\n const releaseAbort = this.bindAbortSignal(signal);\n\n try {\n if (modelId && this.config.env?.[HERMES_ACP_ROUTE_BRIDGE_ENV] !== \"1\") {\n try {\n // Hermes ACP must switch on prompt-scoped providerRoute, not modelId alone.\n await this.connection.unstable_setSessionModel({\n sessionId: this.remoteSessionId,\n modelId,\n });\n } catch {\n // Not all ACP agents implement unstable session model switching.\n }\n }\n\n return await withTimeout(\n this.connection.prompt({\n sessionId: this.remoteSessionId,\n prompt: [{ type: \"text\", text }],\n _meta: {\n [NARP_STDIO_PROMPT_META_KEY]: meta,\n },\n }),\n this.config.requestTimeoutMs,\n `[narp-stdio] prompt timed out for session ${sessionId}`,\n );\n } finally {\n releaseAbort();\n detach();\n this.promptInFlight = false;\n }\n };\n\n cancel = async (): Promise<void> => {\n if (!this.connection || !this.remoteSessionId) {\n return;\n }\n try {\n await this.connection.cancel({\n sessionId: this.remoteSessionId,\n });\n } catch {\n // Best effort.\n }\n };\n\n private bindAbortSignal = (signal?: AbortSignal): (() => void) => {\n if (!signal) {\n return () => undefined;\n }\n\n const onAbort = (): void => {\n void this.cancel();\n };\n\n if (signal.aborted) {\n onAbort();\n return () => undefined;\n }\n\n signal.addEventListener(\"abort\", onAbort, { once: true });\n return () => {\n signal.removeEventListener(\"abort\", onAbort);\n };\n };\n\n readStderr = (): string => this.stderr;\n\n readPromptTimeoutMetadataResetKeys = (): readonly string[] | undefined =>\n this.config.resetSessionMetadataOnPromptTimeout;\n\n dispose = async (): Promise<void> => {\n await this.cancel();\n const child = this.child;\n this.connection = null;\n this.remoteSessionId = null;\n this.remoteSessionCwd = null;\n this.child = null;\n if (!child || child.killed || child.exitCode !== null || child.signalCode !== null) {\n return;\n }\n\n const exited = new Promise<void>((resolve) => {\n child.once(\"exit\", () => resolve());\n child.once(\"error\", () => resolve());\n });\n const forceKill = setTimeout(() => {\n child.kill(\"SIGKILL\");\n }, 3_000);\n forceKill.unref();\n child.kill(\"SIGTERM\");\n await exited;\n clearTimeout(forceKill);\n };\n}\n\nclass StdioRuntimeRunController {\n private readonly buffer = new UpdateBuffer();\n private readonly conversationStateManager: NcpAgentConversationStateManager;\n private readonly toolStates = new Map<string, AcpToolState>();\n private textStarted = false;\n private reasoningStarted = false;\n private readonly resolvedTools: ReadonlyArray<OpenAITool>;\n private readonly resolvedProviderRoute: NcpProviderRuntimeRoute | undefined;\n private readonly runId: string;\n private runStartedAt: string | undefined;\n\n constructor(\n private readonly session: StdioRuntimeSession,\n private readonly input: NcpAgentRunInput,\n stateManager?: NcpAgentConversationStateManager,\n private readonly resolveTools?: (input: NcpAgentRunInput) => ReadonlyArray<OpenAITool> | undefined,\n private readonly resolveProviderRoute?: (input: NcpAgentRunInput) => NcpProviderRuntimeRoute | undefined,\n ) {\n this.conversationStateManager =\n stateManager ?? new DefaultNcpAgentConversationStateManager();\n this.resolvedTools = resolveTools?.(input) ?? [];\n this.resolvedProviderRoute = resolveProviderRoute?.(input);\n this.runId = (input as NcpAgentRunInput & { runId?: string }).runId ?? `narp-stdio:${input.sessionId}:${randomUUID()}`;\n }\n execute = async function* (\n this: StdioRuntimeRunController,\n options?: NcpAgentRunOptions,\n ): AsyncGenerator<NcpEndpointEvent> {\n const requestMessage = this.input.messages.at(-1);\n if (!requestMessage) {\n throw new Error(\"[narp-stdio] runtime.run requires at least one input message\");\n }\n\n const assistantMessageId = createAssistantMessageId(requestMessage.id);\n const promptPromise = this.session.runPrompt({\n sessionId: this.input.sessionId,\n text: extractPromptText(requestMessage),\n meta: {\n ...(this.input.correlationId ? { correlationId: this.input.correlationId } : {}),\n ...(this.resolvedProviderRoute ? { providerRoute: this.resolvedProviderRoute } : {}),\n ...(this.input.metadata ? { sessionMetadata: this.input.metadata } : {}),\n ...(this.resolvedTools.length > 0 ? { tools: this.resolvedTools } : {}),\n },\n modelId: resolveModelId({\n providerRoute: this.resolvedProviderRoute,\n metadata: this.input.metadata,\n }),\n signal: options?.signal,\n onUpdate: (update) => this.buffer.push(update),\n });\n const promptState = this.trackPromptState(promptPromise);\n\n yield* this.emitRunStartedEvents(assistantMessageId);\n\n try {\n yield* this.drainPromptUpdates(assistantMessageId, promptState);\n if (this.shouldExitForAbort(options, promptState.error)) {\n return;\n }\n if (promptState.error) throw promptState.error;\n yield* this.emitCompletionEvents(assistantMessageId);\n } catch (error) {\n if (this.shouldExitForAbort(options, error)) {\n return;\n }\n yield* this.emitFailureEvents(assistantMessageId, error);\n }\n };\n private trackPromptState = (\n promptPromise: Promise<acp.PromptResponse>,\n ): PromptExecutionState => {\n const promptState: PromptExecutionState = {\n settled: false,\n error: null,\n };\n\n promptPromise\n .then(() => {\n promptState.settled = true;\n this.buffer.notify();\n })\n .catch((error) => {\n promptState.settled = true;\n promptState.error = error;\n this.buffer.notify();\n });\n\n return promptState;\n };\n private emitRunStartedEvents = async function* (\n this: StdioRuntimeRunController,\n assistantMessageId: string,\n ): AsyncGenerator<NcpEndpointEvent> {\n yield* this.emitEvent({\n type: NcpEventType.MessageAccepted,\n payload: {\n messageId: assistantMessageId,\n ...(this.input.correlationId ? { correlationId: this.input.correlationId } : {}),\n },\n });\n this.runStartedAt = new Date().toISOString();\n yield* this.emitEvent({\n type: NcpEventType.RunStarted,\n payload: {\n sessionId: this.input.sessionId,\n messageId: assistantMessageId,\n runId: this.runId,\n startedAt: this.runStartedAt,\n },\n }, this.runStartedAt);\n };\n private drainPromptUpdates = async function* (\n this: StdioRuntimeRunController,\n assistantMessageId: string,\n promptState: PromptExecutionState,\n ): AsyncGenerator<NcpEndpointEvent> {\n while (!promptState.settled || this.buffer.hasItems()) {\n const update = this.buffer.shift();\n if (!update) {\n await this.buffer.waitForChange();\n continue;\n }\n for (const event of this.translateUpdate(update, assistantMessageId)) {\n yield* this.emitEvent(event);\n }\n }\n };\n private shouldExitForAbort = (\n options: NcpAgentRunOptions | undefined,\n error: unknown,\n ): boolean => options?.signal?.aborted === true || isAbortLikeRuntimeError(error);\n private emitCompletionEvents = async function* (\n this: StdioRuntimeRunController,\n assistantMessageId: string,\n ): AsyncGenerator<NcpEndpointEvent> {\n for (const terminalEvent of this.createTerminalEvents(assistantMessageId)) {\n yield* this.emitEvent(terminalEvent);\n }\n\n const completedMessage = this.buildCompletedAssistantMessage(assistantMessageId);\n if (!completedMessage.parts.length) {\n throw new Error(\n `[narp-stdio] ACP prompt completed without any assistant content for session ${this.input.sessionId}. stderr=${this.session.readStderr()}`,\n );\n }\n\n yield* this.emitEvent({\n type: NcpEventType.MessageCompleted,\n payload: {\n sessionId: this.input.sessionId,\n correlationId: this.input.correlationId,\n message: completedMessage,\n },\n });\n const endedAt = new Date().toISOString();\n yield* this.emitEvent({\n type: NcpEventType.RunFinished,\n payload: {\n sessionId: this.input.sessionId,\n messageId: assistantMessageId,\n runId: this.runId,\n startedAt: this.runStartedAt,\n endedAt,\n },\n }, endedAt);\n };\n private emitFailureEvents = async function* (\n this: StdioRuntimeRunController,\n assistantMessageId: string,\n error: unknown,\n ): AsyncGenerator<NcpEndpointEvent> {\n const ncpError = normalizeRuntimeError(error, { stderr: this.session.readStderr() });\n for (const recoveryEvent of createPromptTimeoutRecoveryEvents({\n correlationId: this.input.correlationId,\n error,\n messageId: assistantMessageId,\n resetKeys: this.session.readPromptTimeoutMetadataResetKeys(),\n runId: this.runId,\n sessionId: this.input.sessionId,\n })) {\n yield* this.emitEvent(recoveryEvent);\n }\n yield* this.emitEvent({\n type: NcpEventType.MessageFailed,\n payload: {\n sessionId: this.input.sessionId,\n messageId: assistantMessageId,\n correlationId: this.input.correlationId,\n error: ncpError,\n },\n });\n const endedAt = new Date().toISOString();\n yield* this.emitEvent({\n type: NcpEventType.RunError,\n payload: {\n sessionId: this.input.sessionId,\n messageId: assistantMessageId,\n runId: this.runId,\n error: ncpError.message,\n startedAt: this.runStartedAt,\n endedAt,\n },\n }, endedAt);\n };\n private emitEvent = async function* (\n this: StdioRuntimeRunController,\n event: NcpEndpointEvent,\n occurredAt?: string,\n ): AsyncGenerator<NcpEndpointEvent> {\n const stampedEvent = createNcpEndpointEvent(event, occurredAt);\n await this.conversationStateManager.dispatch(stampedEvent);\n yield stampedEvent;\n };\n private buildCompletedAssistantMessage = (assistantMessageId: string): NcpMessage => {\n const snapshot = this.conversationStateManager.getSnapshot();\n const message = snapshot.streamingMessage?.id === assistantMessageId\n ? snapshot.streamingMessage\n : snapshot.messages.find((candidate) => candidate.id === assistantMessageId);\n return message\n ? { ...structuredClone(message), status: \"final\" }\n : {\n id: assistantMessageId,\n sessionId: this.input.sessionId,\n role: \"assistant\",\n status: \"final\",\n parts: [],\n timestamp: new Date().toISOString(),\n };\n };\n private translateUpdate = (\n update: AcpClientUpdate,\n messageId: string,\n ): NcpEndpointEvent[] => {\n switch (update.sessionUpdate) {\n case \"agent_message_chunk\":\n return this.emitTextDelta(update.content, messageId);\n case \"agent_thought_chunk\":\n return this.emitReasoningDelta(update.content, messageId);\n case \"tool_call\":\n return this.emitToolCallStart(update, messageId);\n case \"tool_call_update\":\n return this.emitToolCallUpdate(update);\n case \"session_info_update\":\n return this.emitSessionInfoUpdate(update, messageId);\n default:\n return [];\n }\n };\n\n private emitSessionInfoUpdate = (\n update: Extract<AcpClientUpdate, { sessionUpdate: \"session_info_update\" }>,\n messageId: string,\n ): NcpEndpointEvent[] => {\n const patch = readSessionMetadataPatch(update._meta);\n if (!patch) {\n return [];\n }\n return [\n {\n type: NcpEventType.RunMetadata,\n payload: {\n sessionId: this.input.sessionId,\n messageId,\n runId: this.runId,\n ...(this.input.correlationId ? { correlationId: this.input.correlationId } : {}),\n metadata: {\n kind: SESSION_METADATA_PATCH_KIND,\n sessionMetadataPatch: patch,\n },\n },\n },\n ];\n };\n\n private emitTextDelta = (\n content: { type: string; text?: string },\n messageId: string,\n ): NcpEndpointEvent[] => this.emitContentDelta({\n content,\n messageId,\n started: this.textStarted,\n markStarted: () => {\n this.textStarted = true;\n },\n startType: NcpEventType.MessageTextStart,\n deltaType: NcpEventType.MessageTextDelta,\n });\n\n private emitReasoningDelta = (\n content: { type: string; text?: string },\n messageId: string,\n ): NcpEndpointEvent[] => this.emitContentDelta({\n content,\n messageId,\n started: this.reasoningStarted,\n markStarted: () => {\n this.reasoningStarted = true;\n },\n startType: NcpEventType.MessageReasoningStart,\n deltaType: NcpEventType.MessageReasoningDelta,\n });\n\n private emitContentDelta = (params: {\n content: { type: string; text?: string };\n messageId: string;\n started: boolean;\n markStarted: () => void;\n startType: NcpEventType.MessageTextStart | NcpEventType.MessageReasoningStart;\n deltaType: NcpEventType.MessageTextDelta | NcpEventType.MessageReasoningDelta;\n }): NcpEndpointEvent[] => {\n const { content, deltaType, markStarted, messageId, started, startType } = params;\n if (content.type !== \"text\" || !content.text) {\n return [];\n }\n const events: NcpEndpointEvent[] = [];\n if (!started) {\n markStarted();\n events.push({\n type: startType,\n payload: {\n sessionId: this.input.sessionId,\n messageId,\n },\n });\n }\n events.push({\n type: deltaType,\n payload: {\n sessionId: this.input.sessionId,\n messageId,\n delta: content.text,\n },\n });\n return events;\n };\n\n private emitToolCallStart = (\n update: Extract<AcpClientUpdate, { sessionUpdate: \"tool_call\" }>,\n messageId: string,\n ): NcpEndpointEvent[] => {\n const toolName = resolveToolNameFromAcpUpdate(update);\n const args = serializeToolArgs(update.rawInput);\n this.toolStates.set(update.toolCallId, {\n toolName,\n args,\n completed: false,\n });\n return [\n {\n type: NcpEventType.MessageToolCallStart,\n payload: {\n sessionId: this.input.sessionId,\n messageId,\n toolCallId: update.toolCallId,\n toolName,\n },\n },\n {\n type: NcpEventType.MessageToolCallArgs,\n payload: {\n sessionId: this.input.sessionId,\n toolCallId: update.toolCallId,\n args,\n },\n },\n ];\n };\n\n private emitToolCallUpdate = (\n update: Extract<AcpClientUpdate, { sessionUpdate: \"tool_call_update\" }>,\n ): NcpEndpointEvent[] => {\n const existing = this.toolStates.get(update.toolCallId);\n if (!existing) {\n return [];\n }\n\n const nextArgs = serializeToolArgs(update.rawInput);\n const argsChanged = typeof update.rawInput !== \"undefined\" && nextArgs !== existing.args;\n const events: NcpEndpointEvent[] = [];\n if (argsChanged) {\n existing.args = nextArgs;\n events.push({\n type: NcpEventType.MessageToolCallArgs,\n payload: {\n sessionId: this.input.sessionId,\n toolCallId: update.toolCallId,\n args: nextArgs,\n },\n });\n }\n\n if (update.status === \"completed\" || update.status === \"failed\") {\n if (!existing.completed) {\n existing.completed = true;\n events.push({\n type: NcpEventType.MessageToolCallEnd,\n payload: {\n sessionId: this.input.sessionId,\n toolCallId: update.toolCallId,\n },\n });\n }\n if (typeof update.rawOutput !== \"undefined\") {\n events.push({\n type: NcpEventType.MessageToolCallResult,\n payload: {\n sessionId: this.input.sessionId,\n toolCallId: update.toolCallId,\n content: update.rawOutput,\n },\n });\n }\n }\n return events;\n };\n\n private createTerminalEvents = (messageId: string): NcpEndpointEvent[] => {\n const events: NcpEndpointEvent[] = [];\n if (this.textStarted) {\n events.push({\n type: NcpEventType.MessageTextEnd,\n payload: {\n sessionId: this.input.sessionId,\n messageId,\n },\n });\n this.textStarted = false;\n }\n if (this.reasoningStarted) {\n events.push({\n type: NcpEventType.MessageReasoningEnd,\n payload: {\n sessionId: this.input.sessionId,\n messageId,\n },\n });\n this.reasoningStarted = false;\n }\n for (const [toolCallId, state] of this.toolStates.entries()) {\n if (state.completed) {\n continue;\n }\n events.push({\n type: NcpEventType.MessageToolCallEnd,\n payload: {\n sessionId: this.input.sessionId,\n toolCallId,\n },\n });\n state.completed = true;\n }\n return events;\n };\n}\n\nexport class StdioRuntimeNcpAgentRuntime implements NcpAgentRuntime {\n private readonly session: StdioRuntimeSession;\n\n constructor(private readonly config: StdioRuntimeNcpAgentRuntimeConfig) {\n this.session = new StdioRuntimeSession(config);\n }\n\n run = async function* (\n this: StdioRuntimeNcpAgentRuntime,\n input: NcpAgentRunInput,\n options?: NcpAgentRunOptions,\n ): AsyncGenerator<NcpEndpointEvent> {\n await this.session.ensureStarted({\n cwd: input.executionContext?.cwd,\n providerRoute: this.config.resolveProviderRoute?.(input),\n });\n const controller = new StdioRuntimeRunController(\n this.session,\n input,\n this.config.stateManager,\n this.config.resolveTools,\n this.config.resolveProviderRoute,\n );\n yield* controller.execute(options);\n };\n\n dispose = async (): Promise<void> => {\n await this.session.dispose();\n };\n}\n\nfunction createAssistantMessageId(requestMessageId: string): string {\n const normalizedRequestId = requestMessageId.trim() || \"request\";\n return `assistant:${normalizedRequestId}:${randomUUID()}`;\n}\n\nfunction serializeToolArgs(value: unknown): string {\n if (typeof value === \"string\") {\n return value;\n }\n if (typeof value === \"undefined\") {\n return \"{}\";\n }\n return JSON.stringify(value);\n}\n\nasync function withTimeout<T>(\n promise: Promise<T>,\n timeoutMs: number,\n message: string,\n): Promise<T> {\n let timeoutHandle: ReturnType<typeof setTimeout> | null = null;\n try {\n return await Promise.race([\n promise,\n new Promise<T>((_, reject) => {\n timeoutHandle = setTimeout(() => {\n reject(new Error(message));\n }, timeoutMs);\n }),\n ]);\n } finally {\n if (timeoutHandle) {\n clearTimeout(timeoutHandle);\n }\n }\n}\n"],"mappings":"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"}
@@ -1,10 +1,16 @@
1
- import { NcpEventType } from "@nextclaw/ncp";
1
+ import { NARP_STDIO_PROMPT_META_KEY } from "../stdio-runtime-config.utils.js";
2
+ import { NcpEventType, createNcpEndpointEvent } from "@nextclaw/ncp";
2
3
  //#region src/utils/stdio-runtime-recovery.utils.ts
3
4
  const SESSION_METADATA_PATCH_KIND = "session_metadata_patch";
5
+ function readSessionMetadataPatch(meta) {
6
+ const narpMeta = isRecord(meta) ? meta[NARP_STDIO_PROMPT_META_KEY] : void 0;
7
+ const patch = isRecord(narpMeta) ? narpMeta.sessionMetadataPatch : void 0;
8
+ return isRecord(patch) && Object.keys(patch).length > 0 ? structuredClone(patch) : null;
9
+ }
4
10
  function createPromptTimeoutRecoveryEvents(params) {
5
11
  const { correlationId, error, messageId, resetKeys, runId, sessionId } = params;
6
12
  if (!resetKeys?.length || !isPromptTimeoutError(error)) return [];
7
- return [{
13
+ return [createNcpEndpointEvent({
8
14
  type: NcpEventType.RunMetadata,
9
15
  payload: {
10
16
  sessionId,
@@ -16,12 +22,15 @@ function createPromptTimeoutRecoveryEvents(params) {
16
22
  sessionMetadataPatch: Object.fromEntries(resetKeys.map((key) => [key, null]))
17
23
  }
18
24
  }
19
- }];
25
+ })];
20
26
  }
21
27
  function isPromptTimeoutError(error) {
22
28
  return (error instanceof Error ? error.message : String(error)).includes("[narp-stdio] prompt timed out");
23
29
  }
30
+ function isRecord(value) {
31
+ return typeof value === "object" && value !== null && !Array.isArray(value);
32
+ }
24
33
  //#endregion
25
- export { SESSION_METADATA_PATCH_KIND, createPromptTimeoutRecoveryEvents };
34
+ export { SESSION_METADATA_PATCH_KIND, createPromptTimeoutRecoveryEvents, readSessionMetadataPatch };
26
35
 
27
36
  //# sourceMappingURL=stdio-runtime-recovery.utils.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"stdio-runtime-recovery.utils.js","names":[],"sources":["../../src/utils/stdio-runtime-recovery.utils.ts"],"sourcesContent":["import { NcpEventType, type NcpEndpointEvent } from \"@nextclaw/ncp\";\n\nexport const SESSION_METADATA_PATCH_KIND = \"session_metadata_patch\";\n\nexport function createPromptTimeoutRecoveryEvents(params: {\n correlationId?: string;\n error: unknown;\n messageId: string;\n resetKeys?: readonly string[];\n runId: string;\n sessionId: string;\n}): NcpEndpointEvent[] {\n const { correlationId, error, messageId, resetKeys, runId, sessionId } = params;\n if (!resetKeys?.length || !isPromptTimeoutError(error)) {\n return [];\n }\n return [\n {\n type: NcpEventType.RunMetadata,\n payload: {\n sessionId,\n messageId,\n runId,\n ...(correlationId ? { correlationId } : {}),\n metadata: {\n kind: SESSION_METADATA_PATCH_KIND,\n sessionMetadataPatch: Object.fromEntries(\n resetKeys.map((key) => [key, null]),\n ),\n },\n },\n },\n ];\n}\n\nfunction isPromptTimeoutError(error: unknown): boolean {\n const message = error instanceof Error ? error.message : String(error);\n return message.includes(\"[narp-stdio] prompt timed out\");\n}\n"],"mappings":";;AAEA,MAAa,8BAA8B;AAE3C,SAAgB,kCAAkC,QAO3B;CACrB,MAAM,EAAE,eAAe,OAAO,WAAW,WAAW,OAAO,cAAc;AACzE,KAAI,CAAC,WAAW,UAAU,CAAC,qBAAqB,MAAM,CACpD,QAAO,EAAE;AAEX,QAAO,CACL;EACE,MAAM,aAAa;EACnB,SAAS;GACP;GACA;GACA;GACA,GAAI,gBAAgB,EAAE,eAAe,GAAG,EAAE;GAC1C,UAAU;IACR,MAAM;IACN,sBAAsB,OAAO,YAC3B,UAAU,KAAK,QAAQ,CAAC,KAAK,KAAK,CAAC,CACpC;IACF;GACF;EACF,CACF;;AAGH,SAAS,qBAAqB,OAAyB;AAErD,SADgB,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,EACvD,SAAS,gCAAgC"}
1
+ {"version":3,"file":"stdio-runtime-recovery.utils.js","names":[],"sources":["../../src/utils/stdio-runtime-recovery.utils.ts"],"sourcesContent":["import { createNcpEndpointEvent, NcpEventType, type NcpEndpointEvent } from \"@nextclaw/ncp\";\nimport { NARP_STDIO_PROMPT_META_KEY } from \"../stdio-runtime-config.utils.js\";\n\nexport const SESSION_METADATA_PATCH_KIND = \"session_metadata_patch\";\n\nexport function readSessionMetadataPatch(meta: unknown): Record<string, unknown> | null {\n const narpMeta = isRecord(meta)\n ? meta[NARP_STDIO_PROMPT_META_KEY]\n : undefined;\n const patch = isRecord(narpMeta)\n ? narpMeta.sessionMetadataPatch\n : undefined;\n return isRecord(patch) && Object.keys(patch).length > 0\n ? structuredClone(patch)\n : null;\n}\n\nexport function createPromptTimeoutRecoveryEvents(params: {\n correlationId?: string;\n error: unknown;\n messageId: string;\n resetKeys?: readonly string[];\n runId: string;\n sessionId: string;\n}): NcpEndpointEvent[] {\n const { correlationId, error, messageId, resetKeys, runId, sessionId } = params;\n if (!resetKeys?.length || !isPromptTimeoutError(error)) {\n return [];\n }\n return [\n createNcpEndpointEvent({\n type: NcpEventType.RunMetadata,\n payload: {\n sessionId,\n messageId,\n runId,\n ...(correlationId ? { correlationId } : {}),\n metadata: {\n kind: SESSION_METADATA_PATCH_KIND,\n sessionMetadataPatch: Object.fromEntries(\n resetKeys.map((key) => [key, null]),\n ),\n },\n },\n }),\n ];\n}\n\nfunction isPromptTimeoutError(error: unknown): boolean {\n const message = error instanceof Error ? error.message : String(error);\n return message.includes(\"[narp-stdio] prompt timed out\");\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n"],"mappings":";;;AAGA,MAAa,8BAA8B;AAE3C,SAAgB,yBAAyB,MAA+C;CACtF,MAAM,WAAW,SAAS,KAAK,GAC3B,KAAK,8BACL,KAAA;CACJ,MAAM,QAAQ,SAAS,SAAS,GAC5B,SAAS,uBACT,KAAA;AACJ,QAAO,SAAS,MAAM,IAAI,OAAO,KAAK,MAAM,CAAC,SAAS,IAClD,gBAAgB,MAAM,GACtB;;AAGN,SAAgB,kCAAkC,QAO3B;CACrB,MAAM,EAAE,eAAe,OAAO,WAAW,WAAW,OAAO,cAAc;AACzE,KAAI,CAAC,WAAW,UAAU,CAAC,qBAAqB,MAAM,CACpD,QAAO,EAAE;AAEX,QAAO,CACL,uBAAuB;EACrB,MAAM,aAAa;EACnB,SAAS;GACP;GACA;GACA;GACA,GAAI,gBAAgB,EAAE,eAAe,GAAG,EAAE;GAC1C,UAAU;IACR,MAAM;IACN,sBAAsB,OAAO,YAC3B,UAAU,KAAK,QAAQ,CAAC,KAAK,KAAK,CAAC,CACpC;IACF;GACF;EACF,CAAC,CACH;;AAGH,SAAS,qBAAqB,OAAyB;AAErD,SADgB,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,EACvD,SAAS,gCAAgC;;AAG1D,SAAS,SAAS,OAAkD;AAClE,QAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,MAAM"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nextclaw/nextclaw-ncp-runtime-stdio-client",
3
- "version": "0.2.17",
3
+ "version": "0.3.0",
4
4
  "private": false,
5
5
  "description": "Optional NCP runtime adapter backed by a protocol-aware stdio agent command.",
6
6
  "type": "module",
@@ -17,9 +17,9 @@
17
17
  ],
18
18
  "dependencies": {
19
19
  "@agentclientprotocol/sdk": "^0.19.0",
20
- "@nextclaw/core": "0.14.8",
21
- "@nextclaw/ncp": "0.6.6",
22
- "@nextclaw/ncp-toolkit": "0.5.41"
20
+ "@nextclaw/core": "0.15.0",
21
+ "@nextclaw/ncp-toolkit": "0.6.0",
22
+ "@nextclaw/ncp": "0.7.0"
23
23
  },
24
24
  "devDependencies": {
25
25
  "@types/node": "^20.17.6",