//#region src/client/stream/handles/tools.ts
/**
* Project a runtime handle to the client SDK surface (promise-only
* {@link output}, no {@link status} / {@link error} fields).
*/
function toClientAssembledToolCall(handle) {
	return {
		name: handle.name,
		callId: handle.callId,
		id: handle.id,
		namespace: handle.namespace,
		input: handle.input,
		args: handle.args,
		output: handle.outputPromise
	};
}
/**
* Parse wire-format tool payloads into structured values.
*
* Tool events may carry JSON-encoded object strings on the wire; this
* helper normalises them to plain objects for consumers. Non-JSON strings
* are returned unchanged.
*/
function parseToolPayload(value) {
	if (typeof value !== "string") return value;
	const trimmed = value.trim();
	if (!trimmed.startsWith("{") && !trimmed.startsWith("[")) return value;
	try {
		return JSON.parse(trimmed);
	} catch {
		return value;
	}
}
/**
* Skip wrapper `task` tool events scoped to a subagent namespace.
*
* Deep-agent subagents are discovered from root-level `task` tool calls;
* replaying the same dispatch tool inside the worker namespace would
* otherwise surface as a spurious entry in `sub.toolCalls`.
*/
function shouldIgnoreScopedTaskToolEvent(scopeNamespace, event) {
	const data = event.params.data;
	return scopeNamespace.length > 0 && event.params.namespace.length === scopeNamespace.length && event.params.namespace.every((segment, index) => segment === scopeNamespace[index]) && "tool_name" in data && data.tool_name === "task";
}
function getWireMessageField(message, field) {
	if (!message || typeof message !== "object" || Array.isArray(message)) return;
	const record = message;
	if (field in record) return record[field];
	const kwargs = record.kwargs;
	if (kwargs != null && field in kwargs) return kwargs[field];
	const lcKwargs = record.lc_kwargs;
	if (lcKwargs != null && field in lcKwargs) return lcKwargs[field];
}
function isToolMessageLike(value) {
	if (!value || typeof value !== "object") return false;
	if (value.type === "tool") return true;
	if (getWireMessageField(value, "type") === "tool") return true;
	return typeof getWireMessageField(value, "tool_call_id") === "string" && getWireMessageField(value, "content") !== void 0;
}
function isCommandLike(value) {
	return !!value && typeof value === "object" && value.lg_name === "Command";
}
function textFromContentBlocks(content) {
	let out = "";
	for (const block of content) {
		if (!block || typeof block !== "object") continue;
		const record = block;
		if (record.type === "text" && typeof record.text === "string") out += record.text;
	}
	return out;
}
/**
* Normalise tool-result `content` from a wire ToolMessage into the value
* a tool implementation returned (object, string, etc.).
*/
function parseToolResultContent(content) {
	if (content == null) return null;
	if (typeof content === "string") {
		if (content.trim().length === 0) return null;
		return parseToolPayload(content);
	}
	if (Array.isArray(content)) {
		const text = textFromContentBlocks(content);
		if (text.length === 0) return null;
		return parseToolPayload(text);
	}
	if (typeof content === "object") return content;
	return null;
}
function parseToolMessageRecord(message) {
	return parseToolResultContent(getWireMessageField(message, "content"));
}
function parseCommandToolOutput(command, toolCallId) {
	const update = command.update;
	if (update == null || typeof update !== "object" || Array.isArray(update)) return { found: false };
	const messages = update.messages;
	if (!Array.isArray(messages)) return { found: false };
	const toolMessages = messages.filter((message) => isToolMessageLike(message));
	if (toolMessages.length === 0) return { found: false };
	if (toolCallId != null) {
		for (const message of toolMessages) {
			if (getWireMessageField(message, "tool_call_id") !== toolCallId) continue;
			return {
				found: true,
				value: parseToolMessageRecord(message)
			};
		}
		return { found: false };
	}
	if (toolMessages.length === 1) return {
		found: true,
		value: parseToolMessageRecord(toolMessages[0])
	};
	for (let i = toolMessages.length - 1; i >= 0; i -= 1) {
		const parsed = parseToolMessageRecord(toolMessages[i]);
		if (parsed != null) return {
			found: true,
			value: parsed
		};
	}
	return {
		found: true,
		value: null
	};
}
/**
* Parse a `tool-finished` output payload into the tool's return value.
*
* Wire events often wrap structured tool results in a ToolMessage-shaped
* object (`{ type: "tool", content: "..." }`) or a LangGraph
* {@link Command} whose `update.messages` carries the ToolMessage.
* This unwraps those envelopes, JSON-decodes string content when possible,
* and leaves plain strings as-is. Returns `null` when a ToolMessage envelope
* is present but its content cannot be normalised.
*/
function parseToolOutput(value, toolCallId) {
	const parsed = parseToolPayload(value);
	if (isCommandLike(parsed)) {
		const commandOutput = parseCommandToolOutput(parsed, toolCallId);
		return commandOutput.found ? commandOutput.value : parsed;
	}
	if (isToolMessageLike(parsed)) return parseToolResultContent(getWireMessageField(parsed, "content"));
	return parsed ?? null;
}
/**
* Incrementally assembles `tools` events into mutable tool-call handles.
*
* Framework consumers store the handle directly; client SDK consumers
* should map with {@link toClientAssembledToolCall} before yielding.
*/
var ToolCallAssembler = class {
	active = /* @__PURE__ */ new Map();
	consume(event) {
		const data = event.params.data;
		if (data.event === "tool-started") return this.handleStarted(event, data);
		if (data.event === "tool-finished") return this.handleFinished(data);
		if (data.event === "tool-error") return this.handleError(data);
	}
	/**
	* Reject any in-flight tool calls (e.g. on session close).
	*/
	failAll(reason) {
		for (const entry of this.active.values()) {
			entry.rejectOutput(reason);
			entry.handle.status = "error";
			entry.handle.error = reason.message;
		}
		this.active.clear();
	}
	handleStarted(event, data) {
		let resolveOutput;
		let rejectOutput;
		const outputPromise = new Promise((resolve, reject) => {
			resolveOutput = resolve;
			rejectOutput = reject;
		});
		outputPromise.catch(() => void 0);
		const input = parseToolPayload(data.input);
		const name = data.tool_name;
		const callId = data.tool_call_id;
		const handle = {
			name,
			callId,
			id: callId,
			namespace: [...event.params.namespace],
			input,
			args: input,
			output: null,
			status: "running",
			error: void 0,
			outputPromise
		};
		this.active.set(callId, {
			handle,
			resolveOutput,
			rejectOutput
		});
		return handle;
	}
	handleFinished(data) {
		const entry = this.active.get(data.tool_call_id);
		if (!entry) return void 0;
		this.active.delete(data.tool_call_id);
		const value = parseToolOutput(data.output, data.tool_call_id);
		entry.resolveOutput(value);
		entry.handle.output = value;
		entry.handle.status = "finished";
		entry.handle.error = void 0;
		return entry.handle;
	}
	handleError(data) {
		const entry = this.active.get(data.tool_call_id);
		if (!entry) return void 0;
		this.active.delete(data.tool_call_id);
		entry.rejectOutput(new Error(data.message));
		entry.handle.output = null;
		entry.handle.status = "error";
		entry.handle.error = data.message;
		return entry.handle;
	}
};
//#endregion
export { ToolCallAssembler, parseToolOutput, parseToolPayload, shouldIgnoreScopedTaskToolEvent, toClientAssembledToolCall };

//# sourceMappingURL=tools.js.map