const require_helpers = require('./helpers.cjs');
const require_router = require('./router.cjs');
const require_sse_writer = require('./sse-writer.cjs');
const require_interruption = require('./interruption.cjs');
const require_chaos = require('./chaos.cjs');
const require_recorder = require('./recorder.cjs');
const require_aws_event_stream = require('./aws-event-stream.cjs');

//#region src/bedrock.ts
function bedrockStopReason(overrideFinishReason, defaultReason) {
	if (!overrideFinishReason) return defaultReason;
	if (overrideFinishReason === "stop") return "end_turn";
	if (overrideFinishReason === "tool_calls") return "tool_use";
	if (overrideFinishReason === "length") return "max_tokens";
	return overrideFinishReason;
}
/**
* Build a Bedrock-style usage object from optional overrides.
*
* When no overrides are provided (the common case for mock fixtures),
* returns all-zero token counts. This is intentional — aimock does not
* attempt to estimate token usage from fixture content. Callers that
* need realistic usage numbers should set `usage` in their fixture's
* response overrides.
*/
function bedrockUsage(overrides) {
	if (!overrides?.usage) return {
		input_tokens: 0,
		output_tokens: 0
	};
	return {
		input_tokens: overrides.usage.input_tokens ?? overrides.usage.prompt_tokens ?? 0,
		output_tokens: overrides.usage.output_tokens ?? overrides.usage.completion_tokens ?? 0
	};
}
function extractTextContent(content) {
	if (typeof content === "string") return content;
	return content.filter((b) => b.type === "text").map((b) => b.text ?? "").join("");
}
function bedrockToCompletionRequest(req, modelId, logger) {
	const messages = [];
	if (req.system) {
		const systemText = typeof req.system === "string" ? req.system : req.system.filter((b) => b.type === "text").map((b) => b.text ?? "").join("");
		if (systemText) messages.push({
			role: "system",
			content: systemText
		});
	}
	for (const msg of req.messages) if (msg.role === "user") {
		if (typeof msg.content !== "string" && Array.isArray(msg.content)) {
			const unsupportedBlocks = msg.content.filter((b) => b.type !== "text" && b.type !== "tool_result");
			if (unsupportedBlocks.length > 0 && logger) {
				const types = [...new Set(unsupportedBlocks.map((b) => b.type))].join(", ");
				logger.warn(`Bedrock user message contains unsupported content block types [${types}] — these will be dropped during conversion`);
			}
			const toolResults = msg.content.filter((b) => b.type === "tool_result");
			const textBlocks = msg.content.filter((b) => b.type === "text");
			if (toolResults.length > 0) {
				for (const tr of toolResults) {
					const resultContent = typeof tr.content === "string" ? tr.content : Array.isArray(tr.content) ? tr.content.filter((b) => b.type === "text").map((b) => b.text ?? "").join("") : "";
					messages.push({
						role: "tool",
						content: resultContent,
						tool_call_id: tr.tool_use_id
					});
				}
				if (textBlocks.length > 0) messages.push({
					role: "user",
					content: textBlocks.map((b) => b.text ?? "").join("")
				});
				continue;
			}
		}
		messages.push({
			role: "user",
			content: extractTextContent(msg.content)
		});
	} else if (msg.role === "assistant") if (typeof msg.content === "string") messages.push({
		role: "assistant",
		content: msg.content
	});
	else if (Array.isArray(msg.content)) {
		const toolUseBlocks = msg.content.filter((b) => b.type === "tool_use");
		const textContent = extractTextContent(msg.content);
		if (toolUseBlocks.length > 0) messages.push({
			role: "assistant",
			content: textContent || null,
			tool_calls: toolUseBlocks.map((b, index) => {
				if (!b.id && logger) logger.warn(`Bedrock assistant tool_use block at index ${index} is missing an id — using deterministic fallback "tool_use_${index}"`);
				return {
					id: b.id ?? `tool_use_${index}`,
					type: "function",
					function: {
						name: b.name ?? "",
						arguments: typeof b.input === "string" ? b.input : JSON.stringify(b.input ?? {})
					}
				};
			})
		});
		else messages.push({
			role: "assistant",
			content: textContent || null
		});
	} else messages.push({
		role: "assistant",
		content: null
	});
	else if (logger) logger.warn(`Bedrock message has unexpected role "${msg.role}" — skipping`);
	let tools;
	if (req.tools && req.tools.length > 0) tools = req.tools.map((t) => ({
		type: "function",
		function: {
			name: t.name,
			description: t.description,
			parameters: t.input_schema
		}
	}));
	return {
		model: modelId,
		messages,
		stream: false,
		temperature: req.temperature,
		max_tokens: req.max_tokens,
		tools
	};
}
function buildBedrockTextResponse(content, model, reasoning, overrides) {
	const contentBlocks = [];
	if (reasoning) contentBlocks.push({
		type: "thinking",
		thinking: reasoning,
		signature: ""
	});
	contentBlocks.push({
		type: "text",
		text: content
	});
	return {
		id: overrides?.id ?? require_helpers.generateMessageId(),
		type: "message",
		role: "assistant",
		content: contentBlocks,
		model: overrides?.model ?? model,
		stop_reason: bedrockStopReason(overrides?.finishReason, "end_turn"),
		stop_sequence: null,
		usage: bedrockUsage(overrides)
	};
}
function buildBedrockToolCallResponse(toolCalls, model, logger, reasoning, overrides) {
	const contentBlocks = [];
	if (reasoning) contentBlocks.push({
		type: "thinking",
		thinking: reasoning,
		signature: ""
	});
	for (const tc of toolCalls) {
		let argsObj;
		try {
			argsObj = JSON.parse(tc.arguments || "{}");
		} catch {
			logger.warn(`Malformed JSON in fixture tool call arguments for "${tc.name}": ${tc.arguments}`);
			argsObj = {};
		}
		contentBlocks.push({
			type: "tool_use",
			id: tc.id || require_helpers.generateToolUseId(),
			name: tc.name,
			input: argsObj
		});
	}
	return {
		id: overrides?.id ?? require_helpers.generateMessageId(),
		type: "message",
		role: "assistant",
		content: contentBlocks,
		model: overrides?.model ?? model,
		stop_reason: bedrockStopReason(overrides?.finishReason, "tool_use"),
		stop_sequence: null,
		usage: bedrockUsage(overrides)
	};
}
/**
* Build a Bedrock-invoke (Anthropic-style) non-streaming response whose
* `content[]` array honors the fixture's ordered `blocks`. Bedrock-invoke
* mirrors the Anthropic Messages content array, which is positionally
* observable, so a `toolCall` block ahead of a `text` block yields a `tool_use`
* content entry ahead of the `text` entry (tool-first is wire-expressible).
*
* Any leading thinking block (when reasoning is present) precedes the ordered
* blocks, matching the legacy builders. Reached only when `blocks` is non-empty;
* the legacy `{content, toolCalls}` text-first path is untouched.
*/
function buildBedrockBlocksResponse(blocks, model, logger, reasoning, overrides) {
	const contentBlocks = [];
	if (reasoning) contentBlocks.push({
		type: "thinking",
		thinking: reasoning,
		signature: ""
	});
	const ordered = require_helpers.resolveFixtureBlocks(blocks);
	for (const block of ordered) if (block.type === "text") contentBlocks.push({
		type: "text",
		text: block.text
	});
	else {
		let argsObj;
		try {
			argsObj = JSON.parse(block.arguments || "{}");
		} catch {
			logger.warn(`Malformed JSON in fixture tool call arguments for "${block.name}": ${block.arguments}`);
			argsObj = {};
		}
		contentBlocks.push({
			type: "tool_use",
			id: block.id || require_helpers.generateToolUseId(),
			name: block.name,
			input: argsObj
		});
	}
	return {
		id: overrides?.id ?? require_helpers.generateMessageId(),
		type: "message",
		role: "assistant",
		content: contentBlocks,
		model: overrides?.model ?? model,
		stop_reason: bedrockStopReason(overrides?.finishReason, "tool_use"),
		stop_sequence: null,
		usage: bedrockUsage(overrides)
	};
}
async function handleBedrock(req, res, raw, modelId, fixtures, journal, defaults, setCorsHeaders) {
	const { logger } = defaults;
	setCorsHeaders(res);
	const urlPath = req.url ?? `/model/${modelId}/invoke`;
	let bedrockReq;
	try {
		bedrockReq = JSON.parse(raw);
	} catch (parseErr) {
		const detail = parseErr instanceof Error ? parseErr.message : "unknown";
		journal.add({
			method: req.method ?? "POST",
			path: urlPath,
			headers: require_helpers.flattenHeaders(req.headers),
			body: null,
			response: {
				status: 400,
				fixture: null
			}
		});
		require_sse_writer.writeErrorResponse(res, 400, JSON.stringify({ error: {
			message: `Malformed JSON: ${detail}`,
			type: "invalid_request_error"
		} }));
		return;
	}
	if (!bedrockReq.messages || !Array.isArray(bedrockReq.messages)) {
		journal.add({
			method: req.method ?? "POST",
			path: urlPath,
			headers: require_helpers.flattenHeaders(req.headers),
			body: null,
			response: {
				status: 400,
				fixture: null
			}
		});
		require_sse_writer.writeErrorResponse(res, 400, JSON.stringify({ error: {
			message: "Invalid request: messages array is required",
			type: "invalid_request_error"
		} }));
		return;
	}
	const completionReq = bedrockToCompletionRequest(bedrockReq, modelId, logger);
	completionReq._endpointType = "chat";
	completionReq._context = require_helpers.getContext(req);
	const testId = require_helpers.getTestId(req);
	const { fixture, skippedBySequenceOrTurn } = require_router.matchFixtureDiagnostic(fixtures, completionReq, journal.getFixtureMatchCountsForTest(testId), defaults.requestTransform, require_router.recordMatchOptions(!!defaults.record, defaults.logger));
	if (fixture) logger.debug(`Fixture matched: ${JSON.stringify(fixture.match).slice(0, 120)}`);
	else logger.debug(`No fixture matched for request`);
	if (fixture) journal.incrementFixtureMatchCount(fixture, fixtures, testId);
	if (require_chaos.applyChaos(res, fixture, defaults.chaos, req.headers, journal, {
		method: req.method ?? "POST",
		path: urlPath,
		headers: require_helpers.flattenHeaders(req.headers),
		body: completionReq
	}, fixture ? "fixture" : "proxy", defaults.registry, defaults.logger)) return;
	if (!fixture) {
		if (require_helpers.resolveStrictMode(defaults.strict, req.headers)) {
			const strictStatus = 503;
			const strictMessage = require_helpers.strictNoMatchMessage(skippedBySequenceOrTurn);
			logger.error(require_helpers.strictNoMatchLogLine(req.method ?? "POST", urlPath, skippedBySequenceOrTurn));
			journal.add({
				method: req.method ?? "POST",
				path: urlPath,
				headers: require_helpers.flattenHeaders(req.headers),
				body: completionReq,
				response: {
					status: strictStatus,
					fixture: null,
					...require_helpers.strictOverrideField(defaults.strict, req.headers)
				}
			});
			require_sse_writer.writeErrorResponse(res, strictStatus, JSON.stringify({ error: {
				message: strictMessage,
				type: "invalid_request_error"
			} }));
			return;
		}
		if (defaults.record) {
			const outcome = await require_recorder.proxyAndRecord(req, res, completionReq, "bedrock", urlPath, fixtures, defaults, raw);
			if (outcome === "handled_by_hook") return;
			if (outcome !== "not_configured") {
				journal.add({
					method: req.method ?? "POST",
					path: urlPath,
					headers: require_helpers.flattenHeaders(req.headers),
					body: completionReq,
					response: {
						status: res.statusCode ?? 200,
						fixture: null,
						source: "proxy"
					}
				});
				return;
			}
		}
		journal.add({
			method: req.method ?? "POST",
			path: urlPath,
			headers: require_helpers.flattenHeaders(req.headers),
			body: completionReq,
			response: {
				status: 404,
				fixture: null,
				...require_helpers.strictOverrideField(defaults.strict, req.headers)
			}
		});
		require_sse_writer.writeErrorResponse(res, 404, JSON.stringify({ error: {
			message: "No fixture matched",
			type: "invalid_request_error"
		} }));
		return;
	}
	const response = await require_helpers.resolveResponse(fixture, completionReq);
	if (require_helpers.isErrorResponse(response)) {
		const status = response.status ?? 500;
		journal.add({
			method: req.method ?? "POST",
			path: urlPath,
			headers: require_helpers.flattenHeaders(req.headers),
			body: completionReq,
			response: {
				status,
				fixture
			}
		});
		const anthropicError = {
			type: "error",
			error: {
				type: response.error.type ?? "api_error",
				message: response.error.message
			}
		};
		require_sse_writer.writeErrorResponse(res, status, JSON.stringify(anthropicError), { retryAfter: response.retryAfter });
		return;
	}
	if (require_helpers.isContentWithToolCallsResponse(response)) {
		if (response.webSearches?.length) logger.warn("webSearches in fixture response are not supported for Bedrock API — ignoring");
		const overrides = require_helpers.extractOverrides(response);
		const effReasoning = require_helpers.resolveReasoningForModel(response.reasoning, completionReq.model, require_helpers.resolveStrictMode(defaults.strict, req.headers), logger);
		journal.add({
			method: req.method ?? "POST",
			path: urlPath,
			headers: require_helpers.flattenHeaders(req.headers),
			body: completionReq,
			response: {
				status: 200,
				fixture
			}
		});
		if (response.blocks && response.blocks.length > 0) {
			const blocksBody = buildBedrockBlocksResponse(response.blocks, completionReq.model, logger, effReasoning, overrides);
			res.writeHead(200, { "Content-Type": "application/json" });
			res.end(JSON.stringify(blocksBody));
			return;
		}
		const textBody = buildBedrockTextResponse(response.content ?? "", completionReq.model, effReasoning, overrides);
		const toolBody = buildBedrockToolCallResponse(response.toolCalls ?? [], completionReq.model, logger, void 0, overrides);
		const merged = {
			...textBody,
			content: [...textBody.content, ...toolBody.content],
			stop_reason: bedrockStopReason(overrides?.finishReason, "tool_use")
		};
		res.writeHead(200, { "Content-Type": "application/json" });
		res.end(JSON.stringify(merged));
		return;
	}
	if (require_helpers.isTextResponse(response)) {
		if (response.webSearches?.length) logger.warn("webSearches in fixture response are not supported for Bedrock API — ignoring");
		const overrides = require_helpers.extractOverrides(response);
		const effReasoning = require_helpers.resolveReasoningForModel(response.reasoning, completionReq.model, require_helpers.resolveStrictMode(defaults.strict, req.headers), logger);
		journal.add({
			method: req.method ?? "POST",
			path: urlPath,
			headers: require_helpers.flattenHeaders(req.headers),
			body: completionReq,
			response: {
				status: 200,
				fixture
			}
		});
		const body = buildBedrockTextResponse(response.content, completionReq.model, effReasoning, overrides);
		res.writeHead(200, { "Content-Type": "application/json" });
		res.end(JSON.stringify(body));
		return;
	}
	if (require_helpers.isToolCallResponse(response)) {
		if (response.webSearches?.length) logger.warn("webSearches in fixture response are not supported for Bedrock API — ignoring");
		const overrides = require_helpers.extractOverrides(response);
		const effReasoning = require_helpers.resolveReasoningForModel(response.reasoning, completionReq.model, require_helpers.resolveStrictMode(defaults.strict, req.headers), logger);
		journal.add({
			method: req.method ?? "POST",
			path: urlPath,
			headers: require_helpers.flattenHeaders(req.headers),
			body: completionReq,
			response: {
				status: 200,
				fixture
			}
		});
		const body = buildBedrockToolCallResponse(response.toolCalls, completionReq.model, logger, effReasoning, overrides);
		res.writeHead(200, { "Content-Type": "application/json" });
		res.end(JSON.stringify(body));
		return;
	}
	journal.add({
		method: req.method ?? "POST",
		path: urlPath,
		headers: require_helpers.flattenHeaders(req.headers),
		body: completionReq,
		response: {
			status: 500,
			fixture
		}
	});
	require_sse_writer.writeErrorResponse(res, 500, JSON.stringify({ error: {
		message: "Fixture response did not match any known type",
		type: "server_error"
	} }));
}
const BEDROCK_INVOKE_STREAM_EVENT_TYPE = "chunk";
function buildBedrockInvokeMessageStart(model, overrides) {
	return {
		eventType: BEDROCK_INVOKE_STREAM_EVENT_TYPE,
		payload: {
			type: "message_start",
			message: {
				id: overrides?.id ?? require_helpers.generateMessageId(),
				type: "message",
				role: "assistant",
				content: [],
				model: overrides?.model ?? model,
				stop_reason: null,
				stop_sequence: null,
				usage: bedrockUsage(overrides)
			}
		}
	};
}
function buildBedrockInvokeMessageDelta(stopReason) {
	return {
		eventType: BEDROCK_INVOKE_STREAM_EVENT_TYPE,
		payload: {
			type: "message_delta",
			delta: {
				stop_reason: stopReason,
				stop_sequence: null
			},
			usage: { output_tokens: 0 }
		}
	};
}
function buildBedrockInvokeMessageStop() {
	return {
		eventType: BEDROCK_INVOKE_STREAM_EVENT_TYPE,
		payload: { type: "message_stop" }
	};
}
function parseToolArgumentsForStream(toolCall, logger) {
	try {
		const parsed = JSON.parse(toolCall.arguments || "{}");
		return JSON.stringify(parsed);
	} catch {
		logger.warn(`Malformed JSON in fixture tool call arguments for "${toolCall.name}": ${toolCall.arguments}`);
		return "{}";
	}
}
function buildBedrockStreamTextEvents(content, model, chunkSize, reasoning, overrides) {
	const events = [];
	events.push(buildBedrockInvokeMessageStart(model, overrides));
	if (reasoning) {
		const blockIndex = 0;
		events.push({
			eventType: BEDROCK_INVOKE_STREAM_EVENT_TYPE,
			payload: {
				type: "content_block_start",
				index: blockIndex,
				content_block: {
					type: "thinking",
					thinking: "",
					signature: ""
				}
			}
		});
		for (let i = 0; i < reasoning.length; i += chunkSize) {
			const slice = reasoning.slice(i, i + chunkSize);
			events.push({
				eventType: BEDROCK_INVOKE_STREAM_EVENT_TYPE,
				payload: {
					type: "content_block_delta",
					index: blockIndex,
					delta: {
						type: "thinking_delta",
						thinking: slice
					}
				}
			});
		}
		events.push({
			eventType: BEDROCK_INVOKE_STREAM_EVENT_TYPE,
			payload: {
				type: "content_block_delta",
				index: blockIndex,
				delta: {
					type: "signature_delta",
					signature: ""
				}
			}
		});
		events.push({
			eventType: BEDROCK_INVOKE_STREAM_EVENT_TYPE,
			payload: {
				type: "content_block_stop",
				index: blockIndex
			}
		});
	}
	const textBlockIndex = reasoning ? 1 : 0;
	events.push({
		eventType: BEDROCK_INVOKE_STREAM_EVENT_TYPE,
		payload: {
			type: "content_block_start",
			index: textBlockIndex,
			content_block: {
				type: "text",
				text: ""
			}
		}
	});
	for (let i = 0; i < content.length; i += chunkSize) {
		const slice = content.slice(i, i + chunkSize);
		events.push({
			eventType: BEDROCK_INVOKE_STREAM_EVENT_TYPE,
			payload: {
				type: "content_block_delta",
				index: textBlockIndex,
				delta: {
					type: "text_delta",
					text: slice
				}
			}
		});
	}
	events.push({
		eventType: BEDROCK_INVOKE_STREAM_EVENT_TYPE,
		payload: {
			type: "content_block_stop",
			index: textBlockIndex
		}
	});
	events.push(buildBedrockInvokeMessageDelta(bedrockStopReason(overrides?.finishReason, "end_turn")));
	events.push(buildBedrockInvokeMessageStop());
	return events;
}
function buildBedrockStreamContentWithToolCallsEvents(content, toolCalls, model, chunkSize, logger, reasoning, overrides, blocks) {
	const events = [];
	events.push(buildBedrockInvokeMessageStart(model, overrides));
	let blockIndex = 0;
	if (reasoning) {
		events.push({
			eventType: BEDROCK_INVOKE_STREAM_EVENT_TYPE,
			payload: {
				type: "content_block_start",
				index: blockIndex,
				content_block: {
					type: "thinking",
					thinking: "",
					signature: ""
				}
			}
		});
		for (let i = 0; i < reasoning.length; i += chunkSize) {
			const slice = reasoning.slice(i, i + chunkSize);
			events.push({
				eventType: BEDROCK_INVOKE_STREAM_EVENT_TYPE,
				payload: {
					type: "content_block_delta",
					index: blockIndex,
					delta: {
						type: "thinking_delta",
						thinking: slice
					}
				}
			});
		}
		events.push({
			eventType: BEDROCK_INVOKE_STREAM_EVENT_TYPE,
			payload: {
				type: "content_block_delta",
				index: blockIndex,
				delta: {
					type: "signature_delta",
					signature: ""
				}
			}
		});
		events.push({
			eventType: BEDROCK_INVOKE_STREAM_EVENT_TYPE,
			payload: {
				type: "content_block_stop",
				index: blockIndex
			}
		});
		blockIndex++;
	}
	if (blocks && blocks.length > 0) {
		const ordered = require_helpers.resolveFixtureBlocks(blocks);
		for (const block of ordered) if (block.type === "text") {
			events.push({
				eventType: BEDROCK_INVOKE_STREAM_EVENT_TYPE,
				payload: {
					type: "content_block_start",
					index: blockIndex,
					content_block: {
						type: "text",
						text: ""
					}
				}
			});
			for (let i = 0; i < block.text.length; i += chunkSize) {
				const slice = block.text.slice(i, i + chunkSize);
				events.push({
					eventType: BEDROCK_INVOKE_STREAM_EVENT_TYPE,
					payload: {
						type: "content_block_delta",
						index: blockIndex,
						delta: {
							type: "text_delta",
							text: slice
						}
					}
				});
			}
			events.push({
				eventType: BEDROCK_INVOKE_STREAM_EVENT_TYPE,
				payload: {
					type: "content_block_stop",
					index: blockIndex
				}
			});
			blockIndex++;
		} else {
			const toolUseId = block.id || require_helpers.generateToolUseId();
			events.push({
				eventType: BEDROCK_INVOKE_STREAM_EVENT_TYPE,
				payload: {
					type: "content_block_start",
					index: blockIndex,
					content_block: {
						type: "tool_use",
						id: toolUseId,
						name: block.name,
						input: {}
					}
				}
			});
			const argsStr = parseToolArgumentsForStream({
				name: block.name,
				arguments: block.arguments
			}, logger);
			for (let i = 0; i < argsStr.length; i += chunkSize) {
				const slice = argsStr.slice(i, i + chunkSize);
				events.push({
					eventType: BEDROCK_INVOKE_STREAM_EVENT_TYPE,
					payload: {
						type: "content_block_delta",
						index: blockIndex,
						delta: {
							type: "input_json_delta",
							partial_json: slice
						}
					}
				});
			}
			events.push({
				eventType: BEDROCK_INVOKE_STREAM_EVENT_TYPE,
				payload: {
					type: "content_block_stop",
					index: blockIndex
				}
			});
			blockIndex++;
		}
		events.push(buildBedrockInvokeMessageDelta(bedrockStopReason(overrides?.finishReason, "tool_use")));
		events.push(buildBedrockInvokeMessageStop());
		return events;
	}
	events.push({
		eventType: BEDROCK_INVOKE_STREAM_EVENT_TYPE,
		payload: {
			type: "content_block_start",
			index: blockIndex,
			content_block: {
				type: "text",
				text: ""
			}
		}
	});
	for (let i = 0; i < content.length; i += chunkSize) {
		const slice = content.slice(i, i + chunkSize);
		events.push({
			eventType: BEDROCK_INVOKE_STREAM_EVENT_TYPE,
			payload: {
				type: "content_block_delta",
				index: blockIndex,
				delta: {
					type: "text_delta",
					text: slice
				}
			}
		});
	}
	events.push({
		eventType: BEDROCK_INVOKE_STREAM_EVENT_TYPE,
		payload: {
			type: "content_block_stop",
			index: blockIndex
		}
	});
	blockIndex++;
	for (let tcIdx = 0; tcIdx < toolCalls.length; tcIdx++) {
		const tc = toolCalls[tcIdx];
		const toolUseId = tc.id || require_helpers.generateToolUseId();
		const currentBlock = blockIndex + tcIdx;
		events.push({
			eventType: BEDROCK_INVOKE_STREAM_EVENT_TYPE,
			payload: {
				type: "content_block_start",
				index: currentBlock,
				content_block: {
					type: "tool_use",
					id: toolUseId,
					name: tc.name,
					input: {}
				}
			}
		});
		const argsStr = parseToolArgumentsForStream(tc, logger);
		for (let i = 0; i < argsStr.length; i += chunkSize) {
			const slice = argsStr.slice(i, i + chunkSize);
			events.push({
				eventType: BEDROCK_INVOKE_STREAM_EVENT_TYPE,
				payload: {
					type: "content_block_delta",
					index: currentBlock,
					delta: {
						type: "input_json_delta",
						partial_json: slice
					}
				}
			});
		}
		events.push({
			eventType: BEDROCK_INVOKE_STREAM_EVENT_TYPE,
			payload: {
				type: "content_block_stop",
				index: currentBlock
			}
		});
	}
	events.push(buildBedrockInvokeMessageDelta(bedrockStopReason(overrides?.finishReason, "tool_use")));
	events.push(buildBedrockInvokeMessageStop());
	return events;
}
function buildBedrockStreamToolCallEvents(toolCalls, model, chunkSize, logger, reasoning, overrides) {
	const events = [];
	events.push(buildBedrockInvokeMessageStart(model, overrides));
	let blockIndex = 0;
	if (reasoning) {
		events.push({
			eventType: BEDROCK_INVOKE_STREAM_EVENT_TYPE,
			payload: {
				type: "content_block_start",
				index: blockIndex,
				content_block: {
					type: "thinking",
					thinking: "",
					signature: ""
				}
			}
		});
		for (let i = 0; i < reasoning.length; i += chunkSize) {
			const slice = reasoning.slice(i, i + chunkSize);
			events.push({
				eventType: BEDROCK_INVOKE_STREAM_EVENT_TYPE,
				payload: {
					type: "content_block_delta",
					index: blockIndex,
					delta: {
						type: "thinking_delta",
						thinking: slice
					}
				}
			});
		}
		events.push({
			eventType: BEDROCK_INVOKE_STREAM_EVENT_TYPE,
			payload: {
				type: "content_block_delta",
				index: blockIndex,
				delta: {
					type: "signature_delta",
					signature: ""
				}
			}
		});
		events.push({
			eventType: BEDROCK_INVOKE_STREAM_EVENT_TYPE,
			payload: {
				type: "content_block_stop",
				index: blockIndex
			}
		});
		blockIndex++;
	}
	for (let tcIdx = 0; tcIdx < toolCalls.length; tcIdx++) {
		const tc = toolCalls[tcIdx];
		const toolUseId = tc.id || require_helpers.generateToolUseId();
		const currentBlock = blockIndex + tcIdx;
		events.push({
			eventType: BEDROCK_INVOKE_STREAM_EVENT_TYPE,
			payload: {
				type: "content_block_start",
				index: currentBlock,
				content_block: {
					type: "tool_use",
					id: toolUseId,
					name: tc.name,
					input: {}
				}
			}
		});
		const argsStr = parseToolArgumentsForStream(tc, logger);
		for (let i = 0; i < argsStr.length; i += chunkSize) {
			const slice = argsStr.slice(i, i + chunkSize);
			events.push({
				eventType: BEDROCK_INVOKE_STREAM_EVENT_TYPE,
				payload: {
					type: "content_block_delta",
					index: currentBlock,
					delta: {
						type: "input_json_delta",
						partial_json: slice
					}
				}
			});
		}
		events.push({
			eventType: BEDROCK_INVOKE_STREAM_EVENT_TYPE,
			payload: {
				type: "content_block_stop",
				index: currentBlock
			}
		});
	}
	events.push(buildBedrockInvokeMessageDelta(bedrockStopReason(overrides?.finishReason, "tool_use")));
	events.push(buildBedrockInvokeMessageStop());
	return events;
}
async function handleBedrockStream(req, res, raw, modelId, fixtures, journal, defaults, setCorsHeaders) {
	const { logger } = defaults;
	setCorsHeaders(res);
	const urlPath = req.url ?? `/model/${modelId}/invoke-with-response-stream`;
	let bedrockReq;
	try {
		bedrockReq = JSON.parse(raw);
	} catch (parseErr) {
		const detail = parseErr instanceof Error ? parseErr.message : "unknown";
		journal.add({
			method: req.method ?? "POST",
			path: urlPath,
			headers: require_helpers.flattenHeaders(req.headers),
			body: null,
			response: {
				status: 400,
				fixture: null
			}
		});
		require_sse_writer.writeErrorResponse(res, 400, JSON.stringify({ error: {
			message: `Malformed JSON: ${detail}`,
			type: "invalid_request_error"
		} }));
		return;
	}
	if (!bedrockReq.messages || !Array.isArray(bedrockReq.messages)) {
		journal.add({
			method: req.method ?? "POST",
			path: urlPath,
			headers: require_helpers.flattenHeaders(req.headers),
			body: null,
			response: {
				status: 400,
				fixture: null
			}
		});
		require_sse_writer.writeErrorResponse(res, 400, JSON.stringify({ error: {
			message: "Invalid request: messages array is required",
			type: "invalid_request_error"
		} }));
		return;
	}
	const completionReq = bedrockToCompletionRequest(bedrockReq, modelId, logger);
	completionReq.stream = true;
	completionReq._endpointType = "chat";
	completionReq._context = require_helpers.getContext(req);
	const testId = require_helpers.getTestId(req);
	const { fixture, skippedBySequenceOrTurn } = require_router.matchFixtureDiagnostic(fixtures, completionReq, journal.getFixtureMatchCountsForTest(testId), defaults.requestTransform, require_router.recordMatchOptions(!!defaults.record, defaults.logger));
	if (fixture) logger.debug(`Fixture matched: ${JSON.stringify(fixture.match).slice(0, 120)}`);
	else logger.debug(`No fixture matched for request`);
	if (fixture) journal.incrementFixtureMatchCount(fixture, fixtures, testId);
	if (require_chaos.applyChaos(res, fixture, defaults.chaos, req.headers, journal, {
		method: req.method ?? "POST",
		path: urlPath,
		headers: require_helpers.flattenHeaders(req.headers),
		body: completionReq
	}, fixture ? "fixture" : "proxy", defaults.registry, defaults.logger)) return;
	if (!fixture) {
		if (require_helpers.resolveStrictMode(defaults.strict, req.headers)) {
			const strictStatus = 503;
			const strictMessage = require_helpers.strictNoMatchMessage(skippedBySequenceOrTurn);
			logger.error(require_helpers.strictNoMatchLogLine(req.method ?? "POST", urlPath, skippedBySequenceOrTurn));
			journal.add({
				method: req.method ?? "POST",
				path: urlPath,
				headers: require_helpers.flattenHeaders(req.headers),
				body: completionReq,
				response: {
					status: strictStatus,
					fixture: null,
					...require_helpers.strictOverrideField(defaults.strict, req.headers)
				}
			});
			require_sse_writer.writeErrorResponse(res, strictStatus, JSON.stringify({ error: {
				message: strictMessage,
				type: "invalid_request_error"
			} }));
			return;
		}
		if (defaults.record) {
			const outcome = await require_recorder.proxyAndRecord(req, res, completionReq, "bedrock", urlPath, fixtures, defaults, raw);
			if (outcome === "handled_by_hook") return;
			if (outcome !== "not_configured") {
				journal.add({
					method: req.method ?? "POST",
					path: urlPath,
					headers: require_helpers.flattenHeaders(req.headers),
					body: completionReq,
					response: {
						status: res.statusCode ?? 200,
						fixture: null,
						source: "proxy"
					}
				});
				return;
			}
		}
		journal.add({
			method: req.method ?? "POST",
			path: urlPath,
			headers: require_helpers.flattenHeaders(req.headers),
			body: completionReq,
			response: {
				status: 404,
				fixture: null,
				...require_helpers.strictOverrideField(defaults.strict, req.headers)
			}
		});
		require_sse_writer.writeErrorResponse(res, 404, JSON.stringify({ error: {
			message: "No fixture matched",
			type: "invalid_request_error"
		} }));
		return;
	}
	const response = await require_helpers.resolveResponse(fixture, completionReq);
	const latency = fixture.latency ?? defaults.latency;
	const chunkSize = Math.max(1, fixture.chunkSize ?? defaults.chunkSize);
	if (require_helpers.isErrorResponse(response)) {
		const status = response.status ?? 500;
		journal.add({
			method: req.method ?? "POST",
			path: urlPath,
			headers: require_helpers.flattenHeaders(req.headers),
			body: completionReq,
			response: {
				status,
				fixture
			}
		});
		const anthropicError = {
			type: "error",
			error: {
				type: response.error.type ?? "api_error",
				message: response.error.message
			}
		};
		require_sse_writer.writeErrorResponse(res, status, JSON.stringify(anthropicError), { retryAfter: response.retryAfter });
		return;
	}
	if (require_helpers.isContentWithToolCallsResponse(response)) {
		if (response.webSearches?.length) logger.warn("webSearches in fixture response are not supported for Bedrock API — ignoring");
		const overrides = require_helpers.extractOverrides(response);
		const effReasoning = require_helpers.resolveReasoningForModel(response.reasoning, completionReq.model, require_helpers.resolveStrictMode(defaults.strict, req.headers), logger);
		const journalEntry = journal.add({
			method: req.method ?? "POST",
			path: urlPath,
			headers: require_helpers.flattenHeaders(req.headers),
			body: completionReq,
			response: {
				status: 200,
				fixture
			}
		});
		const events = buildBedrockStreamContentWithToolCallsEvents(response.content ?? "", response.toolCalls ?? [], completionReq.model, chunkSize, logger, effReasoning, overrides, response.blocks);
		const interruption = require_interruption.createInterruptionSignal(fixture);
		if (!await require_aws_event_stream.writeEventStream(res, events, {
			latency,
			streamingProfile: fixture.streamingProfile,
			recordedTimings: fixture.recordedTimings,
			replaySpeed: fixture.replaySpeed ?? defaults.replaySpeed,
			signal: interruption?.signal,
			onChunkSent: interruption?.tick
		})) {
			if (!res.writableEnded) res.destroy();
			journalEntry.response.interrupted = true;
			journalEntry.response.interruptReason = interruption?.reason();
		}
		interruption?.cleanup();
		return;
	}
	if (require_helpers.isTextResponse(response)) {
		if (response.webSearches?.length) logger.warn("webSearches in fixture response are not supported for Bedrock API — ignoring");
		const overrides = require_helpers.extractOverrides(response);
		const effReasoning = require_helpers.resolveReasoningForModel(response.reasoning, completionReq.model, require_helpers.resolveStrictMode(defaults.strict, req.headers), logger);
		const journalEntry = journal.add({
			method: req.method ?? "POST",
			path: urlPath,
			headers: require_helpers.flattenHeaders(req.headers),
			body: completionReq,
			response: {
				status: 200,
				fixture
			}
		});
		const events = buildBedrockStreamTextEvents(response.content, completionReq.model, chunkSize, effReasoning, overrides);
		const interruption = require_interruption.createInterruptionSignal(fixture);
		if (!await require_aws_event_stream.writeEventStream(res, events, {
			latency,
			streamingProfile: fixture.streamingProfile,
			recordedTimings: fixture.recordedTimings,
			replaySpeed: fixture.replaySpeed ?? defaults.replaySpeed,
			signal: interruption?.signal,
			onChunkSent: interruption?.tick
		})) {
			if (!res.writableEnded) res.destroy();
			journalEntry.response.interrupted = true;
			journalEntry.response.interruptReason = interruption?.reason();
		}
		interruption?.cleanup();
		return;
	}
	if (require_helpers.isToolCallResponse(response)) {
		if (response.webSearches?.length) logger.warn("webSearches in fixture response are not supported for Bedrock API — ignoring");
		const overrides = require_helpers.extractOverrides(response);
		const effReasoning = require_helpers.resolveReasoningForModel(response.reasoning, completionReq.model, require_helpers.resolveStrictMode(defaults.strict, req.headers), logger);
		const journalEntry = journal.add({
			method: req.method ?? "POST",
			path: urlPath,
			headers: require_helpers.flattenHeaders(req.headers),
			body: completionReq,
			response: {
				status: 200,
				fixture
			}
		});
		const events = buildBedrockStreamToolCallEvents(response.toolCalls, completionReq.model, chunkSize, logger, effReasoning, overrides);
		const interruption = require_interruption.createInterruptionSignal(fixture);
		if (!await require_aws_event_stream.writeEventStream(res, events, {
			latency,
			streamingProfile: fixture.streamingProfile,
			recordedTimings: fixture.recordedTimings,
			replaySpeed: fixture.replaySpeed ?? defaults.replaySpeed,
			signal: interruption?.signal,
			onChunkSent: interruption?.tick
		})) {
			if (!res.writableEnded) res.destroy();
			journalEntry.response.interrupted = true;
			journalEntry.response.interruptReason = interruption?.reason();
		}
		interruption?.cleanup();
		return;
	}
	journal.add({
		method: req.method ?? "POST",
		path: urlPath,
		headers: require_helpers.flattenHeaders(req.headers),
		body: completionReq,
		response: {
			status: 500,
			fixture
		}
	});
	require_sse_writer.writeErrorResponse(res, 500, JSON.stringify({ error: {
		message: "Fixture response did not match any known type",
		type: "server_error"
	} }));
}

//#endregion
exports.bedrockToCompletionRequest = bedrockToCompletionRequest;
exports.handleBedrock = handleBedrock;
exports.handleBedrockStream = handleBedrockStream;
//# sourceMappingURL=bedrock.cjs.map