@nextclaw/nextclaw-ncp-runtime-stdio-client 0.2.12 → 0.2.14-beta.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.
- package/dist/stdio-runtime-config.utils.d.ts +1 -0
- package/dist/stdio-runtime-config.utils.d.ts.map +1 -1
- package/dist/stdio-runtime-config.utils.js +34 -4
- package/dist/stdio-runtime-config.utils.js.map +1 -1
- package/dist/stdio-runtime-error.utils.js +7 -2
- package/dist/stdio-runtime-error.utils.js.map +1 -1
- package/dist/stdio-runtime-probe.utils.d.ts.map +1 -1
- package/dist/stdio-runtime-probe.utils.js +6 -4
- package/dist/stdio-runtime-probe.utils.js.map +1 -1
- package/dist/stdio-runtime.service.d.ts +0 -1
- package/dist/stdio-runtime.service.d.ts.map +1 -1
- package/dist/stdio-runtime.service.js +67 -25
- package/dist/stdio-runtime.service.js.map +1 -1
- package/dist/utils/stdio-runtime-input.utils.js +18 -0
- package/dist/utils/stdio-runtime-input.utils.js.map +1 -0
- package/dist/utils/stdio-runtime-recovery.utils.js +27 -0
- package/dist/utils/stdio-runtime-recovery.utils.js.map +1 -0
- package/package.json +3 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stdio-runtime-config.utils.d.ts","names":[],"sources":["../src/stdio-runtime-config.utils.ts"],"mappings":";;;cAGa,0BAAA;AAAA,KAWD,eAAA,GAAkB,MAAA;AAAA,KAClB,uBAAA;AAAA,KACA,wBAAA;AAAA,KAEA,mBAAA;EACV,aAAA;EACA,aAAA,GAAgB,uBAAA;EAChB,eAAA,GAAkB,MAAA;EAClB,KAAA,GAAQ,aAAA,CAAc,UAAA;AAAA;AAAA,KAGZ,0BAAA;EACV,WAAA,EAAa,uBAAA;EACb,YAAA,EAAc,wBAAA;EACd,OAAA;EACA,IAAA;EACA,GAAA;EACA,GAAA,GAAM,eAAA;EACN,gBAAA;EACA,cAAA;EACA,gBAAA;AAAA;AAAA,
|
|
1
|
+
{"version":3,"file":"stdio-runtime-config.utils.d.ts","names":[],"sources":["../src/stdio-runtime-config.utils.ts"],"mappings":";;;cAGa,0BAAA;AAAA,KAWD,eAAA,GAAkB,MAAA;AAAA,KAClB,uBAAA;AAAA,KACA,wBAAA;AAAA,KAEA,mBAAA;EACV,aAAA;EACA,aAAA,GAAgB,uBAAA;EAChB,eAAA,GAAkB,MAAA;EAClB,KAAA,GAAQ,aAAA,CAAc,UAAA;AAAA;AAAA,KAGZ,0BAAA;EACV,WAAA,EAAa,uBAAA;EACb,YAAA,EAAc,wBAAA;EACd,OAAA;EACA,IAAA;EACA,GAAA;EACA,GAAA,GAAM,eAAA;EACN,mCAAA;EACA,gBAAA;EACA,cAAA;EACA,gBAAA;AAAA;AAAA,cAkGW,0BAAA;EAAA,iBACkB,MAAA;cAAA,MAAA,GAAQ,MAAA;EAErC,OAAA,QAAc,0BAAA;EAAA,QAmDN,kBAAA;EAAA,QAQA,mBAAA;AAAA;AAAA,iBASM,0BAAA,CAA2B,MAAA;EACzC,aAAA,GAAgB,uBAAA;AAAA,IACd,MAAA;AAAA,iBAaY,0BAAA,CAA2B,MAAA;EACzC,OAAA,GAAU,MAAA;EACV,SAAA,GAAY,eAAA;EACZ,aAAA,GAAgB,uBAAA;AAAA,IACd,MAAA"}
|
|
@@ -41,6 +41,30 @@ function readStringRecord(value) {
|
|
|
41
41
|
}
|
|
42
42
|
return Object.keys(output).length > 0 ? output : void 0;
|
|
43
43
|
}
|
|
44
|
+
function readCommandOverrides(value) {
|
|
45
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return {};
|
|
46
|
+
const overrides = {};
|
|
47
|
+
for (const [rawCommand, rawOverride] of Object.entries(value)) {
|
|
48
|
+
const commandKey = readString(rawCommand);
|
|
49
|
+
if (!commandKey || !rawOverride || typeof rawOverride !== "object" || Array.isArray(rawOverride)) continue;
|
|
50
|
+
const overrideRecord = rawOverride;
|
|
51
|
+
const command = readString(overrideRecord.command);
|
|
52
|
+
const args = readStringArray(overrideRecord.args);
|
|
53
|
+
const cwd = readString(overrideRecord.cwd);
|
|
54
|
+
const env = readStringRecord(overrideRecord.env);
|
|
55
|
+
if (!command && !args && !cwd && !env) continue;
|
|
56
|
+
overrides[commandKey] = {
|
|
57
|
+
...command ? { command } : {},
|
|
58
|
+
...args ? { args } : {},
|
|
59
|
+
...cwd ? { cwd } : {},
|
|
60
|
+
...env ? { env } : {}
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
return overrides;
|
|
64
|
+
}
|
|
65
|
+
function readCommandOverride(command) {
|
|
66
|
+
return readCommandOverrides(parseJsonObject(process.env.NEXTCLAW_NARP_STDIO_COMMAND_OVERRIDES))[command];
|
|
67
|
+
}
|
|
44
68
|
var StdioRuntimeConfigResolver = class {
|
|
45
69
|
constructor(source = {}) {
|
|
46
70
|
this.source = source;
|
|
@@ -50,13 +74,19 @@ var StdioRuntimeConfigResolver = class {
|
|
|
50
74
|
const processScope = this.resolveProcessScope();
|
|
51
75
|
const command = readString(this.source.command) ?? readString(process.env.NEXTCLAW_NARP_STDIO_COMMAND);
|
|
52
76
|
if (!command) throw new Error("[narp-stdio] missing stdio command");
|
|
77
|
+
const override = readCommandOverride(command);
|
|
78
|
+
const args = override?.args ?? readStringArray(this.source.args) ?? readStringArray(parseJsonArray(process.env.NEXTCLAW_NARP_STDIO_ARGS)) ?? [];
|
|
79
|
+
const cwd = override?.cwd ?? readString(this.source.cwd) ?? readString(process.env.NEXTCLAW_NARP_STDIO_CWD);
|
|
80
|
+
const env = override?.env ?? readStringRecord(this.source.env) ?? readStringRecord(parseJsonObject(process.env.NEXTCLAW_NARP_STDIO_ENV));
|
|
81
|
+
const resetSessionMetadataOnPromptTimeout = readStringArray(this.source.resetSessionMetadataOnPromptTimeout);
|
|
53
82
|
return {
|
|
54
83
|
wireDialect,
|
|
55
84
|
processScope,
|
|
56
|
-
command,
|
|
57
|
-
args
|
|
58
|
-
...
|
|
59
|
-
...
|
|
85
|
+
command: override?.command ?? command,
|
|
86
|
+
args,
|
|
87
|
+
...cwd ? { cwd } : {},
|
|
88
|
+
...env ? { env } : {},
|
|
89
|
+
...resetSessionMetadataOnPromptTimeout ? { resetSessionMetadataOnPromptTimeout } : {},
|
|
60
90
|
startupTimeoutMs: readPositiveInteger(this.source.startupTimeoutMs) ?? readPositiveInteger(process.env.NEXTCLAW_NARP_STDIO_STARTUP_TIMEOUT_MS) ?? DEFAULT_STARTUP_TIMEOUT_MS,
|
|
61
91
|
probeTimeoutMs: readPositiveInteger(this.source.probeTimeoutMs) ?? DEFAULT_PROBE_TIMEOUT_MS,
|
|
62
92
|
requestTimeoutMs: readPositiveInteger(this.source.requestTimeoutMs) ?? DEFAULT_REQUEST_TIMEOUT_MS
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stdio-runtime-config.utils.js","names":[],"sources":["../src/stdio-runtime-config.utils.ts"],"sourcesContent":["import type { OpenAITool, NcpProviderRuntimeRoute } from \"@nextclaw/ncp\";\nimport { createRuntimeChildEnv } from \"@nextclaw/core\";\n\nexport const NARP_STDIO_PROMPT_META_KEY = \"nextclaw_narp\";\nconst DEFAULT_STARTUP_TIMEOUT_MS = 10_000;\nconst DEFAULT_PROBE_TIMEOUT_MS = 3_000;\nconst DEFAULT_REQUEST_TIMEOUT_MS = 120_000;\nconst DEFAULT_RUNTIME_ROUTE_BRIDGE_FIELDS = {\n model: \"NEXTCLAW_MODEL\",\n apiBase: \"NEXTCLAW_API_BASE\",\n apiKey: \"NEXTCLAW_API_KEY\",\n headers: \"NEXTCLAW_HEADERS_JSON\",\n} as const;\n\nexport type StdioRuntimeEnv = Record<string, string>;\nexport type StdioRuntimeWireDialect = \"acp\";\nexport type StdioRuntimeProcessScope = \"per-session\";\n\nexport type NarpStdioPromptMeta = {\n correlationId?: string;\n providerRoute?: NcpProviderRuntimeRoute;\n sessionMetadata?: Record<string, unknown>;\n tools?: ReadonlyArray<OpenAITool>;\n};\n\nexport type StdioRuntimeResolvedConfig = {\n wireDialect: StdioRuntimeWireDialect;\n processScope: StdioRuntimeProcessScope;\n command: string;\n args: string[];\n cwd?: string;\n env?: StdioRuntimeEnv;\n startupTimeoutMs: number;\n probeTimeoutMs: number;\n requestTimeoutMs: number;\n};\n\nexport function readString(value: unknown): string | undefined {\n if (typeof value !== \"string\") {\n return undefined;\n }\n const trimmed = value.trim();\n return trimmed.length > 0 ? trimmed : undefined;\n}\n\nexport function readPositiveInteger(value: unknown): number | undefined {\n const parsed =\n typeof value === \"number\"\n ? value\n : typeof value === \"string\"\n ? Number.parseInt(value, 10)\n : Number.NaN;\n if (!Number.isFinite(parsed)) {\n return undefined;\n }\n const normalized = Math.trunc(parsed);\n return normalized > 0 ? normalized : undefined;\n}\n\nexport function readStringArray(value: unknown): string[] | undefined {\n if (!Array.isArray(value)) {\n return undefined;\n }\n\n const output: string[] = [];\n for (const entry of value) {\n const normalized = readString(entry);\n if (!normalized) {\n continue;\n }\n output.push(normalized);\n }\n return output.length > 0 ? output : undefined;\n}\n\nexport function readStringRecord(value: unknown): Record<string, string> | undefined {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n return undefined;\n }\n\n const output: Record<string, string> = {};\n for (const [entryKey, entryValue] of Object.entries(value)) {\n const normalizedValue = readString(entryValue);\n if (!normalizedValue) {\n continue;\n }\n output[entryKey] = normalizedValue;\n }\n return Object.keys(output).length > 0 ? output : undefined;\n}\n\nexport class StdioRuntimeConfigResolver {\n constructor(private readonly source: Record<string, unknown> = {}) {}\n\n resolve = (): StdioRuntimeResolvedConfig => {\n const wireDialect = this.resolveWireDialect();\n const processScope = this.resolveProcessScope();\n const command =\n readString(this.source.command) ??\n readString(process.env.NEXTCLAW_NARP_STDIO_COMMAND);\n if (!command) {\n throw new Error(\"[narp-stdio] missing stdio command\");\n }\n\n return {\n wireDialect,\n processScope,\n command,\n args:\n readStringArray(this.source.args) ??\n readStringArray(parseJsonArray(process.env.NEXTCLAW_NARP_STDIO_ARGS)) ??\n [],\n ...(readString(this.source.cwd) ?? readString(process.env.NEXTCLAW_NARP_STDIO_CWD)\n ? {\n cwd:\n readString(this.source.cwd) ??\n readString(process.env.NEXTCLAW_NARP_STDIO_CWD),\n }\n : {}),\n ...(readStringRecord(this.source.env) ?? readStringRecord(parseJsonObject(process.env.NEXTCLAW_NARP_STDIO_ENV))\n ? {\n env:\n readStringRecord(this.source.env) ??\n readStringRecord(parseJsonObject(process.env.NEXTCLAW_NARP_STDIO_ENV)),\n }\n : {}),\n startupTimeoutMs:\n readPositiveInteger(this.source.startupTimeoutMs) ??\n readPositiveInteger(process.env.NEXTCLAW_NARP_STDIO_STARTUP_TIMEOUT_MS) ??\n DEFAULT_STARTUP_TIMEOUT_MS,\n probeTimeoutMs:\n readPositiveInteger(this.source.probeTimeoutMs) ??\n DEFAULT_PROBE_TIMEOUT_MS,\n requestTimeoutMs:\n readPositiveInteger(this.source.requestTimeoutMs) ??\n DEFAULT_REQUEST_TIMEOUT_MS,\n };\n };\n\n private resolveWireDialect = (): StdioRuntimeWireDialect => {\n const wireDialect = readString(this.source.wireDialect) ?? \"acp\";\n if (wireDialect !== \"acp\") {\n throw new Error(`[narp-stdio] unsupported wireDialect \"${wireDialect}\"`);\n }\n return \"acp\";\n };\n\n private resolveProcessScope = (): StdioRuntimeProcessScope => {\n const processScope = readString(this.source.processScope) ?? \"per-session\";\n if (processScope !== \"per-session\") {\n throw new Error(`[narp-stdio] unsupported processScope \"${processScope}\"`);\n }\n return \"per-session\";\n };\n}\n\nexport function buildRuntimeRouteBridgeEnv(params: {\n providerRoute?: NcpProviderRuntimeRoute;\n}): Record<string, string> {\n const { providerRoute } = params;\n if (!providerRoute) {\n return {};\n }\n return {\n [DEFAULT_RUNTIME_ROUTE_BRIDGE_FIELDS.model]: providerRoute.model,\n [DEFAULT_RUNTIME_ROUTE_BRIDGE_FIELDS.apiBase]: providerRoute.apiBase ?? \"\",\n [DEFAULT_RUNTIME_ROUTE_BRIDGE_FIELDS.apiKey]: providerRoute.apiKey ?? \"\",\n [DEFAULT_RUNTIME_ROUTE_BRIDGE_FIELDS.headers]: JSON.stringify(providerRoute.headers ?? {}),\n };\n}\n\nexport function buildStdioRuntimeLaunchEnv(params: {\n baseEnv?: Record<string, string | undefined>;\n configEnv?: StdioRuntimeEnv;\n providerRoute?: NcpProviderRuntimeRoute;\n}): Record<string, string> {\n return {\n ...createRuntimeChildEnv(params.baseEnv ?? process.env, params.configEnv, {\n inheritBaseEnv: true,\n }),\n ...buildRuntimeRouteBridgeEnv({\n providerRoute: params.providerRoute,\n }),\n };\n}\n\nfunction parseJsonArray(value: unknown): unknown {\n if (typeof value !== \"string\" || !value.trim()) {\n return undefined;\n }\n try {\n return JSON.parse(value);\n } catch {\n return undefined;\n }\n}\n\nfunction parseJsonObject(value: unknown): unknown {\n if (typeof value !== \"string\" || !value.trim()) {\n return undefined;\n }\n try {\n return JSON.parse(value);\n } catch {\n return undefined;\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"stdio-runtime-config.utils.js","names":[],"sources":["../src/stdio-runtime-config.utils.ts"],"sourcesContent":["import type { OpenAITool, NcpProviderRuntimeRoute } from \"@nextclaw/ncp\";\nimport { createRuntimeChildEnv } from \"@nextclaw/core\";\n\nexport const NARP_STDIO_PROMPT_META_KEY = \"nextclaw_narp\";\nconst DEFAULT_STARTUP_TIMEOUT_MS = 10_000;\nconst DEFAULT_PROBE_TIMEOUT_MS = 3_000;\nconst DEFAULT_REQUEST_TIMEOUT_MS = 120_000;\nconst DEFAULT_RUNTIME_ROUTE_BRIDGE_FIELDS = {\n model: \"NEXTCLAW_MODEL\",\n apiBase: \"NEXTCLAW_API_BASE\",\n apiKey: \"NEXTCLAW_API_KEY\",\n headers: \"NEXTCLAW_HEADERS_JSON\",\n} as const;\n\nexport type StdioRuntimeEnv = Record<string, string>;\nexport type StdioRuntimeWireDialect = \"acp\";\nexport type StdioRuntimeProcessScope = \"per-session\";\n\nexport type NarpStdioPromptMeta = {\n correlationId?: string;\n providerRoute?: NcpProviderRuntimeRoute;\n sessionMetadata?: Record<string, unknown>;\n tools?: ReadonlyArray<OpenAITool>;\n};\n\nexport type StdioRuntimeResolvedConfig = {\n wireDialect: StdioRuntimeWireDialect;\n processScope: StdioRuntimeProcessScope;\n command: string;\n args: string[];\n cwd?: string;\n env?: StdioRuntimeEnv;\n resetSessionMetadataOnPromptTimeout?: string[];\n startupTimeoutMs: number;\n probeTimeoutMs: number;\n requestTimeoutMs: number;\n};\n\ntype StdioRuntimeCommandOverride = {\n command?: string;\n args?: string[];\n cwd?: string;\n env?: StdioRuntimeEnv;\n};\n\nexport function readString(value: unknown): string | undefined {\n if (typeof value !== \"string\") {\n return undefined;\n }\n const trimmed = value.trim();\n return trimmed.length > 0 ? trimmed : undefined;\n}\n\nexport function readPositiveInteger(value: unknown): number | undefined {\n const parsed =\n typeof value === \"number\"\n ? value\n : typeof value === \"string\"\n ? Number.parseInt(value, 10)\n : Number.NaN;\n if (!Number.isFinite(parsed)) {\n return undefined;\n }\n const normalized = Math.trunc(parsed);\n return normalized > 0 ? normalized : undefined;\n}\n\nexport function readStringArray(value: unknown): string[] | undefined {\n if (!Array.isArray(value)) {\n return undefined;\n }\n\n const output: string[] = [];\n for (const entry of value) {\n const normalized = readString(entry);\n if (!normalized) {\n continue;\n }\n output.push(normalized);\n }\n return output.length > 0 ? output : undefined;\n}\n\nexport function readStringRecord(value: unknown): Record<string, string> | undefined {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n return undefined;\n }\n\n const output: Record<string, string> = {};\n for (const [entryKey, entryValue] of Object.entries(value)) {\n const normalizedValue = readString(entryValue);\n if (!normalizedValue) {\n continue;\n }\n output[entryKey] = normalizedValue;\n }\n return Object.keys(output).length > 0 ? output : undefined;\n}\n\nfunction readCommandOverrides(value: unknown): Record<string, StdioRuntimeCommandOverride> {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n return {};\n }\n\n const overrides: Record<string, StdioRuntimeCommandOverride> = {};\n for (const [rawCommand, rawOverride] of Object.entries(value)) {\n const commandKey = readString(rawCommand);\n if (!commandKey || !rawOverride || typeof rawOverride !== \"object\" || Array.isArray(rawOverride)) {\n continue;\n }\n const overrideRecord = rawOverride as Record<string, unknown>;\n const command = readString(overrideRecord.command);\n const args = readStringArray(overrideRecord.args);\n const cwd = readString(overrideRecord.cwd);\n const env = readStringRecord(overrideRecord.env);\n if (!command && !args && !cwd && !env) {\n continue;\n }\n overrides[commandKey] = {\n ...(command ? { command } : {}),\n ...(args ? { args } : {}),\n ...(cwd ? { cwd } : {}),\n ...(env ? { env } : {}),\n };\n }\n return overrides;\n}\n\nfunction readCommandOverride(command: string): StdioRuntimeCommandOverride | undefined {\n const rawOverrides = parseJsonObject(process.env.NEXTCLAW_NARP_STDIO_COMMAND_OVERRIDES);\n return readCommandOverrides(rawOverrides)[command];\n}\n\nexport class StdioRuntimeConfigResolver {\n constructor(private readonly source: Record<string, unknown> = {}) {}\n\n resolve = (): StdioRuntimeResolvedConfig => {\n const wireDialect = this.resolveWireDialect();\n const processScope = this.resolveProcessScope();\n const command =\n readString(this.source.command) ??\n readString(process.env.NEXTCLAW_NARP_STDIO_COMMAND);\n if (!command) {\n throw new Error(\"[narp-stdio] missing stdio command\");\n }\n\n const override = readCommandOverride(command);\n const args =\n override?.args ??\n readStringArray(this.source.args) ??\n readStringArray(parseJsonArray(process.env.NEXTCLAW_NARP_STDIO_ARGS)) ??\n [];\n const cwd =\n override?.cwd ??\n readString(this.source.cwd) ??\n readString(process.env.NEXTCLAW_NARP_STDIO_CWD);\n const env =\n override?.env ??\n readStringRecord(this.source.env) ??\n readStringRecord(parseJsonObject(process.env.NEXTCLAW_NARP_STDIO_ENV));\n const resetSessionMetadataOnPromptTimeout = readStringArray(\n this.source.resetSessionMetadataOnPromptTimeout,\n );\n\n return {\n wireDialect,\n processScope,\n command: override?.command ?? command,\n args,\n ...(cwd ? { cwd } : {}),\n ...(env ? { env } : {}),\n ...(resetSessionMetadataOnPromptTimeout\n ? { resetSessionMetadataOnPromptTimeout }\n : {}),\n startupTimeoutMs:\n readPositiveInteger(this.source.startupTimeoutMs) ??\n readPositiveInteger(process.env.NEXTCLAW_NARP_STDIO_STARTUP_TIMEOUT_MS) ??\n DEFAULT_STARTUP_TIMEOUT_MS,\n probeTimeoutMs:\n readPositiveInteger(this.source.probeTimeoutMs) ??\n DEFAULT_PROBE_TIMEOUT_MS,\n requestTimeoutMs:\n readPositiveInteger(this.source.requestTimeoutMs) ??\n DEFAULT_REQUEST_TIMEOUT_MS,\n };\n };\n\n private resolveWireDialect = (): StdioRuntimeWireDialect => {\n const wireDialect = readString(this.source.wireDialect) ?? \"acp\";\n if (wireDialect !== \"acp\") {\n throw new Error(`[narp-stdio] unsupported wireDialect \"${wireDialect}\"`);\n }\n return \"acp\";\n };\n\n private resolveProcessScope = (): StdioRuntimeProcessScope => {\n const processScope = readString(this.source.processScope) ?? \"per-session\";\n if (processScope !== \"per-session\") {\n throw new Error(`[narp-stdio] unsupported processScope \"${processScope}\"`);\n }\n return \"per-session\";\n };\n}\n\nexport function buildRuntimeRouteBridgeEnv(params: {\n providerRoute?: NcpProviderRuntimeRoute;\n}): Record<string, string> {\n const { providerRoute } = params;\n if (!providerRoute) {\n return {};\n }\n return {\n [DEFAULT_RUNTIME_ROUTE_BRIDGE_FIELDS.model]: providerRoute.model,\n [DEFAULT_RUNTIME_ROUTE_BRIDGE_FIELDS.apiBase]: providerRoute.apiBase ?? \"\",\n [DEFAULT_RUNTIME_ROUTE_BRIDGE_FIELDS.apiKey]: providerRoute.apiKey ?? \"\",\n [DEFAULT_RUNTIME_ROUTE_BRIDGE_FIELDS.headers]: JSON.stringify(providerRoute.headers ?? {}),\n };\n}\n\nexport function buildStdioRuntimeLaunchEnv(params: {\n baseEnv?: Record<string, string | undefined>;\n configEnv?: StdioRuntimeEnv;\n providerRoute?: NcpProviderRuntimeRoute;\n}): Record<string, string> {\n return {\n ...createRuntimeChildEnv(params.baseEnv ?? process.env, params.configEnv, {\n inheritBaseEnv: true,\n }),\n ...buildRuntimeRouteBridgeEnv({\n providerRoute: params.providerRoute,\n }),\n };\n}\n\nfunction parseJsonArray(value: unknown): unknown {\n if (typeof value !== \"string\" || !value.trim()) {\n return undefined;\n }\n try {\n return JSON.parse(value);\n } catch {\n return undefined;\n }\n}\n\nfunction parseJsonObject(value: unknown): unknown {\n if (typeof value !== \"string\" || !value.trim()) {\n return undefined;\n }\n try {\n return JSON.parse(value);\n } catch {\n return undefined;\n }\n}\n"],"mappings":"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"}
|
|
@@ -3,9 +3,9 @@ function buildSpawnFailureMessage(params) {
|
|
|
3
3
|
const { command, cwd, error } = params;
|
|
4
4
|
return `[narp-stdio] failed to start stdio runtime command "${command}"${cwd ? ` (cwd: ${cwd})` : ""}: ${error.message}`;
|
|
5
5
|
}
|
|
6
|
-
function normalizeRuntimeError(error) {
|
|
6
|
+
function normalizeRuntimeError(error, diagnostics = {}) {
|
|
7
7
|
if (isNcpError(error)) return error;
|
|
8
|
-
const message = error
|
|
8
|
+
const message = formatRuntimeErrorMessage(error, diagnostics);
|
|
9
9
|
const lowered = message.toLowerCase();
|
|
10
10
|
return {
|
|
11
11
|
code: lowered.includes("abort") || lowered.includes("cancel") ? "abort-error" : "runtime-error",
|
|
@@ -17,6 +17,11 @@ function isAbortLikeRuntimeError(error) {
|
|
|
17
17
|
const lowered = (error instanceof Error ? error.message : String(error)).toLowerCase();
|
|
18
18
|
return lowered.includes("abort") || lowered.includes("cancel");
|
|
19
19
|
}
|
|
20
|
+
function formatRuntimeErrorMessage(error, diagnostics = {}) {
|
|
21
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
22
|
+
const stderr = diagnostics.stderr?.trim();
|
|
23
|
+
return stderr && !message.includes(stderr) ? `${message}. stderr=${stderr}` : message;
|
|
24
|
+
}
|
|
20
25
|
function isNcpError(value) {
|
|
21
26
|
if (!value || typeof value !== "object") return false;
|
|
22
27
|
return typeof value.code === "string" && typeof value.message === "string";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stdio-runtime-error.utils.js","names":[],"sources":["../src/stdio-runtime-error.utils.ts"],"sourcesContent":["import type { NcpError } from \"@nextclaw/ncp\";\n\nexport function buildSpawnFailureMessage(params: {\n command: string;\n cwd?: string;\n error: Error;\n}): string {\n const { command, cwd, error } = params;\n const cwdSuffix = cwd ? ` (cwd: ${cwd})` : \"\";\n return `[narp-stdio] failed to start stdio runtime command \"${command}\"${cwdSuffix}: ${error.message}`;\n}\n\nexport function normalizeRuntimeError(error: unknown): NcpError {\n if (isNcpError(error)) {\n return error;\n }\n const message = error
|
|
1
|
+
{"version":3,"file":"stdio-runtime-error.utils.js","names":[],"sources":["../src/stdio-runtime-error.utils.ts"],"sourcesContent":["import type { NcpError } from \"@nextclaw/ncp\";\n\nexport function buildSpawnFailureMessage(params: {\n command: string;\n cwd?: string;\n error: Error;\n}): string {\n const { command, cwd, error } = params;\n const cwdSuffix = cwd ? ` (cwd: ${cwd})` : \"\";\n return `[narp-stdio] failed to start stdio runtime command \"${command}\"${cwdSuffix}: ${error.message}`;\n}\n\nexport function normalizeRuntimeError(\n error: unknown,\n diagnostics: { stderr?: string } = {},\n): NcpError {\n if (isNcpError(error)) {\n return error;\n }\n const message = formatRuntimeErrorMessage(error, diagnostics);\n const lowered = message.toLowerCase();\n return {\n code: lowered.includes(\"abort\") || lowered.includes(\"cancel\")\n ? \"abort-error\"\n : \"runtime-error\",\n message,\n };\n}\n\nexport function isAbortLikeRuntimeError(error: unknown): boolean {\n if (isNcpError(error)) {\n return error.code === \"abort-error\";\n }\n const message = error instanceof Error ? error.message : String(error);\n const lowered = message.toLowerCase();\n return lowered.includes(\"abort\") || lowered.includes(\"cancel\");\n}\n\nexport function formatRuntimeErrorMessage(\n error: unknown,\n diagnostics: { stderr?: string } = {},\n): string {\n const message = error instanceof Error ? error.message : String(error);\n const stderr = diagnostics.stderr?.trim();\n return stderr && !message.includes(stderr) ? `${message}. stderr=${stderr}` : message;\n}\n\nfunction isNcpError(value: unknown): value is NcpError {\n if (!value || typeof value !== \"object\") {\n return false;\n }\n return typeof (value as NcpError).code === \"string\" && typeof (value as NcpError).message === \"string\";\n}\n"],"mappings":";AAEA,SAAgB,yBAAyB,QAI9B;CACT,MAAM,EAAE,SAAS,KAAK,UAAU;AAEhC,QAAO,uDAAuD,QAAQ,GADpD,MAAM,UAAU,IAAI,KAAK,GACwC,IAAI,MAAM;;AAG/F,SAAgB,sBACd,OACA,cAAmC,EAAE,EAC3B;AACV,KAAI,WAAW,MAAM,CACnB,QAAO;CAET,MAAM,UAAU,0BAA0B,OAAO,YAAY;CAC7D,MAAM,UAAU,QAAQ,aAAa;AACrC,QAAO;EACL,MAAM,QAAQ,SAAS,QAAQ,IAAI,QAAQ,SAAS,SAAS,GACzD,gBACA;EACJ;EACD;;AAGH,SAAgB,wBAAwB,OAAyB;AAC/D,KAAI,WAAW,MAAM,CACnB,QAAO,MAAM,SAAS;CAGxB,MAAM,WADU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,EAC9C,aAAa;AACrC,QAAO,QAAQ,SAAS,QAAQ,IAAI,QAAQ,SAAS,SAAS;;AAGhE,SAAgB,0BACd,OACA,cAAmC,EAAE,EAC7B;CACR,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;CACtE,MAAM,SAAS,YAAY,QAAQ,MAAM;AACzC,QAAO,UAAU,CAAC,QAAQ,SAAS,OAAO,GAAG,GAAG,QAAQ,WAAW,WAAW;;AAGhF,SAAS,WAAW,OAAmC;AACrD,KAAI,CAAC,SAAS,OAAO,UAAU,SAC7B,QAAO;AAET,QAAO,OAAQ,MAAmB,SAAS,YAAY,OAAQ,MAAmB,YAAY"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stdio-runtime-probe.utils.d.ts","names":[],"sources":["../src/stdio-runtime-probe.utils.ts"],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"stdio-runtime-probe.utils.d.ts","names":[],"sources":["../src/stdio-runtime-probe.utils.ts"],"mappings":";;;iBAwBsB,iBAAA,CAAkB,MAAA,EAAQ,0BAAA,GAA6B,OAAA"}
|
|
@@ -3,6 +3,7 @@ import { buildSpawnFailureMessage } from "./stdio-runtime-error.utils.js";
|
|
|
3
3
|
import { spawn } from "node:child_process";
|
|
4
4
|
import { Readable, Writable } from "node:stream";
|
|
5
5
|
import * as acp from "@agentclientprotocol/sdk";
|
|
6
|
+
import { tmpdir } from "node:os";
|
|
6
7
|
//#region src/stdio-runtime-probe.utils.ts
|
|
7
8
|
const createProbeClientBridge = () => ({
|
|
8
9
|
sessionUpdate: async () => void 0,
|
|
@@ -37,16 +38,17 @@ async function probeStdioRuntime(config) {
|
|
|
37
38
|
});
|
|
38
39
|
const stream = acp.ndJsonStream(Writable.toWeb(child.stdin), Readable.toWeb(child.stdout));
|
|
39
40
|
const connection = new acp.ClientSideConnection(() => createProbeClientBridge(), stream);
|
|
41
|
+
const newSessionParams = {
|
|
42
|
+
cwd: config.cwd ?? tmpdir(),
|
|
43
|
+
mcpServers: []
|
|
44
|
+
};
|
|
40
45
|
try {
|
|
41
46
|
const session = await Promise.race([(async () => {
|
|
42
47
|
await withTimeout(connection.initialize({
|
|
43
48
|
protocolVersion: acp.PROTOCOL_VERSION,
|
|
44
49
|
clientCapabilities: {}
|
|
45
50
|
}), config.probeTimeoutMs, `[narp-stdio] probe timed out initializing stdio runtime`);
|
|
46
|
-
return withTimeout(connection.newSession(
|
|
47
|
-
cwd: config.cwd ?? process.cwd(),
|
|
48
|
-
mcpServers: []
|
|
49
|
-
}), config.probeTimeoutMs, `[narp-stdio] probe timed out creating remote session`);
|
|
51
|
+
return withTimeout(connection.newSession(newSessionParams), config.probeTimeoutMs, `[narp-stdio] probe timed out creating remote session`);
|
|
50
52
|
})(), spawnErrorPromise]);
|
|
51
53
|
await connection.cancel({ sessionId: session.sessionId }).catch(() => void 0);
|
|
52
54
|
} catch (error) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stdio-runtime-probe.utils.js","names":[],"sources":["../src/stdio-runtime-probe.utils.ts"],"sourcesContent":["import { spawn } from \"node:child_process\";\nimport { Readable, Writable } from \"node:stream\";\nimport * as acp from \"@agentclientprotocol/sdk\";\nimport {\n buildStdioRuntimeLaunchEnv,\n type StdioRuntimeResolvedConfig,\n} from \"./stdio-runtime-config.utils.js\";\nimport { buildSpawnFailureMessage } from \"./stdio-runtime-error.utils.js\";\n\ntype ProbeClientBridge = {\n sessionUpdate: (params: { sessionId: string; update: unknown }) => Promise<void>;\n requestPermission: () => Promise<{ outcome: { outcome: \"cancelled\" } }>;\n readTextFile: () => Promise<{ content: string }>;\n writeTextFile: () => Promise<Record<string, never>>;\n};\n\nconst createProbeClientBridge = (): ProbeClientBridge => ({\n sessionUpdate: async () => undefined,\n requestPermission: async () => ({ outcome: { outcome: \"cancelled\" } }),\n readTextFile: async () => ({ content: \"\" }),\n writeTextFile: async () => ({}),\n});\n\nexport async function probeStdioRuntime(config: StdioRuntimeResolvedConfig): Promise<void> {\n const child = spawn(config.command, config.args, {\n cwd: config.cwd,\n env: buildStdioRuntimeLaunchEnv({\n configEnv: config.env,\n }),\n stdio: [\"pipe\", \"pipe\", \"pipe\"], windowsHide: true,\n });\n const spawnErrorPromise = new Promise<never>((_, reject) => {\n child.once(\"error\", (error) => {\n reject(new Error(buildSpawnFailureMessage({ command: config.command, cwd: config.cwd, error })));\n });\n });\n\n let stderr = \"\";\n child.stderr.setEncoding(\"utf8\");\n child.stderr.on(\"data\", (chunk: string) => {\n stderr = `${stderr}${chunk}`.slice(-4000);\n });\n\n const stream = acp.ndJsonStream(\n Writable.toWeb(child.stdin),\n Readable.toWeb(child.stdout),\n );\n const connection = new acp.ClientSideConnection(\n () => createProbeClientBridge(),\n stream,\n );\n\n try {\n const session = await Promise.race([\n (async () => {\n await withTimeout(\n connection.initialize({\n protocolVersion: acp.PROTOCOL_VERSION,\n clientCapabilities: {},\n }),\n config.probeTimeoutMs,\n `[narp-stdio] probe timed out initializing stdio runtime`,\n );\n return withTimeout(\n connection.newSession(
|
|
1
|
+
{"version":3,"file":"stdio-runtime-probe.utils.js","names":[],"sources":["../src/stdio-runtime-probe.utils.ts"],"sourcesContent":["import { spawn } from \"node:child_process\";\nimport { tmpdir } from \"node:os\";\nimport { Readable, Writable } from \"node:stream\";\nimport * as acp from \"@agentclientprotocol/sdk\";\nimport {\n buildStdioRuntimeLaunchEnv,\n type StdioRuntimeResolvedConfig,\n} from \"./stdio-runtime-config.utils.js\";\nimport { buildSpawnFailureMessage } from \"./stdio-runtime-error.utils.js\";\n\ntype ProbeClientBridge = {\n sessionUpdate: (params: { sessionId: string; update: unknown }) => Promise<void>;\n requestPermission: () => Promise<{ outcome: { outcome: \"cancelled\" } }>;\n readTextFile: () => Promise<{ content: string }>;\n writeTextFile: () => Promise<Record<string, never>>;\n};\n\nconst createProbeClientBridge = (): ProbeClientBridge => ({\n sessionUpdate: async () => undefined,\n requestPermission: async () => ({ outcome: { outcome: \"cancelled\" } }),\n readTextFile: async () => ({ content: \"\" }),\n writeTextFile: async () => ({}),\n});\n\nexport async function probeStdioRuntime(config: StdioRuntimeResolvedConfig): Promise<void> {\n const child = spawn(config.command, config.args, {\n cwd: config.cwd,\n env: buildStdioRuntimeLaunchEnv({\n configEnv: config.env,\n }),\n stdio: [\"pipe\", \"pipe\", \"pipe\"], windowsHide: true,\n });\n const spawnErrorPromise = new Promise<never>((_, reject) => {\n child.once(\"error\", (error) => {\n reject(new Error(buildSpawnFailureMessage({ command: config.command, cwd: config.cwd, error })));\n });\n });\n\n let stderr = \"\";\n child.stderr.setEncoding(\"utf8\");\n child.stderr.on(\"data\", (chunk: string) => {\n stderr = `${stderr}${chunk}`.slice(-4000);\n });\n\n const stream = acp.ndJsonStream(\n Writable.toWeb(child.stdin),\n Readable.toWeb(child.stdout),\n );\n const connection = new acp.ClientSideConnection(\n () => createProbeClientBridge(),\n stream,\n );\n const newSessionParams = {\n cwd: config.cwd ?? tmpdir(),\n mcpServers: [],\n };\n\n try {\n const session = await Promise.race([\n (async () => {\n await withTimeout(\n connection.initialize({\n protocolVersion: acp.PROTOCOL_VERSION,\n clientCapabilities: {},\n }),\n config.probeTimeoutMs,\n `[narp-stdio] probe timed out initializing stdio runtime`,\n );\n return withTimeout(\n connection.newSession(newSessionParams),\n config.probeTimeoutMs,\n `[narp-stdio] probe timed out creating remote session`,\n );\n })(),\n spawnErrorPromise,\n ]);\n await connection.cancel({ sessionId: session.sessionId }).catch(() => undefined);\n } catch (error) {\n const message =\n error instanceof Error ? error.message : \"[narp-stdio] stdio runtime probe failed\";\n throw new Error(`${message}. stderr=${stderr}`.trim());\n } finally {\n child.kill(\"SIGTERM\");\n }\n}\n\nasync function withTimeout<T>(\n promise: Promise<T>,\n timeoutMs: number,\n message: string,\n): Promise<T> {\n let timeoutHandle: NodeJS.Timeout | undefined;\n const timeoutPromise = new Promise<never>((_, reject) => {\n timeoutHandle = setTimeout(() => reject(new Error(message)), timeoutMs);\n });\n try {\n return await Promise.race([promise, timeoutPromise]);\n } finally {\n if (timeoutHandle) {\n clearTimeout(timeoutHandle);\n }\n }\n}\n"],"mappings":";;;;;;;AAiBA,MAAM,iCAAoD;CACxD,eAAe,YAAY,KAAA;CAC3B,mBAAmB,aAAa,EAAE,SAAS,EAAE,SAAS,aAAa,EAAE;CACrE,cAAc,aAAa,EAAE,SAAS,IAAI;CAC1C,eAAe,aAAa,EAAE;CAC/B;AAED,eAAsB,kBAAkB,QAAmD;CACzF,MAAM,QAAQ,MAAM,OAAO,SAAS,OAAO,MAAM;EAC/C,KAAK,OAAO;EACZ,KAAK,2BAA2B,EAC9B,WAAW,OAAO,KACnB,CAAC;EACF,OAAO;GAAC;GAAQ;GAAQ;GAAO;EAAE,aAAa;EAC/C,CAAC;CACF,MAAM,oBAAoB,IAAI,SAAgB,GAAG,WAAW;AAC1D,QAAM,KAAK,UAAU,UAAU;AAC7B,UAAO,IAAI,MAAM,yBAAyB;IAAE,SAAS,OAAO;IAAS,KAAK,OAAO;IAAK;IAAO,CAAC,CAAC,CAAC;IAChG;GACF;CAEF,IAAI,SAAS;AACb,OAAM,OAAO,YAAY,OAAO;AAChC,OAAM,OAAO,GAAG,SAAS,UAAkB;AACzC,WAAS,GAAG,SAAS,QAAQ,MAAM,KAAM;GACzC;CAEF,MAAM,SAAS,IAAI,aACjB,SAAS,MAAM,MAAM,MAAM,EAC3B,SAAS,MAAM,MAAM,OAAO,CAC7B;CACD,MAAM,aAAa,IAAI,IAAI,2BACnB,yBAAyB,EAC/B,OACD;CACD,MAAM,mBAAmB;EACvB,KAAK,OAAO,OAAO,QAAQ;EAC3B,YAAY,EAAE;EACf;AAED,KAAI;EACF,MAAM,UAAU,MAAM,QAAQ,KAAK,EAChC,YAAY;AACX,SAAM,YACJ,WAAW,WAAW;IACpB,iBAAiB,IAAI;IACrB,oBAAoB,EAAE;IACvB,CAAC,EACF,OAAO,gBACP,0DACD;AACD,UAAO,YACL,WAAW,WAAW,iBAAiB,EACvC,OAAO,gBACP,uDACD;MACC,EACJ,kBACD,CAAC;AACF,QAAM,WAAW,OAAO,EAAE,WAAW,QAAQ,WAAW,CAAC,CAAC,YAAY,KAAA,EAAU;UACzE,OAAO;EACd,MAAM,UACJ,iBAAiB,QAAQ,MAAM,UAAU;AAC3C,QAAM,IAAI,MAAM,GAAG,QAAQ,WAAW,SAAS,MAAM,CAAC;WAC9C;AACR,QAAM,KAAK,UAAU;;;AAIzB,eAAe,YACb,SACA,WACA,SACY;CACZ,IAAI;CACJ,MAAM,iBAAiB,IAAI,SAAgB,GAAG,WAAW;AACvD,kBAAgB,iBAAiB,OAAO,IAAI,MAAM,QAAQ,CAAC,EAAE,UAAU;GACvE;AACF,KAAI;AACF,SAAO,MAAM,QAAQ,KAAK,CAAC,SAAS,eAAe,CAAC;WAC5C;AACR,MAAI,cACF,cAAa,cAAc"}
|
|
@@ -3,7 +3,6 @@ import { NcpAgentConversationStateManager, NcpAgentRunInput, NcpAgentRunOptions,
|
|
|
3
3
|
|
|
4
4
|
//#region src/stdio-runtime.service.d.ts
|
|
5
5
|
type StdioRuntimeNcpAgentRuntimeConfig = StdioRuntimeResolvedConfig & {
|
|
6
|
-
sessionId: string;
|
|
7
6
|
stateManager?: NcpAgentConversationStateManager;
|
|
8
7
|
resolveTools?: (input: NcpAgentRunInput) => ReadonlyArray<OpenAITool> | undefined;
|
|
9
8
|
resolveProviderRoute?: (input: NcpAgentRunInput) => NcpProviderRuntimeRoute | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stdio-runtime.service.d.ts","names":[],"sources":["../src/stdio-runtime.service.ts"],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"stdio-runtime.service.d.ts","names":[],"sources":["../src/stdio-runtime.service.ts"],"mappings":";;;;KAgCY,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,cAq0BzC,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,5 +1,7 @@
|
|
|
1
|
-
import { NARP_STDIO_PROMPT_META_KEY, buildStdioRuntimeLaunchEnv
|
|
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";
|
|
4
|
+
import { extractPromptText, resolveModelId } from "./utils/stdio-runtime-input.utils.js";
|
|
3
5
|
import { resolveToolNameFromAcpUpdate } from "./stdio-runtime-tool-name.utils.js";
|
|
4
6
|
import { randomUUID } from "node:crypto";
|
|
5
7
|
import { spawn } from "node:child_process";
|
|
@@ -157,16 +159,21 @@ var StdioRuntimeSession = class {
|
|
|
157
159
|
connection = null;
|
|
158
160
|
promptInFlight = false;
|
|
159
161
|
remoteSessionId = null;
|
|
162
|
+
remoteSessionCwd = null;
|
|
160
163
|
clientBridge = new StdioRuntimeClientBridge();
|
|
161
164
|
stderr = "";
|
|
162
165
|
pendingProviderRoute;
|
|
163
|
-
constructor(config
|
|
166
|
+
constructor(config) {
|
|
164
167
|
this.config = config;
|
|
165
|
-
this.sessionId = sessionId;
|
|
166
168
|
}
|
|
167
169
|
ensureStarted = async (params) => {
|
|
168
|
-
|
|
169
|
-
|
|
170
|
+
const { cwd, providerRoute } = params;
|
|
171
|
+
this.pendingProviderRoute = providerRoute;
|
|
172
|
+
if (this.connection && this.remoteSessionId) {
|
|
173
|
+
if (this.remoteSessionCwd === cwd) return;
|
|
174
|
+
await this.dispose();
|
|
175
|
+
}
|
|
176
|
+
if (!cwd) throw new Error("[narp-stdio] missing execution cwd for stdio runtime session");
|
|
170
177
|
const env = buildStdioRuntimeLaunchEnv({
|
|
171
178
|
configEnv: this.config.env,
|
|
172
179
|
providerRoute: this.pendingProviderRoute
|
|
@@ -200,15 +207,16 @@ var StdioRuntimeSession = class {
|
|
|
200
207
|
await withTimeout(this.connection?.initialize({
|
|
201
208
|
protocolVersion: acp.PROTOCOL_VERSION,
|
|
202
209
|
clientCapabilities: {}
|
|
203
|
-
}) ?? Promise.reject(/* @__PURE__ */ new Error("[narp-stdio] stdio runtime connection not started")), this.config.startupTimeoutMs,
|
|
210
|
+
}) ?? Promise.reject(/* @__PURE__ */ new Error("[narp-stdio] stdio runtime connection not started")), this.config.startupTimeoutMs, "[narp-stdio] timed out initializing stdio runtime");
|
|
204
211
|
return withTimeout(this.connection?.newSession({
|
|
205
|
-
cwd
|
|
212
|
+
cwd,
|
|
206
213
|
mcpServers: []
|
|
207
|
-
}) ?? Promise.reject(/* @__PURE__ */ new Error("[narp-stdio] stdio runtime connection not started")), this.config.startupTimeoutMs,
|
|
214
|
+
}) ?? Promise.reject(/* @__PURE__ */ new Error("[narp-stdio] stdio runtime connection not started")), this.config.startupTimeoutMs, "[narp-stdio] timed out creating remote stdio session");
|
|
208
215
|
})(), spawnErrorPromise])).sessionId;
|
|
216
|
+
this.remoteSessionCwd = cwd;
|
|
209
217
|
};
|
|
210
218
|
runPrompt = async (params) => {
|
|
211
|
-
const { meta, modelId, onUpdate, signal, text } = params;
|
|
219
|
+
const { meta, modelId, onUpdate, sessionId, signal, text } = params;
|
|
212
220
|
if (!this.connection || !this.remoteSessionId) throw new Error("[narp-stdio] stdio runtime connection not started");
|
|
213
221
|
if (this.promptInFlight) throw new Error("[narp-stdio] concurrent prompt is not supported for one stdio session");
|
|
214
222
|
this.promptInFlight = true;
|
|
@@ -231,7 +239,7 @@ var StdioRuntimeSession = class {
|
|
|
231
239
|
text
|
|
232
240
|
}],
|
|
233
241
|
_meta: { [NARP_STDIO_PROMPT_META_KEY]: meta }
|
|
234
|
-
}), this.config.requestTimeoutMs, `[narp-stdio] prompt timed out for session ${
|
|
242
|
+
}), this.config.requestTimeoutMs, `[narp-stdio] prompt timed out for session ${sessionId}`);
|
|
235
243
|
} finally {
|
|
236
244
|
releaseAbort();
|
|
237
245
|
detach();
|
|
@@ -259,20 +267,26 @@ var StdioRuntimeSession = class {
|
|
|
259
267
|
};
|
|
260
268
|
};
|
|
261
269
|
readStderr = () => this.stderr;
|
|
270
|
+
readPromptTimeoutMetadataResetKeys = () => this.config.resetSessionMetadataOnPromptTimeout;
|
|
262
271
|
dispose = async () => {
|
|
263
272
|
await this.cancel();
|
|
264
273
|
const child = this.child;
|
|
265
274
|
this.connection = null;
|
|
266
275
|
this.remoteSessionId = null;
|
|
276
|
+
this.remoteSessionCwd = null;
|
|
267
277
|
this.child = null;
|
|
268
278
|
if (!child || child.killed || child.exitCode !== null || child.signalCode !== null) return;
|
|
279
|
+
const exited = new Promise((resolve) => {
|
|
280
|
+
child.once("exit", () => resolve());
|
|
281
|
+
child.once("error", () => resolve());
|
|
282
|
+
});
|
|
269
283
|
const forceKill = setTimeout(() => {
|
|
270
284
|
child.kill("SIGKILL");
|
|
271
285
|
}, 3e3);
|
|
272
|
-
|
|
273
|
-
clearTimeout(forceKill);
|
|
274
|
-
});
|
|
286
|
+
forceKill.unref();
|
|
275
287
|
child.kill("SIGTERM");
|
|
288
|
+
await exited;
|
|
289
|
+
clearTimeout(forceKill);
|
|
276
290
|
};
|
|
277
291
|
};
|
|
278
292
|
var StdioRuntimeRunController = class {
|
|
@@ -299,6 +313,7 @@ var StdioRuntimeRunController = class {
|
|
|
299
313
|
if (!requestMessage) throw new Error("[narp-stdio] runtime.run requires at least one input message");
|
|
300
314
|
const assistantMessageId = createAssistantMessageId(requestMessage.id);
|
|
301
315
|
const promptPromise = this.session.runPrompt({
|
|
316
|
+
sessionId: this.input.sessionId,
|
|
302
317
|
text: extractPromptText(requestMessage),
|
|
303
318
|
meta: {
|
|
304
319
|
...this.input.correlationId ? { correlationId: this.input.correlationId } : {},
|
|
@@ -318,6 +333,7 @@ var StdioRuntimeRunController = class {
|
|
|
318
333
|
try {
|
|
319
334
|
yield* this.drainPromptUpdates(assistantMessageId, promptState);
|
|
320
335
|
if (this.shouldExitForAbort(options, promptState.error)) return;
|
|
336
|
+
if (promptState.error) throw promptState.error;
|
|
321
337
|
yield* this.emitCompletionEvents(assistantMessageId);
|
|
322
338
|
} catch (error) {
|
|
323
339
|
if (this.shouldExitForAbort(options, error)) return;
|
|
@@ -395,7 +411,15 @@ var StdioRuntimeRunController = class {
|
|
|
395
411
|
});
|
|
396
412
|
};
|
|
397
413
|
emitFailureEvents = async function* (assistantMessageId, error) {
|
|
398
|
-
const ncpError = normalizeRuntimeError(error);
|
|
414
|
+
const ncpError = normalizeRuntimeError(error, { stderr: this.session.readStderr() });
|
|
415
|
+
for (const recoveryEvent of createPromptTimeoutRecoveryEvents({
|
|
416
|
+
correlationId: this.input.correlationId,
|
|
417
|
+
error,
|
|
418
|
+
messageId: assistantMessageId,
|
|
419
|
+
resetKeys: this.session.readPromptTimeoutMetadataResetKeys(),
|
|
420
|
+
runId: this.runId,
|
|
421
|
+
sessionId: this.input.sessionId
|
|
422
|
+
})) yield* this.emitEvent(recoveryEvent);
|
|
399
423
|
yield* this.emitEvent({
|
|
400
424
|
type: NcpEventType.MessageFailed,
|
|
401
425
|
payload: {
|
|
@@ -426,9 +450,27 @@ var StdioRuntimeRunController = class {
|
|
|
426
450
|
case "agent_thought_chunk": return this.emitReasoningDelta(update.content, messageId);
|
|
427
451
|
case "tool_call": return this.emitToolCallStart(update, messageId);
|
|
428
452
|
case "tool_call_update": return this.emitToolCallUpdate(update);
|
|
453
|
+
case "session_info_update": return this.emitSessionInfoUpdate(update, messageId);
|
|
429
454
|
default: return [];
|
|
430
455
|
}
|
|
431
456
|
};
|
|
457
|
+
emitSessionInfoUpdate = (update, messageId) => {
|
|
458
|
+
const patch = readSessionMetadataPatch(update._meta);
|
|
459
|
+
if (!patch) return [];
|
|
460
|
+
return [{
|
|
461
|
+
type: NcpEventType.RunMetadata,
|
|
462
|
+
payload: {
|
|
463
|
+
sessionId: this.input.sessionId,
|
|
464
|
+
messageId,
|
|
465
|
+
runId: this.runId,
|
|
466
|
+
...this.input.correlationId ? { correlationId: this.input.correlationId } : {},
|
|
467
|
+
metadata: {
|
|
468
|
+
kind: SESSION_METADATA_PATCH_KIND,
|
|
469
|
+
sessionMetadataPatch: patch
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
}];
|
|
473
|
+
};
|
|
432
474
|
emitTextDelta = (content, messageId) => this.emitContentDelta({
|
|
433
475
|
content,
|
|
434
476
|
messageId,
|
|
@@ -577,26 +619,26 @@ var StdioRuntimeNcpAgentRuntime = class {
|
|
|
577
619
|
session;
|
|
578
620
|
constructor(config) {
|
|
579
621
|
this.config = config;
|
|
580
|
-
this.session = new StdioRuntimeSession(config
|
|
622
|
+
this.session = new StdioRuntimeSession(config);
|
|
581
623
|
}
|
|
582
624
|
run = async function* (input, options) {
|
|
583
|
-
await this.session.ensureStarted({
|
|
625
|
+
await this.session.ensureStarted({
|
|
626
|
+
cwd: input.executionContext?.cwd,
|
|
627
|
+
providerRoute: this.config.resolveProviderRoute?.(input)
|
|
628
|
+
});
|
|
584
629
|
yield* new StdioRuntimeRunController(this.session, input, this.config.stateManager, this.config.resolveTools, this.config.resolveProviderRoute).execute(options);
|
|
585
630
|
};
|
|
586
631
|
dispose = async () => {
|
|
587
632
|
await this.session.dispose();
|
|
588
633
|
};
|
|
589
634
|
};
|
|
590
|
-
function
|
|
591
|
-
const
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
}).join("\n").trim();
|
|
595
|
-
return text.length > 0 ? text : "[empty message]";
|
|
635
|
+
function readSessionMetadataPatch(meta) {
|
|
636
|
+
const narpMeta = isRecord(meta) ? meta[NARP_STDIO_PROMPT_META_KEY] : void 0;
|
|
637
|
+
const patch = isRecord(narpMeta) ? narpMeta.sessionMetadataPatch : void 0;
|
|
638
|
+
return isRecord(patch) && Object.keys(patch).length > 0 ? structuredClone(patch) : null;
|
|
596
639
|
}
|
|
597
|
-
function
|
|
598
|
-
|
|
599
|
-
return providerRoute?.model ?? readString(metadata?.preferred_model) ?? readString(metadata?.preferredModel) ?? readString(metadata?.model);
|
|
640
|
+
function isRecord(value) {
|
|
641
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
600
642
|
}
|
|
601
643
|
function resolveToolName(update) {
|
|
602
644
|
return resolveToolNameFromAcpUpdate(update);
|
|
@@ -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 type {\n NcpAgentConversationStateManager,\n NcpAgentRunInput,\n NcpAgentRunOptions,\n NcpAgentRuntime,\n NcpEndpointEvent,\n NcpProviderRuntimeRoute,\n OpenAITool,\n} from \"@nextclaw/ncp\";\nimport { NcpEventType } from \"@nextclaw/ncp\";\nimport type { StdioRuntimeResolvedConfig, NarpStdioPromptMeta } from \"./stdio-runtime-config.utils.js\";\nimport {\n NARP_STDIO_PROMPT_META_KEY,\n buildStdioRuntimeLaunchEnv,\n readString,\n} from \"./stdio-runtime-config.utils.js\";\nimport {\n buildSpawnFailureMessage,\n isAbortLikeRuntimeError,\n normalizeRuntimeError,\n} from \"./stdio-runtime-error.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 sessionId: string;\n stateManager?: NcpAgentConversationStateManager;\n resolveTools?: (input: NcpAgentRunInput) => ReadonlyArray<OpenAITool> | undefined;\n resolveProviderRoute?: (input: NcpAgentRunInput) => NcpProviderRuntimeRoute | undefined;\n};\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 PromptUpdateCollector {\n private readonly parts: Array<\n | { type: \"text\"; text: string }\n | { type: \"reasoning\"; text: string }\n | { type: \"tool-invocation\"; toolCallId: string; toolName: string; state: \"partial-call\" | \"call\"; args: string }\n > = [];\n private readonly toolIndex = new Map<string, number>();\n\n apply = (event: NcpEndpointEvent): void => {\n switch (event.type) {\n case NcpEventType.MessageTextDelta:\n this.appendPart(\"text\", event.payload.delta);\n return;\n case NcpEventType.MessageReasoningDelta:\n this.appendPart(\"reasoning\", event.payload.delta);\n return;\n case NcpEventType.MessageToolCallStart:\n this.upsertTool({\n toolCallId: event.payload.toolCallId,\n toolName: event.payload.toolName,\n args: \"\",\n state: \"partial-call\",\n });\n return;\n case NcpEventType.MessageToolCallArgs:\n {\n const tool = this.readTool(event.payload.toolCallId);\n this.upsertTool({\n toolCallId: event.payload.toolCallId,\n toolName: tool.toolName,\n args: event.payload.args,\n state: \"partial-call\",\n });\n }\n return;\n case NcpEventType.MessageToolCallArgsDelta:\n {\n const tool = this.readTool(event.payload.toolCallId);\n this.upsertTool({\n toolCallId: event.payload.toolCallId,\n toolName: tool.toolName,\n args: `${tool.args}${event.payload.delta}`,\n state: \"partial-call\",\n });\n }\n return;\n case NcpEventType.MessageToolCallEnd:\n {\n const tool = this.readTool(event.payload.toolCallId);\n this.upsertTool({\n toolCallId: event.payload.toolCallId,\n toolName: tool.toolName,\n args: tool.args,\n state: \"call\",\n });\n }\n return;\n default:\n return;\n }\n };\n\n hasParts = (): boolean => this.parts.length > 0;\n\n buildParts = (): Array<Record<string, unknown>> => structuredClone(this.parts);\n\n private appendPart = (type: \"text\" | \"reasoning\", text: string): void => {\n if (!text) {\n return;\n }\n const last = this.parts.at(-1);\n if (last?.type === type) {\n last.text = `${last.text}${text}`;\n return;\n }\n this.parts.push({ type, text });\n };\n\n private upsertTool = (nextTool: {\n toolCallId: string;\n toolName: string;\n args: string;\n state: \"partial-call\" | \"call\";\n }): void => {\n const existingIndex = this.toolIndex.get(nextTool.toolCallId);\n if (typeof existingIndex === \"number\") {\n const existing = this.parts[existingIndex];\n if (existing?.type !== \"tool-invocation\") {\n return;\n }\n this.parts[existingIndex] = {\n ...existing,\n ...nextTool,\n };\n return;\n }\n\n this.toolIndex.set(nextTool.toolCallId, this.parts.length);\n this.parts.push({\n type: \"tool-invocation\",\n ...nextTool,\n });\n };\n\n private readTool = (toolCallId: string): { toolName: string; args: string } => {\n const index = this.toolIndex.get(toolCallId);\n const part = typeof index === \"number\" ? this.parts[index] : null;\n if (part?.type !== \"tool-invocation\") {\n return { toolName: \"unknown\", args: \"\" };\n }\n return { toolName: part.toolName, args: part.args };\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 readonly clientBridge = new StdioRuntimeClientBridge();\n private stderr = \"\";\n private pendingProviderRoute: NcpProviderRuntimeRoute | undefined;\n\n constructor(\n private readonly config: StdioRuntimeResolvedConfig,\n private readonly sessionId: string,\n ) {}\n\n ensureStarted = async (params?: {\n providerRoute?: NcpProviderRuntimeRoute;\n }): Promise<void> => {\n this.pendingProviderRoute = params?.providerRoute;\n if (this.connection && this.remoteSessionId) {\n return;\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 for session ${this.sessionId}`,\n );\n\n return withTimeout(\n this.connection?.newSession({\n cwd: this.config.cwd ?? process.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 session for ${this.sessionId}`,\n );\n })(),\n spawnErrorPromise,\n ]);\n this.remoteSessionId = session.sessionId;\n };\n\n runPrompt = async (params: {\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, 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 ${this.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 dispose = async (): Promise<void> => {\n await this.cancel();\n const child = this.child;\n this.connection = null;\n this.remoteSessionId = null;\n this.child = null;\n if (!child || child.killed || child.exitCode !== null || child.signalCode !== null) {\n return;\n }\n\n const forceKill = setTimeout(() => {\n child.kill(\"SIGKILL\");\n }, 3_000);\n child.once(\"exit\", () => {\n clearTimeout(forceKill);\n });\n child.kill(\"SIGTERM\");\n };\n}\n\nclass StdioRuntimeRunController {\n private readonly buffer = new UpdateBuffer();\n private readonly collector = new PromptUpdateCollector();\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 private readonly stateManager?: NcpAgentConversationStateManager,\n private readonly resolveTools?: (input: NcpAgentRunInput) => ReadonlyArray<OpenAITool> | undefined,\n private readonly resolveProviderRoute?: (input: NcpAgentRunInput) => NcpProviderRuntimeRoute | undefined,\n ) {\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 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 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 if (!this.collector.hasParts()) {\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: {\n id: assistantMessageId,\n sessionId: this.input.sessionId,\n role: \"assistant\",\n status: \"final\",\n parts: this.collector.buildParts() as never,\n timestamp: new Date().toISOString(),\n },\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);\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 this.collector.apply(event);\n await this.stateManager?.dispatch(event);\n yield event;\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 default:\n return [];\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, config.sessionId);\n }\n\n run = async function* (\n this: StdioRuntimeNcpAgentRuntime,\n input: NcpAgentRunInput,\n options?: NcpAgentRunOptions,\n ): AsyncGenerator<NcpEndpointEvent> {\n await this.session.ensureStarted({\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 extractPromptText(message: { parts?: Array<{ type: string; text?: string }> }): string {\n const text = (message.parts ?? [])\n .map((part) => {\n if (part.type === \"text\" || part.type === \"reasoning\" || part.type === \"rich-text\") {\n return part.text ?? \"\";\n }\n return \"\";\n })\n .join(\"\\n\")\n .trim();\n return text.length > 0 ? text : \"[empty message]\";\n}\n\nfunction resolveModelId(params: {\n providerRoute?: NcpProviderRuntimeRoute;\n metadata?: Record<string, unknown>;\n}): string | undefined {\n const { metadata, providerRoute } = params;\n return (\n providerRoute?.model ??\n readString(metadata?.preferred_model) ??\n readString(metadata?.preferredModel) ??\n readString(metadata?.model)\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 NcpEventType,\n type NcpAgentConversationStateManager,\n type NcpAgentRunInput,\n type NcpAgentRunOptions,\n type NcpAgentRuntime,\n type NcpEndpointEvent,\n type NcpProviderRuntimeRoute,\n type OpenAITool,\n} from \"@nextclaw/ncp\";\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 PromptUpdateCollector {\n private readonly parts: Array<\n | { type: \"text\"; text: string }\n | { type: \"reasoning\"; text: string }\n | { type: \"tool-invocation\"; toolCallId: string; toolName: string; state: \"partial-call\" | \"call\"; args: string }\n > = [];\n private readonly toolIndex = new Map<string, number>();\n\n apply = (event: NcpEndpointEvent): void => {\n switch (event.type) {\n case NcpEventType.MessageTextDelta:\n this.appendPart(\"text\", event.payload.delta);\n return;\n case NcpEventType.MessageReasoningDelta:\n this.appendPart(\"reasoning\", event.payload.delta);\n return;\n case NcpEventType.MessageToolCallStart:\n this.upsertTool({\n toolCallId: event.payload.toolCallId,\n toolName: event.payload.toolName,\n args: \"\",\n state: \"partial-call\",\n });\n return;\n case NcpEventType.MessageToolCallArgs:\n {\n const tool = this.readTool(event.payload.toolCallId);\n this.upsertTool({\n toolCallId: event.payload.toolCallId,\n toolName: tool.toolName,\n args: event.payload.args,\n state: \"partial-call\",\n });\n }\n return;\n case NcpEventType.MessageToolCallArgsDelta:\n {\n const tool = this.readTool(event.payload.toolCallId);\n this.upsertTool({\n toolCallId: event.payload.toolCallId,\n toolName: tool.toolName,\n args: `${tool.args}${event.payload.delta}`,\n state: \"partial-call\",\n });\n }\n return;\n case NcpEventType.MessageToolCallEnd:\n {\n const tool = this.readTool(event.payload.toolCallId);\n this.upsertTool({\n toolCallId: event.payload.toolCallId,\n toolName: tool.toolName,\n args: tool.args,\n state: \"call\",\n });\n }\n return;\n default:\n return;\n }\n };\n\n hasParts = (): boolean => this.parts.length > 0;\n\n buildParts = (): Array<Record<string, unknown>> => structuredClone(this.parts);\n\n private appendPart = (type: \"text\" | \"reasoning\", text: string): void => {\n if (!text) {\n return;\n }\n const last = this.parts.at(-1);\n if (last?.type === type) {\n last.text = `${last.text}${text}`;\n return;\n }\n this.parts.push({ type, text });\n };\n\n private upsertTool = (nextTool: {\n toolCallId: string;\n toolName: string;\n args: string;\n state: \"partial-call\" | \"call\";\n }): void => {\n const existingIndex = this.toolIndex.get(nextTool.toolCallId);\n if (typeof existingIndex === \"number\") {\n const existing = this.parts[existingIndex];\n if (existing?.type !== \"tool-invocation\") {\n return;\n }\n this.parts[existingIndex] = {\n ...existing,\n ...nextTool,\n };\n return;\n }\n\n this.toolIndex.set(nextTool.toolCallId, this.parts.length);\n this.parts.push({\n type: \"tool-invocation\",\n ...nextTool,\n });\n };\n\n private readTool = (toolCallId: string): { toolName: string; args: string } => {\n const index = this.toolIndex.get(toolCallId);\n const part = typeof index === \"number\" ? this.parts[index] : null;\n if (part?.type !== \"tool-invocation\") {\n return { toolName: \"unknown\", args: \"\" };\n }\n return { toolName: part.toolName, args: part.args };\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 collector = new PromptUpdateCollector();\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 private readonly stateManager?: NcpAgentConversationStateManager,\n private readonly resolveTools?: (input: NcpAgentRunInput) => ReadonlyArray<OpenAITool> | undefined,\n private readonly resolveProviderRoute?: (input: NcpAgentRunInput) => NcpProviderRuntimeRoute | undefined,\n ) {\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 if (!this.collector.hasParts()) {\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: {\n id: assistantMessageId,\n sessionId: this.input.sessionId,\n role: \"assistant\",\n status: \"final\",\n parts: this.collector.buildParts() as never,\n timestamp: new Date().toISOString(),\n },\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 this.collector.apply(event);\n await this.stateManager?.dispatch(event);\n yield event;\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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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { readString } from "../stdio-runtime-config.utils.js";
|
|
2
|
+
//#region src/utils/stdio-runtime-input.utils.ts
|
|
3
|
+
function extractPromptText(message) {
|
|
4
|
+
const text = (message.parts ?? []).map((part) => {
|
|
5
|
+
if (part.type === "text" || part.type === "reasoning" || part.type === "rich-text") return part.text ?? "";
|
|
6
|
+
return "";
|
|
7
|
+
}).join("\n").trim();
|
|
8
|
+
return text.length > 0 ? text : "[empty message]";
|
|
9
|
+
}
|
|
10
|
+
function resolveModelId(params) {
|
|
11
|
+
const { metadata, providerRoute } = params;
|
|
12
|
+
const modelId = providerRoute?.model ?? readString(metadata?.preferred_model) ?? readString(metadata?.preferredModel) ?? readString(metadata?.model);
|
|
13
|
+
return modelId === "__nextclaw_runtime_default__" ? void 0 : modelId;
|
|
14
|
+
}
|
|
15
|
+
//#endregion
|
|
16
|
+
export { extractPromptText, resolveModelId };
|
|
17
|
+
|
|
18
|
+
//# sourceMappingURL=stdio-runtime-input.utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stdio-runtime-input.utils.js","names":[],"sources":["../../src/utils/stdio-runtime-input.utils.ts"],"sourcesContent":["import type { NcpProviderRuntimeRoute } from \"@nextclaw/ncp\";\nimport { readString } from \"../stdio-runtime-config.utils.js\";\n\nexport function extractPromptText(message: { parts?: Array<{ type: string; text?: string }> }): string {\n const text = (message.parts ?? [])\n .map((part) => {\n if (part.type === \"text\" || part.type === \"reasoning\" || part.type === \"rich-text\") {\n return part.text ?? \"\";\n }\n return \"\";\n })\n .join(\"\\n\")\n .trim();\n return text.length > 0 ? text : \"[empty message]\";\n}\n\nexport function resolveModelId(params: {\n providerRoute?: NcpProviderRuntimeRoute;\n metadata?: Record<string, unknown>;\n}): string | undefined {\n const { metadata, providerRoute } = params;\n const modelId =\n providerRoute?.model ??\n readString(metadata?.preferred_model) ??\n readString(metadata?.preferredModel) ??\n readString(metadata?.model);\n return modelId === \"__nextclaw_runtime_default__\" ? undefined : modelId;\n}\n"],"mappings":";;AAGA,SAAgB,kBAAkB,SAAqE;CACrG,MAAM,QAAQ,QAAQ,SAAS,EAAE,EAC9B,KAAK,SAAS;AACb,MAAI,KAAK,SAAS,UAAU,KAAK,SAAS,eAAe,KAAK,SAAS,YACrE,QAAO,KAAK,QAAQ;AAEtB,SAAO;GACP,CACD,KAAK,KAAK,CACV,MAAM;AACT,QAAO,KAAK,SAAS,IAAI,OAAO;;AAGlC,SAAgB,eAAe,QAGR;CACrB,MAAM,EAAE,UAAU,kBAAkB;CACpC,MAAM,UACJ,eAAe,SACf,WAAW,UAAU,gBAAgB,IACrC,WAAW,UAAU,eAAe,IACpC,WAAW,UAAU,MAAM;AAC7B,QAAO,YAAY,iCAAiC,KAAA,IAAY"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { NcpEventType } from "@nextclaw/ncp";
|
|
2
|
+
//#region src/utils/stdio-runtime-recovery.utils.ts
|
|
3
|
+
const SESSION_METADATA_PATCH_KIND = "session_metadata_patch";
|
|
4
|
+
function createPromptTimeoutRecoveryEvents(params) {
|
|
5
|
+
const { correlationId, error, messageId, resetKeys, runId, sessionId } = params;
|
|
6
|
+
if (!resetKeys?.length || !isPromptTimeoutError(error)) return [];
|
|
7
|
+
return [{
|
|
8
|
+
type: NcpEventType.RunMetadata,
|
|
9
|
+
payload: {
|
|
10
|
+
sessionId,
|
|
11
|
+
messageId,
|
|
12
|
+
runId,
|
|
13
|
+
...correlationId ? { correlationId } : {},
|
|
14
|
+
metadata: {
|
|
15
|
+
kind: SESSION_METADATA_PATCH_KIND,
|
|
16
|
+
sessionMetadataPatch: Object.fromEntries(resetKeys.map((key) => [key, null]))
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}];
|
|
20
|
+
}
|
|
21
|
+
function isPromptTimeoutError(error) {
|
|
22
|
+
return (error instanceof Error ? error.message : String(error)).includes("[narp-stdio] prompt timed out");
|
|
23
|
+
}
|
|
24
|
+
//#endregion
|
|
25
|
+
export { SESSION_METADATA_PATCH_KIND, createPromptTimeoutRecoveryEvents };
|
|
26
|
+
|
|
27
|
+
//# sourceMappingURL=stdio-runtime-recovery.utils.js.map
|
|
@@ -0,0 +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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nextclaw/nextclaw-ncp-runtime-stdio-client",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.14-beta.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,8 +17,8 @@
|
|
|
17
17
|
],
|
|
18
18
|
"dependencies": {
|
|
19
19
|
"@agentclientprotocol/sdk": "^0.19.0",
|
|
20
|
-
"@nextclaw/core": "0.14.
|
|
21
|
-
"@nextclaw/ncp": "0.6.
|
|
20
|
+
"@nextclaw/core": "0.14.5-beta.0",
|
|
21
|
+
"@nextclaw/ncp": "0.6.4-beta.0"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
24
|
"@types/node": "^20.17.6",
|