require("../../_virtual/_rolldown/runtime.cjs");
let _langchain_core_messages = require("@langchain/core/messages");
let _langchain_langgraph = require("@langchain/langgraph");
//#region src/agents/transformers/tool-call.ts
/**
* Returns true when `ns` belongs to the agent's own graph — i.e. it
* starts with `path` and is at most one level deeper (the agent's
* internal nodes like `tools`, `model_request`, etc.).
*
* Events from subagent subgraphs (two or more levels deeper) are
* excluded, so `run.toolCalls` / `run.middleware` only show events
* from the agent itself, not from its subagents.
*/
function isOwnEvent(ns, path) {
	if (ns.length < path.length || ns.length > path.length + 1) return false;
	for (let i = 0; i < path.length; i += 1) if (ns[i] !== path[i]) return false;
	return true;
}
/**
* Detects when a `tool-error` payload is actually a graph interrupt rather
* than a genuine tool failure.
*
* A tool that calls `interrupt()` throws a `GraphInterrupt`, whose message is
* the JSON-serialized `Interrupt[]` array. Each entry has the LangGraph
* `Interrupt` shape `{ id, value }`: a stable `id` (a hash of the checkpoint
* namespace, generated by `interrupt()` and always present during graph
* execution) plus the `value` passed to `interrupt(...)`. We require BOTH a
* string `id` and a `value` on every entry — a bare `value` is not a reliable
* discriminator, since a genuine tool error message can also be a JSON array
* of `{ value }` records (e.g. a validator emitting
* `[{ "value": "bad input", "message": "invalid" }]`). Keying off the
* interrupt `id` keeps real tool failures on the error path.
*
* An interrupt is control flow that *suspends* the run (the tool re-runs on
* resume); it is not an error, so the tool call must stay pending rather than
* have its `output` promise rejected. Any interrupt qualifies regardless of
* its `value` shape: HITL middleware interrupts (`value.type === "tool"`) and
* raw `interrupt(...)` calls from inside a tool are treated identically —
* raising an interrupt in a tool must work whether or not
* `humanInTheLoopMiddleware` is involved.
*/
function isToolInterrupt(message) {
	let parsed;
	try {
		parsed = JSON.parse(message);
	} catch {
		return false;
	}
	if (!Array.isArray(parsed) || parsed.length === 0) return false;
	return parsed.every((entry) => {
		if (entry == null || typeof entry !== "object") return false;
		const record = entry;
		return typeof record.id === "string" && "value" in record;
	});
}
/**
* Detects serialized LangChain `ToolMessage` values that can appear on
* `tool-finished.output` after crossing a protocol or serialization boundary.
*
* @example
* ```ts
* {
*   lc: 1,
*   type: "constructor",
*   id: ["langchain_core", "messages", "ToolMessage"],
*   kwargs: { content: "raw tool result", tool_call_id: "call_1" }
* }
* ```
*/
function isSerializedToolMessage(value) {
	if (value == null || typeof value !== "object") return false;
	const record = value;
	if (record.type !== "constructor" || !Array.isArray(record.id)) return false;
	return record.id[record.id.length - 1] === "ToolMessage";
}
function normalizeToolOutput(output) {
	if (_langchain_core_messages.ToolMessage.isInstance(output)) return output.content;
	if (isSerializedToolMessage(output)) return output.kwargs?.content;
	return output;
}
/**
* Creates a native transformer that correlates `tools` channel events
* into per-call {@link ToolCallStream} objects.
*
* Marked `__native: true` — projection keys land directly on the
* `GraphRunStream` instance as `run.toolCalls`.
*/
function createToolCallTransformer(path) {
	return () => {
		const toolCallsLog = _langchain_langgraph.StreamChannel.local();
		const pendingCalls = /* @__PURE__ */ new Map();
		function createToolCallEntry(callId, name, rawInput) {
			if (pendingCalls.has(callId)) return;
			const input = typeof rawInput === "string" ? JSON.parse(rawInput) : rawInput;
			let resolveOutput;
			let rejectOutput;
			let resolveStatus;
			let resolveError;
			const output = new Promise((res, rej) => {
				resolveOutput = res;
				rejectOutput = rej;
			});
			const status = new Promise((res) => {
				resolveStatus = res;
			});
			const error = new Promise((res) => {
				resolveError = res;
			});
			pendingCalls.set(callId, {
				resolveOutput,
				rejectOutput,
				resolveStatus,
				resolveError
			});
			toolCallsLog.push({
				name,
				callId,
				input,
				output,
				status,
				error
			});
		}
		return {
			__native: true,
			init: () => ({ toolCalls: toolCallsLog }),
			process(event) {
				/**
				* Only process events that are at the same depth as the agent's graph.
				*/
				if (!isOwnEvent(event.params.namespace, path)) return true;
				if (event.method === "messages") {
					const data = event.params.data;
					if (data.event === "content-block-finish") {
						const cb = data.contentBlock ?? data.content_block;
						if (cb?.type === "tool_call") createToolCallEntry(String(cb.id ?? ""), String(cb.name ?? ""), cb.args ?? cb.input);
					}
				}
				if (event.method === "tools") {
					const data = event.params.data;
					const toolCallId = data.tool_call_id;
					if (data.event === "tool-started") createToolCallEntry(toolCallId, data.tool_name ?? "unknown", data.input);
					const pending = toolCallId ? pendingCalls.get(toolCallId) : void 0;
					if (pending) {
						if (data.event === "tool-finished") {
							pending.resolveOutput(normalizeToolOutput(data.output));
							pending.resolveStatus("finished");
							pending.resolveError(void 0);
							pendingCalls.delete(toolCallId);
						} else if (data.event === "tool-error") {
							const message = data.message ?? "unknown error";
							if (isToolInterrupt(message)) return true;
							pending.rejectOutput(new Error(message));
							pending.resolveStatus("error");
							pending.resolveError(message);
							pendingCalls.delete(toolCallId);
						}
					}
				}
				return true;
			},
			finalize() {
				for (const pending of pendingCalls.values()) {
					pending.resolveStatus("finished");
					pending.resolveError(void 0);
					pending.resolveOutput(void 0);
				}
				pendingCalls.clear();
				toolCallsLog.close();
			},
			fail(err) {
				for (const pending of pendingCalls.values()) {
					pending.resolveStatus("error");
					pending.resolveError(err instanceof Error ? err.message : String(err));
					pending.rejectOutput(err);
				}
				pendingCalls.clear();
				toolCallsLog.fail(err);
			}
		};
	};
}
//#endregion
exports.createToolCallTransformer = createToolCallTransformer;

//# sourceMappingURL=tool-call.cjs.map