UNPKG

eve

Version:

Filesystem-first framework for durable backend AI agents that run anywhere.

3,389 lines 118 kB
import { computed, onScopeDispose, shallowRef } from "vue";
import { z } from "#compiled/zod/index.js";
import { asSchema } from "ai";

//#region src/protocol/routes.ts
const EVE_ROUTE_PREFIX = "/eve/v1";
const EVE_PRODUCTION_CRON_ROUTE_PATTERN = `${EVE_ROUTE_PREFIX}/cron/:token`;
const EVE_HEALTH_ROUTE_PATH = `${EVE_ROUTE_PREFIX}/health`;
const EVE_INFO_ROUTE_PATH = `${EVE_ROUTE_PREFIX}/info`;
const EVE_SESSION_ROUTE_PATH = `${EVE_ROUTE_PREFIX}/session`;
const EVE_SESSION_ROUTE_PATTERN = `${EVE_SESSION_ROUTE_PATH}/:sessionId`;
const EVE_SESSION_CANCEL_ROUTE_PATTERN = `${EVE_SESSION_ROUTE_PATH}/:sessionId/cancel`;
const EVE_SESSION_COMPACT_ROUTE_PATTERN = `${EVE_SESSION_ROUTE_PATH}/:sessionId/compact`;
const EVE_SESSION_CLEAR_ROUTE_PATTERN = `${EVE_SESSION_ROUTE_PATH}/:sessionId/clear`;
const EVE_SESSION_RESET_ROUTE_PATTERN = `${EVE_SESSION_ROUTE_PATH}/:sessionId/reset`;
const EVE_SESSION_STREAM_ROUTE_PATTERN = `${EVE_SESSION_ROUTE_PATH}/:sessionId/stream`;
const EVE_SUBAGENT_STREAM_ROUTE_PATTERN = `${EVE_SESSION_ROUTE_PATH}/:parentSessionId/subagents/:callId/:childSessionId/stream`;
const EVE_DEV_DISPATCH_SCHEDULE_ROUTE_PATTERN = `${EVE_ROUTE_PREFIX}/dev/schedules/:scheduleId`;
const EVE_DEV_RUNTIME_ARTIFACTS_ROUTE_PATH = `${EVE_ROUTE_PREFIX}/dev/runtime-artifacts`;
const EVE_DEV_RUNTIME_ARTIFACTS_REBUILD_ROUTE_PATH = `${EVE_DEV_RUNTIME_ARTIFACTS_ROUTE_PATH}/rebuild`;
const EVE_DEV_RUNTIME_ARTIFACTS_SUSPEND_ROUTE_PATH = `${EVE_DEV_RUNTIME_ARTIFACTS_ROUTE_PATH}/suspend`;
const EVE_DEV_RUNTIME_ARTIFACTS_RESUME_ROUTE_PATH = `${EVE_DEV_RUNTIME_ARTIFACTS_ROUTE_PATH}/resume`;
const EVE_CONNECTION_CALLBACK_ROUTE_PATTERN = `${EVE_ROUTE_PREFIX}/connections/:name/callback/:attemptId/:token`;
const EVE_CALLBACK_ROUTE_PATTERN = `${EVE_ROUTE_PREFIX}/callback/:token`;
const EVE_TASK_INPUT_ROUTE_PATTERN = `${EVE_ROUTE_PREFIX}/task-input/:token`;
const EVE_ACTIVITY_ROUTE_PATTERN = `${EVE_ROUTE_PREFIX}/activity/:token`;
function createEveSessionRoutePath(sessionId) {
	return `${EVE_SESSION_ROUTE_PATH}/${encodeURIComponent(sessionId)}`;
}
function createEveSessionCancelRoutePath(sessionId) {
	return `${EVE_SESSION_ROUTE_PATH}/${encodeURIComponent(sessionId)}/cancel`;
}
function createEveSessionCompactRoutePath(sessionId) {
	return `${EVE_SESSION_ROUTE_PATH}/${encodeURIComponent(sessionId)}/compact`;
}
function createEveSessionClearRoutePath(sessionId) {
	return `${EVE_SESSION_ROUTE_PATH}/${encodeURIComponent(sessionId)}/clear`;
}
function createEveSessionResetRoutePath(sessionId) {
	return `${EVE_SESSION_ROUTE_PATH}/${encodeURIComponent(sessionId)}/reset`;
}
function createEveSessionStreamRoutePath(sessionId) {
	return `${EVE_SESSION_ROUTE_PATH}/${encodeURIComponent(sessionId)}/stream`;
}

//#endregion
//#region src/client/agent-info-error.ts
var AgentInfoResponseError = class extends Error {
	issues;
	constructor(issues = []) {
		const detail = issues.length === 0 ? "" : ` (${issues.join("; ")})`;
		super(`The server returned an unrecognized response from the eve agent info route.${detail}`);
		this.name = "AgentInfoResponseError";
		this.issues = issues;
	}
};

//#endregion
//#region src/client/health-response-error.ts
var HealthResponseError = class extends Error {
	issues;
	constructor(issues = []) {
		const detail = issues.length === 0 ? "" : ` (${issues.join("; ")})`;
		super(`The server returned an unrecognized eve health response.${detail}`);
		this.name = "HealthResponseError";
		this.issues = issues;
	}
};

//#endregion
//#region src/client/health-schema.ts
const HealthResultSchema = z.object({
	ok: z.literal(true),
	status: z.literal("ready"),
	workflowId: z.string().min(1)
}).strict();

//#endregion
//#region src/internal/http/basic-auth.ts
function encodeBasicCredentials(username, password) {
	const bytes = new TextEncoder().encode(`${username}:${password}`);
	const binaryString = Array.from(bytes, (byte) => String.fromCodePoint(byte)).join("");
	return btoa(binaryString);
}

//#endregion
//#region src/client/agent-info-schema.ts
const owner = z.discriminatedUnion("kind", [
	z.object({ kind: z.literal("application") }).strict(),
	z.object({
		feature: z.string(),
		kind: z.literal("framework")
	}).strict(),
	z.object({
		kind: z.literal("extension"),
		namespace: z.string(),
		packageName: z.string()
	}).strict()
]);
const moduleBacking = z.discriminatedUnion("kind", [z.object({
	externalDependencies: z.array(z.string()),
	extensionScope: z.object({
		namespace: z.string(),
		sourceRoot: z.string()
	}).strict().optional(),
	kind: z.literal("filesystem"),
	sourcePath: z.string()
}).strict(), z.object({
	dependencies: z.record(z.string(), z.string()).optional(),
	kind: z.literal("programmatic"),
	moduleId: z.string(),
	parameters: z.record(z.string(), z.unknown()).optional(),
	registryId: z.string(),
	revision: z.string(),
	semanticRevision: z.string().optional()
}).strict()]);
const binding = z.object({
	backing: moduleBacking,
	logicalPath: z.string(),
	owner
}).strict();
const source = z.object({
	binding: binding.optional(),
	exportName: z.string().optional(),
	logicalPath: z.string(),
	owner,
	sourceId: z.string(),
	sourceKind: z.enum([
		"markdown",
		"module",
		"skill-package"
	])
}).strict();
const entry = source.extend({ name: z.string() }).strict();
const dynamicResolver = source.extend({
	eventNames: z.array(z.string()),
	slug: z.string()
}).strict();
const modelRouting = z.discriminatedUnion("kind", [z.object({
	kind: z.literal("gateway"),
	target: z.string(),
	byok: z.string().optional()
}).strict(), z.object({
	kind: z.literal("external"),
	provider: z.string()
}).strict()]);
const modelEndpoint = z.union([
	z.object({
		kind: z.literal("external"),
		provider: z.string()
	}).strict(),
	z.object({
		kind: z.literal("chatgpt"),
		state: z.enum([
			"checking",
			"ready",
			"signed-out",
			"reauth-required",
			"unavailable"
		]),
		accountLabel: z.string().optional()
	}).strict(),
	z.object({
		kind: z.literal("gateway"),
		connected: z.literal(true),
		credential: z.enum([
			"api-key",
			"oidc",
			"oauth"
		]),
		team: z.optional(z.string())
	}).strict(),
	z.object({
		kind: z.literal("gateway"),
		connected: z.literal(false)
	}).strict()
]);
const modelBaseFields = {
	contextWindowTokens: z.number().optional(),
	providerOptions: z.unknown().optional(),
	reasoning: z.enum([
		"provider-default",
		"none",
		"minimal",
		"low",
		"medium",
		"high",
		"xhigh"
	]).optional().catch(void 0),
	source: source.optional()
};
const agentModel = z.union([z.object({
	...modelBaseFields,
	endpoint: modelEndpoint.optional(),
	id: z.string(),
	routing: modelRouting
}).strict(), z.object({
	...modelBaseFields,
	endpoint: z.never().optional(),
	id: z.never().optional(),
	routing: z.object({
		kind: z.literal("dynamic"),
		resolver: dynamicResolver
	}).strict()
}).strict()]);
const tool = entry.extend({
	description: z.string(),
	hasAuth: z.boolean(),
	hasExecute: z.boolean(),
	hasModelOutputProjection: z.boolean(),
	hasOutputSchema: z.boolean(),
	inputSchema: z.unknown(),
	outputSchema: z.unknown().optional(),
	requiresApproval: z.boolean()
}).strict();
const skill = entry.extend({
	description: z.string(),
	license: z.string().optional(),
	markdown: z.string(),
	metadata: z.record(z.string(), z.string()).optional()
}).strict();
const instructions = entry.extend({
	content: z.string(),
	role: z.enum(["system", "user"])
}).strict();
const schedule = entry.extend({
	cron: z.string(),
	hasRun: z.boolean(),
	markdown: z.string().optional()
}).strict();
const channelMethod = z.enum([
	"GET",
	"HEAD",
	"POST",
	"PUT",
	"PATCH",
	"DELETE",
	"OPTIONS",
	"WEBSOCKET"
]);
const channelRoute = entry.extend({
	adapterKind: z.string().optional(),
	method: channelMethod,
	urlPath: z.string()
}).strict();
const sourceDescriptor = z.object({
	backing: z.union([moduleBacking, z.object({
		kind: z.literal("resource"),
		sourcePath: z.string()
	}).strict()]),
	form: z.enum(["derived", "direct"]),
	layer: z.enum([
		"framework-default",
		"extension-package",
		"extension-override",
		"application"
	]),
	logicalPath: z.string(),
	owner,
	sourceId: z.string()
}).strict();
const shadowedChannelRoute = z.object({
	method: channelMethod,
	source: sourceDescriptor,
	urlPath: z.string(),
	winnerSourceId: z.string()
}).strict();
const connection = source.extend({
	connectionName: z.string(),
	description: z.string(),
	hasApproval: z.boolean(),
	hasAuthorization: z.boolean(),
	hasHeaders: z.boolean(),
	protocol: z.string(),
	toolFilter: z.unknown().optional(),
	url: z.string()
}).strict();
const hook = source.extend({
	eventNames: z.array(z.string()),
	slug: z.string()
}).strict();
const memory = source.extend({
	description: z.string().optional(),
	slot: z.string(),
	visibility: z.enum(["scope", "session"])
}).strict();
const sandbox = source.extend({
	provider: z.string().optional(),
	environmentExportName: z.string().optional(),
	revisionHash: z.string()
}).strict();
const subagent = entry.extend({
	configResolver: dynamicResolver.optional(),
	description: z.string().optional(),
	entryPath: z.string(),
	nodeId: z.string(),
	parentNodeId: z.string(),
	rootPath: z.string(),
	summary: z.object({
		channels: z.number(),
		connections: z.number(),
		hooks: z.number(),
		instructions: z.number(),
		memories: z.number(),
		schedules: z.number(),
		skills: z.number(),
		tools: z.number()
	}).strict()
}).strict();
const remoteAgent = entry.extend({
	description: z.string(),
	nodeId: z.string(),
	parentNodeId: z.string(),
	url: z.string().optional()
}).strict();
const kernelEffect = z.object({
	action: z.enum([
		"subagent-call",
		"task-cancel",
		"workflow-tool-call"
	]).optional(),
	audience: z.array(z.enum(["root-session", "delegated-task-child"])),
	kind: z.enum(["dispatch", "provider-tool"]),
	sourceId: z.string()
}).strict();
const compositionDiagnostic = z.object({
	kind: z.enum(["disabled", "shadowed"]),
	logicalPath: z.string(),
	owner,
	sourceId: z.string(),
	winnerSourceId: z.string().optional()
}).strict();
const AgentInfoResultSchema = z.object({
	agent: z.object({
		agentRoot: z.string(),
		appRoot: z.string(),
		config: source.extend({ binding }).strict(),
		description: z.string().optional(),
		model: agentModel,
		name: z.string(),
		nodeId: z.string(),
		outputSchema: z.unknown().optional()
	}).strict(),
	capabilities: z.object({ devRoutes: z.boolean() }).strict(),
	channels: z.object({
		routes: z.array(channelRoute),
		shadowed: z.array(shadowedChannelRoute)
	}).strict(),
	composition: z.object({
		disabled: z.array(compositionDiagnostic),
		shadowed: z.array(compositionDiagnostic)
	}).strict(),
	connections: z.array(connection),
	diagnostics: z.object({
		discoveryErrors: z.number(),
		discoveryWarnings: z.number()
	}).strict(),
	hooks: z.array(hook),
	instructions: z.object({
		dynamic: z.array(dynamicResolver),
		static: z.array(instructions)
	}).strict(),
	instrumentation: source.optional(),
	kernelEffects: z.array(kernelEffect),
	kind: z.literal("eve-agent-info"),
	memories: z.array(memory),
	mode: z.enum(["development", "production"]),
	remoteAgents: z.object({
		entries: z.array(remoteAgent),
		total: z.number()
	}).strict(),
	sandbox,
	schedules: z.array(schedule),
	skills: z.object({
		dynamic: z.array(dynamicResolver),
		static: z.array(skill)
	}).strict(),
	subagents: z.object({
		local: z.array(subagent),
		total: z.number()
	}).strict(),
	tools: z.object({
		dynamic: z.array(dynamicResolver),
		static: z.array(tool)
	}).strict(),
	version: z.literal(5),
	workspace: z.object({
		resourceRoot: z.unknown(),
		rootEntries: z.array(z.string())
	}).strict()
}).strict().superRefine((value, context) => {
	const assertUnique = (entries, identity, path) => {
		const seen = /* @__PURE__ */ new Set();
		entries.forEach((entry, index) => {
			const key = identity(entry);
			if (seen.has(key)) context.addIssue({
				code: "custom",
				message: `Duplicate public identity "${key}".`,
				path: [...path, index]
			});
			seen.add(key);
		});
	};
	const assertTotal = (total, entries, path) => {
		if (!Number.isSafeInteger(total) || total < 0 || total !== entries.length) context.addIssue({
			code: "custom",
			message: `Expected total ${entries.length}, received ${total}.`,
			path: [...path]
		});
	};
	assertUnique(value.tools.static, (entry) => entry.name, ["tools", "static"]);
	assertUnique(value.tools.dynamic, (entry) => entry.slug, ["tools", "dynamic"]);
	assertUnique(value.skills.static, (entry) => entry.name, ["skills", "static"]);
	assertUnique(value.skills.dynamic, (entry) => entry.slug, ["skills", "dynamic"]);
	assertUnique(value.instructions.static, (entry) => entry.name, ["instructions", "static"]);
	assertUnique(value.instructions.dynamic, (entry) => entry.slug, ["instructions", "dynamic"]);
	assertUnique(value.schedules, (entry) => entry.name, ["schedules"]);
	assertUnique(value.connections, (entry) => entry.connectionName, ["connections"]);
	assertUnique(value.hooks, (entry) => entry.slug, ["hooks"]);
	assertUnique(value.memories, (entry) => entry.slot, ["memories"]);
	assertUnique(value.channels.routes, (entry) => `${entry.method} ${normalizeRoutePattern(entry.urlPath)}`, ["channels", "routes"]);
	assertUnique(value.subagents.local, (entry) => entry.nodeId, ["subagents", "local"]);
	assertUnique(value.remoteAgents.entries, (entry) => entry.nodeId, ["remoteAgents", "entries"]);
	assertTotal(value.subagents.total, value.subagents.local, ["subagents", "total"]);
	assertTotal(value.remoteAgents.total, value.remoteAgents.entries, ["remoteAgents", "total"]);
	const boundSources = [
		[value.agent.config, ["agent", "config"]],
		...value.agent.model.source === void 0 ? [] : [[value.agent.model.source, [
			"agent",
			"model",
			"source"
		]]],
		...value.agent.model.routing.kind === "dynamic" ? [[value.agent.model.routing.resolver, [
			"agent",
			"model",
			"routing",
			"resolver"
		]]] : [],
		...value.channels.routes.map((entry, index) => [entry, [
			"channels",
			"routes",
			index
		]]),
		...value.connections.map((entry, index) => [entry, ["connections", index]]),
		...value.hooks.map((entry, index) => [entry, ["hooks", index]]),
		...value.instructions.dynamic.map((entry, index) => [entry, [
			"instructions",
			"dynamic",
			index
		]]),
		...value.instructions.static.map((entry, index) => [entry, [
			"instructions",
			"static",
			index
		]]),
		...value.memories.map((entry, index) => [entry, ["memories", index]]),
		...value.instrumentation === void 0 ? [] : [[value.instrumentation, ["instrumentation"]]],
		...value.remoteAgents.entries.map((entry, index) => [entry, [
			"remoteAgents",
			"entries",
			index
		]]),
		...value.schedules.map((entry, index) => [entry, ["schedules", index]]),
		...value.skills.dynamic.map((entry, index) => [entry, [
			"skills",
			"dynamic",
			index
		]]),
		...value.skills.static.map((entry, index) => [entry, [
			"skills",
			"static",
			index
		]]),
		...value.subagents.local.flatMap((entry, index) => entry.configResolver === void 0 ? [] : [[entry.configResolver, [
			"subagents",
			"local",
			index,
			"configResolver"
		]]]),
		...value.tools.dynamic.map((entry, index) => [entry, [
			"tools",
			"dynamic",
			index
		]]),
		...value.tools.static.map((entry, index) => [entry, [
			"tools",
			"static",
			index
		]]),
		[value.sandbox, ["sandbox"]]
	];
	for (const [entry, path] of boundSources) {
		if (entry.sourceKind === "module" && entry.binding === void 0) {
			context.addIssue({
				code: "custom",
				message: "Module source is missing its compiled binding.",
				path: [...path, "binding"]
			});
			continue;
		}
		if (entry.sourceKind !== "module" && entry.binding !== void 0) {
			context.addIssue({
				code: "custom",
				message: `${entry.sourceKind} source cannot carry a module binding.`,
				path: [...path, "binding"]
			});
			continue;
		}
		if (entry.binding === void 0) continue;
		if (entry.binding.logicalPath !== entry.logicalPath) context.addIssue({
			code: "custom",
			message: "Source and binding logical paths do not match.",
			path: [
				...path,
				"binding",
				"logicalPath"
			]
		});
		if (JSON.stringify(entry.binding.owner) !== JSON.stringify(entry.owner)) context.addIssue({
			code: "custom",
			message: "Source and binding owners do not match.",
			path: [
				...path,
				"binding",
				"owner"
			]
		});
	}
});
function normalizeRoutePattern(path) {
	return path.replace(/^\/+|\/+$/g, "").split("/").map((segment) => segment.startsWith(":") || /^\[[^\]]+\]$/.test(segment) ? ":" : segment).join("/");
}

//#endregion
//#region src/shared/guards.ts
function isObject(value) {
	return typeof value === "object" && value !== null && !Array.isArray(value);
}

//#endregion
//#region src/client/client-error.ts
var ClientError = class extends Error {
	code;
	status;
	body;
	headers;
	constructor(status, body, headers) {
		let message = body || `Server returned ${status}.`;
		let code;
		try {
			const parsed = JSON.parse(body);
			if (isObject(parsed)) {
				if (typeof parsed.error === "string") message = parsed.error;
				if (typeof parsed.code === "string") code = parsed.code;
			}
		} catch {}
		super(message);
		this.name = "ClientError";
		this.code = code;
		this.status = status;
		this.body = body;
		this.headers = Object.freeze(Object.fromEntries(new Headers(headers).entries()));
	}
};

//#endregion
//#region src/shared/errors.ts
function toErrorMessage(error) {
	if (error instanceof Error) return error.message;
	if (typeof error === "string") return error;
	if (error === null || error === void 0) return String(error);
	if (isObject(error)) {
		if (typeof error.message === "string" && error.message.length > 0) return error.message;
		return safeJsonStringify(error);
	}
	return String(error);
}
function toError(raw) {
	if (raw instanceof Error) return raw;
	const error = new Error(toErrorMessage(raw));
	if (!isObject(raw)) return error;
	if (typeof raw.name === "string" && raw.name.length > 0) error.name = raw.name;
	if (typeof raw.stack === "string" && raw.stack.length > 0) error.stack = raw.stack;
	if ("cause" in raw && raw.cause !== void 0 && raw.cause !== raw) error.cause = raw.cause;
	return error;
}
function safeJsonStringify(value) {
	try {
		return JSON.stringify(value) ?? String(value);
	} catch {
		return String(value);
	}
}

//#endregion
//#region src/shared/ulid.ts
const ENCODING = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
const TIME_CHARS = 10;
const TIME_MAX = 2 ** 48 - 1;
const RANDOM_BYTES = 10;
function createUlidFactory() {
	let lastTimeMs = -1;
	const lastRandom = new Uint8Array(RANDOM_BYTES);
	return function createUlidFromFactory() {
		const now = Date.now();
		if (!Number.isInteger(now) || now < 0 || now > TIME_MAX) throw new Error(`Cannot mint a ULID: timestamp must be an integer from 0 to ${TIME_MAX}.`);
		if (now > lastTimeMs) {
			lastTimeMs = now;
			randomFill(lastRandom);
		} else if (!incrementRandom(lastRandom)) {
			if (lastTimeMs === TIME_MAX) throw new Error("Cannot mint a ULID: random component overflowed at the maximum timestamp.");
			lastTimeMs += 1;
			randomFill(lastRandom);
		}
		return `${encodeTime(lastTimeMs)}${encodeRandom(lastRandom)}`;
	};
}
const createUlid = createUlidFactory();
function randomFill(target) {
	const webCrypto = globalThis.crypto;
	if (typeof webCrypto?.getRandomValues !== "function") throw new Error("Cannot mint a ULID: globalThis.crypto.getRandomValues is unavailable.");
	webCrypto.getRandomValues(target);
}
function encodeTime(timeMs) {
	let remaining = timeMs;
	let encoded = "";
	for (let index = 0; index < TIME_CHARS; index += 1) {
		encoded = ENCODING[remaining % 32] + encoded;
		remaining = Math.floor(remaining / 32);
	}
	return encoded;
}
function encodeRandom(bytes) {
	let buffer = 0;
	let bufferedBits = 0;
	let encoded = "";
	for (const byte of bytes) {
		buffer = buffer << 8 | byte;
		bufferedBits += 8;
		while (bufferedBits >= 5) {
			bufferedBits -= 5;
			encoded += ENCODING[buffer >>> bufferedBits & 31];
		}
		buffer &= (1 << bufferedBits) - 1;
	}
	return encoded;
}
function incrementRandom(bytes) {
	for (let index = bytes.length - 1; index >= 0; index -= 1) {
		const byte = bytes[index] ?? 0;
		if (byte < 255) {
			bytes[index] = byte + 1;
			bytes.fill(0, index + 1);
			return true;
		}
	}
	return false;
}

//#endregion
//#region src/protocol/message.ts
const EVE_SESSION_ID_HEADER = "x-eve-session-id";
const EVE_STREAM_TAIL_INDEX_HEADER = "x-eve-stream-tail-index";
const EVE_STREAM_VERSION_HEADER = "x-eve-stream-version";
const EVE_STREAM_CONTROL_VERSION_QUERY = "streamControlVersion";
const EVE_STREAM_LEASE_ENDED_CONTROL = {
	$eve: "stream.lease-ended",
	version: 1
};
const textEncoder = new TextEncoder();
function isCurrentTurnBoundaryEvent(event) {
	return event.type === "session.completed" || event.type === "session.failed" || event.type === "session.waiting";
}
function isTurnFailureEvent(event) {
	return event.type === "session.failed" || event.type === "step.failed" || event.type === "turn.failed";
}

//#endregion
//#region src/client/session-utils.ts
function summarizeTurnEvents(events) {
	let boundary;
	let failure;
	let message;
	const inputRequests = [];
	const pendingAuthorizations = /* @__PURE__ */ new Map();
	for (const event of events) {
		if (isCurrentTurnBoundaryEvent(event)) boundary = event;
		if (isTurnFailureEvent(event)) failure = event;
		if (isFinalMessageCompleted(event)) message = event.data.message ?? void 0;
		if (event.type === "input.requested") inputRequests.push(...event.data.requests);
		if (event.type === "authorization.required") pendingAuthorizations.set(event.data.name, event.data);
		if (event.type === "authorization.completed") pendingAuthorizations.delete(event.data.name);
	}
	return {
		boundary,
		failure,
		inputRequests,
		message,
		pendingAuthorizations: [...pendingAuthorizations.values()],
		status: boundary?.type === "session.waiting" ? "waiting" : boundary?.type === "session.failed" ? "failed" : "completed"
	};
}
function isFinalMessageCompleted(event) {
	return event.type === "message.completed" && event.data.finishReason !== "tool-calls";
}
function updatePendingAuthorizations(pending, event) {
	if (event.type === "authorization.required" && event.data.webhookUrl !== void 0) pending.add(event.data.name);
	else if (event.type === "authorization.completed") pending.delete(event.data.name);
}

//#endregion
//#region src/client/output-schema.ts
function extractCompletedResult(events) {
	let result;
	for (const event of events) if (isResultCompletedEvent(event)) result = event.data.result;
	return result;
}
function isResultCompletedEvent(event) {
	return event.type === "result.completed";
}

//#endregion
//#region src/client/message-response.ts
const consumeResponse = Symbol("consumeMessageResponse");
const acceptedDeliveryId = Symbol("acceptedDeliveryId");
var MessageResponse = class {
	sessionId;
	[acceptedDeliveryId];
	#cancelTurn;
	#cancellation;
	#consumed = false;
	#createStream;
	#settled = false;
	#turnId = Promise.withResolvers();
	constructor(input) {
		this.#cancelTurn = input.cancelTurn;
		this.sessionId = input.sessionId;
		this[acceptedDeliveryId] = input.deliveryId;
		this.#createStream = input.createStream;
	}
	cancel() {
		if (this.#settled) return Promise.resolve({ status: "no_active_turn" });
		if (this.#cancellation !== void 0) return this.#cancellation;
		const cancellation = this.#turnId.promise.then((turnId) => turnId === void 0 ? { status: "no_active_turn" } : this.#cancelTurn(turnId));
		this.#cancellation = cancellation;
		cancellation.catch(() => {
			if (!this.#settled && this.#cancellation === cancellation) this.#cancellation = void 0;
		});
		return cancellation;
	}
	async result() {
		const events = [];
		for await (const event of this) events.push(event);
		const summary = summarizeTurnEvents(events);
		return {
			data: extractCompletedResult(events),
			events,
			inputRequests: summary.inputRequests,
			message: summary.message,
			sessionId: this.sessionId,
			status: summary.status
		};
	}
	[Symbol.asyncIterator]() {
		return this[consumeResponse]();
	}
	[consumeResponse](source) {
		if (this.#consumed) throw new Error("MessageResponse has already been consumed.");
		this.#consumed = true;
		return this.#observeStream(source);
	}
	async *#observeStream(source) {
		try {
			for await (const event of this.#createStream(source)) {
				if (event.type === "turn.started") this.#turnId.resolve(event.data.turnId);
				else if (isCurrentTurnBoundaryEvent(event)) {
					this.#settled = true;
					this.#turnId.resolve(void 0);
				}
				yield event;
			}
		} finally {
			this.#turnId.resolve(void 0);
		}
	}
};
function getMessageResponseDeliveryId(response) {
	return response[acceptedDeliveryId];
}
function consumeMessageResponse(response, source) {
	return response[consumeResponse](source);
}

//#endregion
//#region src/protocol/message-version.ts
function normalizeMessageStreamEvent(version, event) {
	switch (version) {
		case "21":
		case "22":
		case "23":
		case "24": return normalizeLegacyMessageStreamEvent(version, event);
		case "25": return validateCurrentMessageStreamEvent(event);
		default: return assertNever(version);
	}
}
function normalizeLegacyMessageStreamEvent(version, event) {
	if (event.type === "message.appended") {
		assertLegacyAppendSnapshot(event.data.messageSoFar, event.data.messageDelta, "message", version);
		return {
			data: {
				messageDelta: event.data.messageDelta,
				sequence: event.data.sequence,
				stepIndex: event.data.stepIndex,
				turnId: event.data.turnId
			},
			meta: event.meta,
			type: "message.appended"
		};
	}
	if (event.type === "reasoning.appended") {
		assertLegacyAppendSnapshot(event.data.reasoningSoFar, event.data.reasoningDelta, "reasoning", version);
		return {
			data: {
				reasoningDelta: event.data.reasoningDelta,
				sequence: event.data.sequence,
				stepIndex: event.data.stepIndex,
				turnId: event.data.turnId
			},
			meta: event.meta,
			type: "reasoning.appended"
		};
	}
	if (event.type === "action.input.appended") {
		if (version !== void 0 && version !== "24") throw new TypeError(`Invalid action input append for stream version ${version}.`);
		assertLegacyActionInputOffset(event.data.inputTextOffset, version);
		return {
			data: {
				callId: event.data.callId,
				inputTextDelta: event.data.inputTextDelta,
				sequence: event.data.sequence,
				stepIndex: event.data.stepIndex,
				toolName: event.data.toolName,
				turnId: event.data.turnId
			},
			meta: event.meta,
			type: "action.input.appended"
		};
	}
	return event;
}
function validateCurrentMessageStreamEvent(event) {
	if (event.type === "message.appended") {
		assertCurrentAppendDelta(event.data.messageDelta, "message");
		assertUnsupportedAppendField(event.data, "messageOffset", "message");
		assertUnsupportedAppendField(event.data, "messageSoFar", "message");
	} else if (event.type === "reasoning.appended") {
		assertCurrentAppendDelta(event.data.reasoningDelta, "reasoning");
		assertUnsupportedAppendField(event.data, "reasoningOffset", "reasoning");
		assertUnsupportedAppendField(event.data, "reasoningSoFar", "reasoning");
	} else if (event.type === "action.input.appended") {
		assertCurrentAppendDelta(event.data.inputTextDelta, "action input");
		assertUnsupportedAppendField(event.data, "inputTextOffset", "action input");
	}
	return event;
}
function assertCurrentAppendDelta(delta, stream) {
	if (typeof delta !== "string") throw new TypeError(`Invalid ${stream} append delta for stream version 25.`);
}
function assertUnsupportedAppendField(data, field, stream) {
	if (field in data) throw new TypeError(`Invalid ${stream} append shape for stream version 25.`);
}
function assertNever(value) {
	throw new TypeError(`Unsupported message stream version: ${String(value)}.`);
}
function assertLegacyActionInputOffset(offset, version) {
	if (!Number.isSafeInteger(offset) || offset < 0) {
		const source = version === void 0 ? "persisted stream" : `stream version ${version}`;
		throw new TypeError(`Invalid action input append offset for ${source}.`);
	}
}
function assertLegacyAppendSnapshot(snapshot, delta, stream, version) {
	const offset = snapshot.length - delta.length;
	if (offset < 0 || snapshot.slice(offset) !== delta) {
		const source = version === void 0 ? "persisted stream" : `stream version ${version}`;
		throw new TypeError(`Invalid cumulative ${stream} append for ${source}.`);
	}
}

//#endregion
//#region src/client/ndjson.ts
function isStreamDisconnectError(error) {
	if (error instanceof DOMException) return error.name === "AbortError";
	if (!(error instanceof Error)) return false;
	const errorCode = "code" in error && typeof error.code === "string" ? error.code : void 0;
	return error.name === "AbortError" || error.message === "terminated" || errorCode === "UND_ERR_SOCKET" || error instanceof TypeError && /^(?:failed to fetch|fetch failed)$/i.test(error.message) || /abort|cancel|disconnect|premature close|socket|terminated/i.test(error.message);
}
async function* readNdjsonStream(body, options) {
	const reader = body.getReader();
	const decoder = new TextDecoder();
	let buffer = "";
	let reachedEof = false;
	const abort = () => {
		reader.cancel().catch(() => {});
	};
	options.signal?.addEventListener("abort", abort, { once: true });
	try {
		while (true) {
			options.signal?.throwIfAborted();
			const result = await readWithIdleTimeout(reader, options?.idleTimeoutMs);
			options.signal?.throwIfAborted();
			if (result.done) {
				reachedEof = true;
				buffer += decoder.decode();
				break;
			}
			if (result.value) buffer += decoder.decode(result.value, { stream: true });
			let newlineIndex = buffer.indexOf("\n");
			while (newlineIndex !== -1) {
				const line = buffer.slice(0, newlineIndex).trim();
				buffer = buffer.slice(newlineIndex + 1);
				if (line.length > 0) {
					const value = JSON.parse(line);
					if (options.controlVersion === "1" && isLeaseEndedControl(value)) options.onLeaseEnded?.();
					else yield parseMessageStreamEvent(value, options.streamVersion);
				}
				newlineIndex = buffer.indexOf("\n");
			}
		}
		const trailing = buffer.trim();
		if (trailing.length > 0) {
			const value = JSON.parse(trailing);
			if (options.controlVersion === "1" && isLeaseEndedControl(value)) options.onLeaseEnded?.();
			else yield parseMessageStreamEvent(value, options.streamVersion);
		}
	} finally {
		options.signal?.removeEventListener("abort", abort);
		if (!reachedEof) reader.cancel().catch(() => {});
		reader.releaseLock();
	}
}
function isLeaseEndedControl(value) {
	if (value === null || typeof value !== "object") return false;
	const record = value;
	return record.$eve === EVE_STREAM_LEASE_ENDED_CONTROL.$eve && record.version === EVE_STREAM_LEASE_ENDED_CONTROL.version;
}
function parseMessageStreamEvent(value, version) {
	return normalizeMessageStreamEvent(version, value);
}
async function readWithIdleTimeout(reader, idleTimeoutMs) {
	let timeout;
	try {
		if (idleTimeoutMs === void 0) return await reader.read();
		return await Promise.race([reader.read(), new Promise((_resolve, reject) => {
			timeout = setTimeout(() => reject(new DOMException("Session stream was idle.", "AbortError")), idleTimeoutMs);
		})]);
	} catch (error) {
		if (error instanceof TypeError) throw new Error("Session stream disconnected.", { cause: error });
		throw error;
	} finally {
		if (timeout !== void 0) clearTimeout(timeout);
	}
}

//#endregion
//#region src/client/stream-version.ts
const supportedMessageStreamVersions = {
	"21": true,
	"22": true,
	"23": true,
	"24": true,
	"25": true
};
function readMessageStreamVersion(headers) {
	const version = headers.get(EVE_STREAM_VERSION_HEADER);
	if (version !== null && Object.hasOwn(supportedMessageStreamVersions, version)) return version;
	if (version === null) throw new TypeError(`Missing ${EVE_STREAM_VERSION_HEADER} response header.`);
	throw new TypeError(`Unsupported message stream version: ${version}.`);
}

//#endregion
//#region src/shared/eve-route-path.ts
const EVE_NAMED_AGENT_MOUNT_PATTERN = /^\/eve\/[a-z0-9][a-z0-9_-]*$/;
const EVE_NAMED_AGENT_PROTOCOL_PATTERN = /^\/eve\/[a-z0-9][a-z0-9_-]*\/v1$/;
function joinEveRoutePath(basePath, routePath) {
	const base = trimTrailingSlash$1(basePath);
	const route = routePath.startsWith("/") ? routePath : `/${routePath}`;
	if (route === "/eve/v1" || route.startsWith(`${"/eve/v1"}/`)) {
		if (EVE_NAMED_AGENT_MOUNT_PATTERN.test(base)) return `${base}${route.slice(4)}`;
		if (EVE_NAMED_AGENT_PROTOCOL_PATTERN.test(base)) return `${base}${route.slice(EVE_ROUTE_PREFIX.length)}`;
	}
	return `${base}${route}`;
}
function trimTrailingSlash$1(value) {
	if (value === "/") return "";
	return value.endsWith("/") ? value.slice(0, -1) : value;
}

//#endregion
//#region src/client/url.ts
function createClientUrl(host, routePath, searchParams) {
	const queryIndex = routePath.indexOf("?");
	const pathOnly = queryIndex === -1 ? routePath : routePath.slice(0, queryIndex);
	const embeddedQuery = queryIndex === -1 ? "" : routePath.slice(queryIndex + 1);
	const normalizedRoute = pathOnly.startsWith("/") ? pathOnly : `/${pathOnly}`;
	if (isAbsoluteUrl(host)) {
		const url = new URL(host);
		const basePath = trimTrailingSlash(url.pathname);
		url.pathname = joinEveRoutePath(basePath, normalizedRoute);
		mergeEmbeddedQuery(url.searchParams, embeddedQuery);
		mergeSearchParams(url.searchParams, searchParams);
		url.hash = "";
		return url.toString();
	}
	const url = new URL(host, "http://eve.local");
	const basePath = trimTrailingSlash(url.pathname);
	mergeEmbeddedQuery(url.searchParams, embeddedQuery);
	mergeSearchParams(url.searchParams, searchParams);
	return `${joinEveRoutePath(basePath, normalizedRoute)}${formatSearch(url.searchParams)}`;
}
function mergeEmbeddedQuery(target, embeddedQuery) {
	if (embeddedQuery.length === 0) return;
	for (const [name, value] of new URLSearchParams(embeddedQuery)) target.append(name, value);
}
function isAbsoluteUrl(value) {
	return /^[a-z][a-z\d+\-.]*:/i.test(value);
}
function trimTrailingSlash(value) {
	if (value === "/") return "";
	return value.endsWith("/") ? value.slice(0, -1) : value;
}
function mergeSearchParams(target, searchParams) {
	if (searchParams === void 0) return;
	for (const [name, value] of Object.entries(searchParams)) target.set(name, value);
}
function formatSearch(searchParams) {
	const value = searchParams.toString();
	return value.length === 0 ? "" : `?${value}`;
}

//#endregion
//#region src/client/open-stream.ts
const DEFAULT_STREAM_READ_IDLE_TIMEOUT_MS = 15e3;
const DEFAULT_STREAM_RECONNECT_POLICY = {
	retryableErrorStatuses: /* @__PURE__ */ new Set([
		404,
		409,
		425,
		500,
		502,
		503,
		504
	]),
	streamIdleReconnectPolicy: {
		baseDelayMs: 250,
		maxAttempts: 5,
		maxDelayMs: 4e3
	},
	streamOpenReconnectPolicy: {
		baseDelayMs: 250,
		maxAttempts: 12,
		maxDelayMs: 5e3
	}
};
const NO_STREAM_RECONNECT_POLICY = {
	...DEFAULT_STREAM_RECONNECT_POLICY,
	streamIdleReconnectPolicy: {
		...DEFAULT_STREAM_RECONNECT_POLICY.streamIdleReconnectPolicy,
		maxAttempts: 0
	},
	streamOpenReconnectPolicy: {
		...DEFAULT_STREAM_RECONNECT_POLICY.streamOpenReconnectPolicy,
		maxAttempts: 1
	}
};
function resolveRetryPolicy(policy, defaults) {
	return {
		...defaults,
		...policy
	};
}
function resolveStreamReconnectPolicy(policy, keepAlive = false) {
	if (policy && "reconnect" in policy && policy.reconnect === false) return NO_STREAM_RECONNECT_POLICY;
	const configured = policy;
	return {
		retryableErrorStatuses: configured?.retryableErrorStatuses ? new Set(configured.retryableErrorStatuses) : DEFAULT_STREAM_RECONNECT_POLICY.retryableErrorStatuses,
		streamIdleReconnectPolicy: resolveRetryPolicy(configured?.streamIdleReconnectPolicy, {
			...DEFAULT_STREAM_RECONNECT_POLICY.streamIdleReconnectPolicy,
			maxAttempts: keepAlive ? Infinity : DEFAULT_STREAM_RECONNECT_POLICY.streamIdleReconnectPolicy.maxAttempts
		}),
		streamOpenReconnectPolicy: resolveRetryPolicy(configured?.streamOpenReconnectPolicy, DEFAULT_STREAM_RECONNECT_POLICY.streamOpenReconnectPolicy)
	};
}
async function* followStreamIterable(input) {
	if (input.follow === false && input.startIndex < 0) throw new Error("stream({ follow: false }) requires a nonnegative startIndex; a tail-relative cursor cannot be bounded.");
	const resolvePolicy = () => resolveStreamReconnectPolicy(input.resolveReconnectPolicy === void 0 ? input.streamReconnectPolicy : input.resolveReconnectPolicy(), input.keepAlive);
	let retryPolicy = resolvePolicy();
	let idleRetryPolicy = retryPolicy.streamIdleReconnectPolicy;
	let startIndex = input.startIndex;
	let reconnectDelayMs = idleRetryPolicy.baseDelayMs;
	let idleReconnects = 0;
	let initialConnection = true;
	let tailIndex;
	let caughtUp = false;
	while (true) {
		retryPolicy = resolvePolicy();
		idleRetryPolicy = retryPolicy.streamIdleReconnectPolicy;
		let connection;
		try {
			connection = await openStreamBody({
				...input,
				retryPolicy,
				startIndex,
				requestTailIndex: (input.follow === false || input.onCaughtUp !== void 0) && tailIndex === void 0
			});
		} catch (error) {
			if (input.signal?.aborted) return;
			throw error;
		}
		if ((input.follow === false || input.onCaughtUp !== void 0) && tailIndex === void 0) {
			tailIndex = connection.tailIndex;
			if (tailIndex === void 0) {
				connection.close();
				throw new Error(`stream({ follow: false }) requires the server to report the ${EVE_STREAM_TAIL_INDEX_HEADER} header. The agent may be running an older eve version.`);
			}
		}
		if (!caughtUp && tailIndex !== void 0 && startIndex > tailIndex) {
			caughtUp = true;
			input.onCaughtUp?.();
		}
		if (input.follow === false && tailIndex !== void 0 && startIndex > tailIndex) {
			connection.close();
			return;
		}
		let deliveredEvent = false;
		let leaseEnded = false;
		try {
			for await (const event of readNdjsonStream(connection.body, {
				signal: input.signal,
				controlVersion: connection.controlVersion,
				idleTimeoutMs: input.streamReadIdleTimeoutMs ?? DEFAULT_STREAM_READ_IDLE_TIMEOUT_MS,
				onLeaseEnded: () => {
					leaseEnded = true;
				},
				streamVersion: connection.streamVersion
			})) {
				startIndex += 1;
				deliveredEvent = true;
				reconnectDelayMs = idleRetryPolicy.baseDelayMs;
				idleReconnects = 0;
				yield event;
				if (!caughtUp && tailIndex !== void 0 && startIndex > tailIndex) {
					caughtUp = true;
					input.onCaughtUp?.();
				}
				if (input.follow === false && tailIndex !== void 0 && startIndex > tailIndex) return;
			}
		} catch (error) {
			if (!isStreamDisconnectError(error)) throw error;
		} finally {
			connection.close();
		}
		idleRetryPolicy = resolvePolicy().streamIdleReconnectPolicy;
		if (input.signal?.aborted || input.startIndex < 0 || idleRetryPolicy.maxAttempts === 0) return;
		if (leaseEnded) continue;
		if (!deliveredEvent && !initialConnection && (idleReconnects += 1) >= idleRetryPolicy.maxAttempts) return;
		initialConnection = false;
		await sleep(reconnectDelayMs, input.signal);
		if (input.signal?.aborted) return;
		reconnectDelayMs = Math.min(reconnectDelayMs * 2, idleRetryPolicy.maxDelayMs);
	}
}
async function openStreamBody(input) {
	const retryPolicy = input.retryPolicy ?? resolveStreamReconnectPolicy(input.streamReconnectPolicy, input.keepAlive);
	const openRetryPolicy = retryPolicy.streamOpenReconnectPolicy;
	let lastStatus;
	let lastBody;
	let lastHeaders;
	let retryDelayMs = openRetryPolicy.baseDelayMs;
	const controlVersion = input.startIndex >= 0 && retryPolicy.streamIdleReconnectPolicy.maxAttempts > 0 ? "1" : void 0;
	const searchParams = {};
	if (controlVersion !== void 0) searchParams[EVE_STREAM_CONTROL_VERSION_QUERY] = controlVersion;
	if (input.startIndex !== 0) searchParams.startIndex = String(input.startIndex);
	if (input.requestTailIndex === true) searchParams.includeTailIndex = "1";
	for (let attempt = 0; attempt < openRetryPolicy.maxAttempts; attempt += 1) {
		input.signal?.throwIfAborted();
		const url = createClientUrl(input.host, createEveSessionStreamRoutePath(input.sessionId), Object.keys(searchParams).length > 0 ? searchParams : void 0);
		const headers = await input.resolveHeaders();
		input.signal?.throwIfAborted();
		const connectionController = new AbortController();
		const signal = input.signal ? AbortSignal.any([input.signal, connectionController.signal]) : connectionController.signal;
		let response;
		try {
			response = await fetch(url, {
				cache: "no-store",
				headers,
				redirect: input.redirect,
				signal
			});
		} catch (error) {
			if (input.signal?.aborted || !isStreamDisconnectError(error) || attempt === openRetryPolicy.maxAttempts - 1) throw error;
			await sleep(retryDelayMs, input.signal);
			retryDelayMs = Math.min(retryDelayMs * 2, openRetryPolicy.maxDelayMs);
			continue;
		}
		if (response.ok) {
			if (!response.body) throw new ClientError(response.status, "Response body is null.", response.headers);
			let closed = false;
			return {
				body: response.body,
				close: () => {
					if (closed) return;
					closed = true;
					response.body?.cancel().catch(() => {});
					connectionController.abort();
				},
				controlVersion,
				streamVersion: readMessageStreamVersion(response.headers),
				tailIndex: parseTailIndexHeader(response.headers)
			};
		}
		lastStatus = response.status;
		lastBody = await response.text();
		lastHeaders = response.headers;
		if (!retryPolicy.retryableErrorStatuses.has(response.status)) throw new ClientError(response.status, lastBody, response.headers);
		if (attempt < openRetryPolicy.maxAttempts - 1) {
			await sleep(retryDelayMs, input.signal);
			retryDelayMs = Math.min(retryDelayMs * 2, openRetryPolicy.maxDelayMs);
		}
	}
	throw new ClientError(lastStatus ?? 0, lastBody ?? "Failed to open message stream.", lastHeaders);
}
function parseTailIndexHeader(headers) {
	const raw = headers.get(EVE_STREAM_TAIL_INDEX_HEADER);
	if (raw === null || !/^-?\d+$/.test(raw)) return;
	const parsed = Number(raw);
	return Number.isSafeInteger(parsed) ? parsed : void 0;
}
async function sleep(ms, signal) {
	if (signal?.aborted) return;
	await new Promise((resolve) => {
		const onAbort = () => {
			clearTimeout(timer);
			resolve();
		};
		const timer = setTimeout(() => {
			signal?.removeEventListener("abort", onAbort);
			resolve();
		}, ms);
		signal?.addEventListener("abort", onAbort, { once: true });
	});
}

//#endregion
//#region src/protocol/cancel-turn.ts
const CancelTurnResponseSchema = z.discriminatedUnion("status", [z.strictObject({
	ok: z.literal(true),
	sessionId: z.string().min(1),
	status: z.literal("accepted")
}), z.strictObject({
	ok: z.literal(true),
	status: z.literal("no_active_turn")
})]);

//#endregion
//#region src/protocol/clear-session.ts
const ClearResponseSchema = z.discriminatedUnion("status", [z.object({
	ok: z.literal(true),
	sessionId: z.string().min(1),
	status: z.literal("accepted")
}), z.object({
	ok: z.literal(true),
	status: z.literal("no_active_session")
})]);

//#endregion
//#region src/protocol/compact-session.ts
const CompactResponseSchema = z.discriminatedUnion("status", [z.object({
	ok: z.literal(true),
	sessionId: z.string().min(1),
	status: z.literal("accepted")
}), z.object({
	ok: z.literal(true),
	status: z.literal("no_active_session")
})]);

//#endregion
//#region src/protocol/reset-session.ts
const ResetResponseSchema = z.discriminatedUnion("status", [z.object({
	ok: z.literal(true),
	previousSessionId: z.string().min(1),
	status: z.literal("reset")
}), z.object({
	ok: z.literal(true),
	status: z.literal("no_active_session")
})]);

//#endregion
//#region src/client/session-controls.ts
async function cancelClientSession(input) {
	const { signal, ...body } = input.options ?? {};
	const { payload, response } = await postJson({
		body,
		context: input.context,
		operation: "Cancel",
		path: createEveSessionCancelRoutePath(input.sessionId),
		signal
	});
	const result = CancelTurnResponseSchema.safeParse(payload);
	if (!result.success || result.data.status === "accepted" && result.data.sessionId !== input.sessionId) throw new Error(`Cancel route returned an invalid response (${response.status}).`);
	return result.data.status === "accepted" ? {
		sessionId: result.data.sessionId,
		status: "accepted"
	} : { status: "no_active_turn" };
}
async function clearClientSession(input) {
	const { payload } = await postJson({
		context: input.context,
		operation: "Clear",
		path: createEveSessionClearRoutePath(input.sessionId)
	});
	const result = ClearResponseSchema.safeParse(payload);
	if (!result.success || result.data.status === "accepted" && result.data.sessionId !== input.sessionId) throw new Error("Clear route returned an invalid response.");
	return result.data.status === "accepted" ? {
		sessionId: result.data.sessionId,
		status: "accepted"
	} : { status: "no_active_session" };
}
async function compactClientSession(input) {
	const { payload } = await postJson({
		context: input.context,
		operation: "Compact",
		path: createEveSessionCompactRoutePath(input.sessionId)
	});
	const result = CompactResponseSchema.safeParse(payload);
	if (!result.success || result.data.status === "accepted" && result.data.sessionId !== input.sessionId) throw new Error("Compact route returned an invalid response.");
	return result.data.status === "accepted" ? {
		sessionId: result.data.sessionId,
		status: "accepted"
	} : { status: "no_active_session" };
}
async function resetClientSession(input) {
	const { signal, ...body } = input.options ?? {};
	const { payload } = await postJson({
		body,
		context: input.context,
		operation: "Reset",
		path: createEveSessionResetRoutePath(input.sessionId),
		signal
	});
	const result = ResetResponseSchema.safeParse(payload);
	if (!result.success || result.data.status === "reset" && result.data.previousSessionId !== input.sessionId) throw new Error("Reset route returned an invalid response.");
	return result.data.status === "reset" ? {
		previousSessionId: result.data.previousSessionId,
		status: "reset"
	} : { status: "no_active_session" };
}
async function postJson(input) {
	const headers = await input.context.resolveHeaders();
	headers.set("content-type", "application/json");
	const response = await fetch(createClientUrl(input.context.host, input.path), withRedirectPolicy$1({
		body: input.body === void 0 ? void 0 : JSON.stringify(input.body),
		headers,
		method: "POST",
		signal: input.signal
	}, input.context.redirect));
	const text = await response.text();
	if (!response.ok) throw new ClientError(response.status, text, response.headers);
	try {
		return {
			payload: JSON.parse(text),
			response
		};
	} catch {
		throw new Error(`${input.operation} route returned invalid JSON (${response.status}).`);
	}
}
function withRedirectPolicy$1(init, redirect) {
	return redirect === void 0 ? init : {
		...init,
		redirect
	};
}

//#endregion
//#region src/shared/json.ts
const INVALID_JSON_VALUE_CANDIDATE = Symbol("invalid-json-value-candidate");
const JSON_VALUE_ERROR_MESSAGE = "Expected a JSON-serializable value.";
const JSON_OBJECT_ERROR_MESSAGE = "Expected a JSON-serializable object.";
function parseJsonValue(value) {
	const normalized = normalizeJsonValueCandidate(value);
	if (normalized === INVALID_JSON_VALUE_CANDIDATE) throw new TypeError(JSON_VALUE_ERROR_MESSAGE);
	return normalized;
}
function parseJsonObject(value) {
	const normalized = parseJsonValue(value);
	if (!isJsonObjectValue(normalized)) throw new TypeError(JSON_OBJECT_ERROR_MESSAGE);
	return normalized;
}
function normalizeJsonValueCandidate(value, seen = /* @__PURE__ */ new WeakSet()) {
	if (value === null || typeof value === "boolean" || typeof value === "string") return value;
	if (typeof value === "number") return Number.isFinite(value) ? value : INVALID_JSON_VALUE_CANDIDATE;
	if (Array.isArray(value)) {
		const normalizedItems = [];
		for (const item of value) {
			const normalizedItem = normalizeJsonValueCandidate(item, seen);
			if (normalizedItem === INVALID_JSON_VALUE_CANDIDATE) return INVALID_JSON_VALUE_CANDIDATE;
			normalizedItems.push(normalizedItem);
		}
		return normalizedItems;
	}
	if (typeof value !== "object" || value === void 0) return INVALID_JSON_VALUE_CANDIDATE;
	if (!isPlainObject(value)) return INVALID_JSON_VALUE_CANDIDATE;
	if (seen.has(value)) return INVALID_JSON_VALUE_CANDIDATE;
	seen.add(value);
	const normalized = {};
	for (const [key, entry] of Object.entries(value)) {
		if (entry === void 0) continue;
		const normalizedEntry = normalizeJsonValueCandidate(entry, seen);
		if (normalizedEntry === INVALID_JSON_VALUE_CANDIDATE) return INVALID_JSON_VALUE_CANDIDATE;
		normalized[key] = normalizedEntry;
	}
	seen.delete(value);
	return normalized;
}
function isJsonObjectValue(value) {
	return value !== null && !Array.isArray(value) && typeof value === "object";
}
function isPlainObject(value) {
	const prototype = Object.getPrototypeOf(value);
	return prototype === null || Object.getPrototypeOf(prototype) === null;
}

//#endregion
//#region src/tools/schema.ts
const JSON_SCHEMA_TARGET = "draft-07";
function serializeOutputSchema(source) {
	return serializeSchema(source, "output");
}
const UNSPECIFIED_INPUT_SCHEMA = z.fromJSONSchema({});
function serializeSchema(source, direction) {
	if (source === null || source === void 0) return source;
	return toJsonObject(source, direction);
}
function toJsonObject(source, direction) {
	const standard = getStandardSchemaProperties(source);
	const jsonSchema = standard?.jsonSchema;
	const emit = typeof jsonSchema === "object" && jsonSchema !== null ? jsonSchema[direction] : void 0;
	const vendor = typeof standard?.vendor === "string" ? standard.vendor : "unknown";
	if (standard !== void 0 && typeof emit !== "function" && vendor === "zod") {
		if (direction === "input") {
			const schema = asSchema(source);
			const { $schema: _schemaVersion, ...canonical } = parseJsonObject(schema.jsonSchema);
			return canonical;
		}
		throw new Error("Zod 3 cannot emit an output JSON Schema. Upgrade to Zod 4 or provide a plain JSON Schema object.");
	}
	if (standard !== void 0 && typeof emit !== "function") throw new Error(`Standard Schema vendor "${vendor}" does not support JSON Schema conversion. Provide a Standard Schema implementation with JSON Schema conversion or a plain JSON Schema object.`);
	const { $schema: _schemaVersion, ...canonical } = standard === void 0 ? parseJsonObject(source) : parseJsonObject(emit({ target: JSON_SCHEMA_TARGET }));
	return canonical;
}
function getStandardSchemaProperties(value) {
	if (typeof value !== "object" || value === null || !("~standard" in value)) return void 0;
	const standard = value["~standard"];
	return typeof standard === "object" && standard !== null ? standard : void 0;
}

//#endregion
//#region src/client/session.ts
const SESSION_SEND_RETRY_BASE_DELAY_MS = 250;
const SESSION_SEND_RETRY_MAX_DELAY_MS = 2e3;
const SESSION_SEND_READY_TIMEOUT_MS = 2e4;
const followSession = Symbol("followClientSession");
var ClientSession = class ClientSession {
	#context;
	#state;
	constructor(context, state) {
		this.#context = context;
		this.#state = state;
	}
	static async create(context, input) {
		const response = await postTurn(context, EVE_SESSION_ROUTE_PATH, input, true);
		const { sessionId } = await readAcceptedMessage(response);
		const session = new ClientSession(context, {
			sessionId,
			streamIndex: 0
		});
		return {
			response: session.#messageResponse(response, input, 0),
			session
		};
	}
	static async prewarm(context, options = {}) {
		const { sessionId } = await readAcceptedMessage(await postCreateSession(context, options));
		return new ClientSession(context, {
			sessionId,
			streamIndex: 0
		});
	}
	get state() {
		return this.#state;
	}
	async snapshot(options) {
		options?.signal?.throwIfAborted();
		const events = [];
		for await (const event of this.#readStream({
			follow: false,
			signal: options?.signal,
			startIndex: 0
		})) events.push(event);
		options?.signal?.throwIfAborted();
		return {
			events,
			session: {
				sessionId: this.#state.sessionId,
				streamIndex: events.length
			}
		};
	}
	async send(message, options = {}) {
		return await this.#send({
			...options,
			message
		}, true);
	}
	async respond(inputResponses, options = {}) {
		if (inputResponses.length === 0) throw new Error("ClientSession.respond() requires at least one input response.");
		return await this.#send({
			...options,
			inputResponses
		}, false);
	}
	async #send(input, retrySessionNotReady) {
		const initialStreamIndex = this.#state.streamIndex;
		const path = createEveSessionRoutePath(this.#state.sessionId);
		const response = retrySessionNotReady ? await postSessionSend(this.#context, path, input) : await postTurn(this.#context, path, input, false);
		const { sessionId: responseSessionId, deliveryId } = await readAcceptedMessage(response, this.#state.sessionId);
		if (responseSessionId !== this.#state.sessionId) throw new Error("Message route returned a different session id.");
		if (input.message !== void 0 && deliveryId === void 0) throw new Error("Message route did not return a delivery id. Update the server before sending with this client.");
		return this.#messageResponse(response, input, initialStreamIndex, input.message === void 0 ? void 0 : deliveryId);
	}
	async cancel(options) {
		return await cancelClientSession({
			context: this.#context,
			options,
			sessionId: this.#state.sessionId
		});
	}
	async clear() {
		return await clearClientSession({
			context: this.#context,
			sessionId: this.#state.sessionId
		});
	}
	async compact() {
		return await compactClientSession({
			context: this.#context,
			sessionId: this.#state.sessionId
		});
	}
	async reset(options) {
		return await resetClientSession({
			context: this.#context,
			options,
			sessionId: this.#state.sessionId
		});
	}
	stream(options) {
		if (options?.follow === false && (options.startIndex ?? this.#state.streamIndex) < 0) throw new Error("stream({ follow: false }) requires a nonnegative startIndex; a tail-relative cursor cannot be bounded.");
		return this.#streamAndAdvance(options);
	}
	[followSession](options) {
		return this.#streamAndAdvance({
			...options,
			keepAlive: true
		});
	}
	#messageResponse(response, input, initialStreamIndex, deliveryId) {
		response.body?.cancel().catch(() => {});
		return new MessageResponse({
			cancelTurn: async (turnId) => await this.cancel({ turnId }),
			createStream: (source) => this.#createEventStream(initialStreamIndex, input, deliveryId, source),
			deliveryId,
			sessionId: this.#state.sessionId
		});
	}
	async *#createEventStream(initialStreamIndex, input, deliveryId, source) {
		let eventCount = 0;
		let started = deliveryId === void 0;
		let reachedBoundary = false;
		const pendingAuthorizations = /* @__PURE__ */ new Set();
		try {
			for await (const event of source ?? this.#readStream({
				headers: input.headers,
				keepAlive: true,
				signal: input.signal,
				startIndex: initialStreamIndex,
				streamReconnectPolicy: input.streamReconnectPolicy
			})) {
				eventCount += 1;
				if (deliveryId !== void 0) {
					const matches = event.meta?.deliveryIds?.includes(deliveryId) === true;
					const terminal = event.type === "session.failed" || event.type === "session.completed";
					if (!matches && terminal && (!started || event.type === "session.completed")) throw new Error("The session ended before the accepted message reached its turn boundary.");
					if (!started && !matches) continue;
					if (!terminal && event.meta?.deliveryIds !== void 0 && !matches) continue;
					started = true;
				}
				updatePendingAuthorizations(pendingAuthorizations, event);
				reachedBoundary = isCurrentTurnBoundaryEvent(event) && (event.type !== "session.waiting" || pendingAuthorizations.size === 0);
				yield event;
				if (reachedBoundary) break;
			}
			if (deliveryId !== void 0 && !reachedBoundary && !input.signal?.aborted) throw new Error("The response stream ended before the accepted message reached its turn boundary.");
		} finally {
			this.#advanceStreamIndex(initialStreamIndex + eventCount);
		}
	}
	async *#streamAndAdvance(options) {
		const startIndex = options?.startIndex ?? this.#state.streamIndex;
		let eventCount = 0;
		for await (const event of this.#readStream({
			follow: options?.follow,
			headers: options?.headers,
			keepAlive: options?.keepAlive,
			onCaughtUp: options?.onCaughtUp,
			resolveHeaders: options?.resolveHeaders,
			resolveReconnectPolicy: options?.resolveReconnectPolicy,
			signal: options?.signal,
			startIndex,
			streamReconnectPolicy: options?.streamReconnectPolicy
		})) {
			eventCount += 1;
			if (startIndex >= 0) this.#advanceStreamIndex(startIndex + eventCount);
			yield event;
		}
	}
	#advanceStreamIndex(streamIndex) {
		this.#state = {
			sessionId: this.#state.sessionId,
			streamIndex: Math.max(this.#state.streamIndex, streamIndex)
		};
	}
	#readStream(input) {
		return followStreamIterable({
			onCaughtUp: input.onCaughtUp,
			follow: input.follow,
			host: this.#context.host,
			keepAlive: input.keepAlive,
			resolveHeaders: () => this.#context.resolveHeaders(input.resolveHeaders?.() ?? input.headers),
			redirect: this.#context.redirect,
			sessionId: this.#state.sessionId,
			signal: input.signal,
			startIndex: input.startIndex,
			streamReconnectPolicy: input.streamReconnectPolicy,
			resolveReconnectPolicy: input.resolveReconnectPolicy
		});
	}
};
function followClientSession(session, options) {
	return session[followSession](options);
}
async function postSessionSend(context, path, input) {
	const readyDeadline = Date.now() + SESSION_SEND_READY_TIMEOUT_MS;
	let retryDelayMs = SESSION_SEND_RETRY_BASE_DELAY_MS;
	for (;;) {
		try {
			return await postTurn(context, path, input, false);
		} catch (error) {
			if (!isSessionNotReady(error)) throw error;
			const remainingMs = readyDeadline - Date.now();
			if (remainingMs <= 0) throw error;
			await sleep(Math.min(retryDelayMs, remainingMs), input.signal);
		}
		input.signal?.throwIfAborted();
		retryDelayMs = Math.min(retryDelayMs * 2, SESSION_SEND_RETRY_MAX_DELAY_MS);
	}
}
async function postCreateSession(context, options) {
	const headers = await context.resolveHeaders(options.headers);
	const response = await fetch(createClientUrl(context.host, EVE_SESSION_ROUTE_PATH), {
		headers,
		method: "POST",
		redirect: context.redirect,
		signal: options.signal ?? null
	});
	if (!response.ok) {
		const responseBody = await response.text();
		throw new ClientError(response.status, responseBody, response.headers);
	}
	return response;
}
function isSessionNotReady(error) {
	return error instanceof ClientError && error.status === 409 && error.code === "session_not_ready";
}
async function postTurn(context, path, input, requireMessage) {
	const body = createMessageBody(input, requireMessage);
	if (body === null) throw new Error(requireMessage ? "Creating a session requires a non-empty message." : "A session turn requires a non-empty message or inputResponses.");
	const headers = await context.resolveHeaders(input.headers);
	headers.set("content-type", "application/json");
	const response = await fetch(createClientUrl(context.host, path), {
		body: JSON.stringify(body),
		headers,
		method: "POST",
		redirect: context.redirect,
		signal: input.signal ?? null
	});
	if (!response.ok) {
		const responseBody = await response.text();
		throw new ClientError(response.status, responseBody, response.headers);
	}
	return response;
}
async function readAcceptedMessage(response, expected) {
	const payload = await response.json();
	const sessionId = (typeof payload.sessionId === "string" ? payload.sessionId : void 0) ?? response.headers.get("x-eve-session-id")?.trim() ?? expected;
	if (!sessionId) throw new Error("Message route did not return a session id.");
	return {
		sessionId,
		deliveryId: typeof payload.deliveryId === "string" && payload.deliveryId.length > 0 ? payload.deliveryId : void 0
	};
}
function createMessageBody(input, requireMessage) {
	const body = {};
	if (input.message !== void 0) body.message = input.message;
	if (input.inputResponses !== void 0 && input.inputResponses.length > 0) body.inputResponses = input.inputResponses;
	if (!requireMessage && input.message !== void 0 && input.turnPolicy !== void 0) body.turnPolicy = input.turnPolicy;
	if (input.message !== void 0 && input.taskDeliveryPolicy !== void 0) body.taskDeliveryPolicy = input.taskDeliveryPolicy;
	if (input.clientContext !== void 0) body.clientContext = input.clientContext;
	const outputSchema = serializeOutputSchema(input.outputSchema);
	if (outputSchema !== void 0) body.outputSchema = outputSchema;
	if (requireMessage && body.message === void 0) return null;
	if (body.message === void 0 && body.inputResponses === void 0) return null;
	return body;
}

//#endregion
//#region src/client/sessions.ts
var ClientSessions = class {
	#context;
	constructor(context) {
		this.#context = context;
	}
	async create(input = {}) {
		if ("message" in input) return await ClientSession.create(this.#context, input);
		return { session: await ClientSession.prewarm(this.#context, input) };
	}
	attach(sessionId, options) {
		if (sessionId.length === 0) throw new Error("sessionId must be a non-empty string.");
		return new ClientSession(this.#context, {
			sessionId,
			streamIndex: options?.streamIndex ?? 0
		});
	}
};

//#endregion
//#region src/client/types.ts
const VERCEL_TRUSTED_OIDC_IDP_TOKEN_HEADER = "x-vercel-trusted-oidc-idp-token";

//#endregion
//#region src/client/client.ts
var Client = class {
	#auth;
	#headers;
	#host;
	#redirect;
	sessions;
	constructor(options) {
		this.#host = options.host;
		this.#auth = options.auth;
		this.#headers = options.headers;
		this.#redirect = options.redirect;
		this.sessions = new ClientSessions({
			host: this.#host,
			redirect: this.#redirect,
			resolveHeaders: (perRequest) => this.#resolveHeaders(perRequest)
		});
	}
	async health() {
		const url = createClientUrl(this.#host, EVE_HEALTH_ROUTE_PATH);
		const headers = await this.#resolveHeaders();
		const response = await fetch(url, withRedirectPolicy({ headers }, this.#redirect));
		if (!response.ok) {
			const body = await response.text();
			throw new ClientError(response.status, body, response.headers);
		}
		let payload;
		try {
			payload = await response.json();
		} catch {
			throw new HealthResponseError();
		}
		const result = HealthResultSchema.safeParse(payload);
		if (!result.success) throw new HealthResponseError(result.error.issues.slice(0, 5).map((issue) => {
			const path = issue.path.join(".");
			return path.length === 0 ? issue.message : `${path}: ${issue.message}`;
		}));
		return result.data;
	}
	async info(options = {}) {
		const response = await this.fetch(EVE_INFO_ROUTE_PATH, options);
		if (!response.ok) {
			const body = await response.text();
			throw new ClientError(response.status, body, response.headers);
		}
		let payload;
		try {
			payload = await response.json();
		} catch {
			throw new AgentInfoResponseError();
		}
		const result = AgentInfoResultSchema.safeParse(payload);
		if (!result.success) throw new AgentInfoResponseError(result.error.issues.slice(0, 5).map((issue) => {
			const path = issue.path.join(".");
			return path.length === 0 ? issue.message : `${path}: ${issue.message}`;
		}));
		return result.data;
	}
	async fetch(path, init = {}) {
		const url = createClientUrl(this.#host, path);
		const headers = await this.#resolveHeaders(headersInitToRecord(init.headers));
		return await fetch(url, withRedirectPolicy({
			...init,
			headers
		}, this.#redirect));
	}
	async #resolveHeaders(perRequest) {
		const headers = new Headers();
		const [baseHeaders, authHeaders] = await Promise.all([resolveHeadersValue(this.#headers), this.#resolveAuthHeaders()]);
		for (const [key, value] of Object.entries(baseHeaders)) headers.set(key, value);
		for (const [key, value] of Object.entries(authHeaders)) headers.set(key, value);
		if (perRequest) for (const [key, value] of Object.entries(perRequest)) headers.set(key, value);
		return headers;
	}
	async #resolveAuthHeaders() {
		const auth = this.#auth;
		if (!auth) return {};
		if ("vercelOidc" in auth) {
			const token = (await resolveTokenValue(auth.vercelOidc.token)).trim();
			if (token.length === 0) return {};
			return {
				authorization: `Bearer ${token}`,
				[VERCEL_TRUSTED_OIDC_IDP_TOKEN_HEADER]: token
			};
		}
		if ("bearer" in auth) {
			const token = (await resolveTokenValue(auth.bearer)).trim();
			return token.length === 0 ? {} : { authorization: `Bearer ${token}` };
		}
		if ("basic" in auth) {
			const password = await resolveTokenValue(auth.basic.password);
			return { authorization: `Basic ${encodeBasicCredentials(auth.basic.username, password)}` };
		}
		return {};
	}
};
async function resolveTokenValue(value) {
	return typeof value === "function" ? value() : value;
}
async function resolveHeadersValue(value) {
	if (value === void 0) return {};
	return typeof value === "function" ? await value() : value;
}
function headersInitToRecord(headers) {
	if (headers === void 0) return {};
	return Object.fromEntries(new Headers(headers).entries());
}
function withRedirectPolicy(init, redirect) {
	return redirect === void 0 ? init : {
		...init,
		redirect
	};
}

//#endregion
//#region src/client/session-event-stream.ts
var SessionEventStream = class {
	#controller = new AbortController();
	#readers = /* @__PURE__ */ new Set();
	#caughtUp = Promise.withResolvers();
	caughtUp = this.#caughtUp.promise;
	#ended = false;
	#error;
	#headers;
	#reconnectPolicy;
	constructor(session, options) {
		this.setOptions(options);
		this.caughtUp.catch(() => {});
		if (!options.catchUp) this.#caughtUp.resolve();
		(async () => {
			try {
				for await (const event of followClientSession(session, {
					signal: this.#controller.signal,
					resolveHeaders: () => this.#headers,
					resolveReconnectPolicy: () => this.#reconnectPolicy,
					startIndex: options.startIndex,
					onCaughtUp: options.catchUp ? () => this.#caughtUp.resolve() : void 0
				})) {
					if (this.#controller.signal.aborted) return;
					options.onEvent(event);
					for (const reader of this.#readers) reader.push(event);
					if (event.type === "session.completed" || event.type === "session.failed") break;
				}
				this.#caughtUp.resolve();
				this.#finish();
			} catch (error) {
				this.#caughtUp.reject(error);
				this.#finish(error);
				if (!this.#controller.signal.aborted) options.onError(error);
			}
		})();
	}
	subscribe(signal) {
		const reader = new SessionEventReader(() => this.#readers.delete(reader), signal);
		if (this.#ended) reader.end(this.#error);
		else this.#readers.add(reader);
		return reader;
	}
	get ended() {
		return this.#ended;
	}
	setOptions(options) {
		if ("headers" in options) this.#headers = options.headers;
		if ("streamReconnectPolicy" in options) this.#reconnectPolicy = options.streamReconnectPolicy;
	}
	close() {
		const error = new DOMException("Session stream was detached.", "AbortError");
		this.#controller.abort(error);
		this.#caughtUp.reject(error);
		this.#finish(error);
	}
	#finish(error) {
		if (this.#ended) return;
		this.#ended = true;
		this.#error = error;
		for (const reader of this.#readers) reader.end(error);
	}
};
var SessionEventReader = class {
	#events = [];
	#wake = Promise.withResolvers();
	#ended = false;
	#error;
	#dispose;
	constructor(unsubscribe, signal) {
		const abort = () => this.end(signal?.reason);
		signal?.addEventListener("abort", abort, { once: true });
		this.#dispose = () => {
			signal?.removeEventListener("abort", abort);
			unsubscribe();
		};
		if (signal?.aborted) abort();
	}
	push(event) {
		if (this.#ended) return;
		this.#events.push(event);
		this.#wake.resolve();
	}
	end(error) {
		if (this.#ended) return;
		this.#ended = true;
		this.#error = error;
		this.#wake.resolve();
	}
	[Symbol.dispose]() {
		this.end();
		this.#events = [];
		this.#dispose();
	}
	discard() {
		this.#events = [];
	}
	async *[Symbol.asyncIterator]() {
		for (;;) {
			while (this.#events.length > 0) yield this.#events.shift();
			if (this.#ended) {
				if (this.#error !== void 0) throw this.#error;
				return;
			}
			this.#wake = Promise.withResolvers();
			await this.#wake.promise;
		}
	}
};

//#endregion
//#region src/client/eve-agent-projection.ts
var EveAgentProjection = class {
	#reducer;
	#events;
	#data;
	constructor(reducer, events) {
		this.#reducer = reducer;
		this.#events = events;
		this.#data = this.#reduce();
	}
	get data() {
		return this.#data;
	}
	reset() {
		this.#events = [];
		this.#data = this.#reducer.initial();
	}
	append(event) {
		this.#events = [...this.#events, event];
		this.#data = this.#reducer.reduce(this.#data, event);
	}
	remove(predicate) {
		this.#events = this.#events.filter((event) => !predicate(event));
		this.#data = this.#reduce();
	}
	replace(predicate, replacement) {
		const index = this.#events.findIndex(predicate);
		this.#events = index === -1 ? [...this.#events, replacement] : this.#events.map((event, i) => i === index ? replacement : event);
		this.#data = this.#reduce();
	}
	#reduce() {
		let data = this.#reducer.initial();
		for (const event of this.#events) data = this.#reducer.reduce(data, event);
		return data;
	}
};

//#endregion
//#region src/client/eve-agent-store-helpers.ts
function isSettledSessionTail(events) {
	const tail = events.at(-1);
	return tail !== void 0 && isCurrentTurnBoundaryEvent(tail) && (tail.type !== "session.waiting" || collectPendingAuthorizations(events).size === 0);
}
function collectPendingAuthorizations(events) {
	const pending = /* @__PURE__ */ new Set();
	for (const event of events) updatePendingAuthorizations(pending, event);
	return pending;
}
function assertExclusiveTurnInput(input) {
	if (input.message !== void 0 === (input.inputResponses !== void 0)) throw new Error("A turn requires exactly one of message or inputResponses.");
}
let submissionSequence = 0;
function createSubmissionId() {
	const randomUUID = globalThis.crypto?.randomUUID;
	if (randomUUID !== void 0) return randomUUID.call(globalThis.crypto);
	submissionSequence += 1;
	return `submission_${submissionSequence.toString()}`;
}
function createAbortSignal(first, second) {
	return first ? AbortSignal.any([first, second]) : second;
}
function summarizeUserContent(message) {
	if (typeof message === "string") return message;
	const parts = [];
	for (const part of message) if (part.type === "text") parts.push(part.text);
	else if (part.type === "file") parts.push(part.filename ? `[file: ${part.filename}]` : "[file]");
	return parts.join("\n");
}
function isAbortError(error) {
	return error instanceof Error && error.name === "AbortError";
}
function toTerminalStreamFailureError(event) {
	if (event.type !== "session.failed") return void 0;
	const error = new Error(event.data.message);
	error.name = event.data.code;
	return error;
}
function createActiveTurn(cancel) {
	const response = Promise.withResolvers();
	const completion = Promise.withResolvers();
	const turn = {
		abortController: new AbortController(),
		acceptedFollowUps: 0,
		cancel: () => cancel(turn),
		completion: completion.promise,
		followUpDispatches: /* @__PURE__ */ new Set(),
		receivedFollowUps: 0,
		receivedFollowUpEvents: /* @__PURE__ */ new Map(),
		followUpSubmissionIds: /* @__PURE__ */ new Set(),
		resolveCompletion: completion.resolve,
		response: response.promise,
		resolveResponse: response.resolve
	};
	return turn;
}
async function followSteeredTurns(turn, events, isActive) {
	while (turn.followUpDispatches.size > 0) await Promise.allSettled(turn.followUpDispatches);
	if (turn.receivedFollowUps >= turn.acceptedFollowUps) return;
	for await (const event of events) {
		if (!isActive()) return;
		turn.receivedFollowUps += turn.receivedFollowUpEvents.get(event) ?? 0;
		turn.receivedFollowUpEvents.delete(event);
		if (isCurrentTurnBoundaryEvent(event)) {
			while (turn.followUpDispatches.size > 0) await Promise.allSettled(turn.followUpDispatches);
			if (turn.receivedFollowUps >= turn.acceptedFollowUps) return;
		}
	}
}
async function waitWithSignal(promise, signal) {
	if (signal === void 0) return await promise;
	const aborted = Promise.withResolvers();
	const onAbort = () => aborted.reject(signal.reason);
	signal.addEventListener("abort", onAbort, { once: true });
	if (signal.aborted) onAbort();
	try {
		return await Promise.race([aborted.promise, promise]);
	} finally {
		signal.removeEventListener("abort", onAbort);
	}
}

//#endregion
//#region src/client/optimistic-message-submissions.ts
var OptimisticMessageSubmissions = class {
	#optimistic;
	#projection;
	#pending = [];
	constructor(projection, optimistic) {
		this.#projection = projection;
		this.#optimistic = optimistic;
	}
	reset() {
		this.#pending = [];
	}
	submit(input, eventStartIndex) {
		if (input.message === void 0) return void 0;
		const pending = {
			createdAt: Date.now(),
			eventStartIndex,
			id: createSubmissionId(),
			message: summarizeUserContent(input.message),
			requiresDeliveryId: true
		};
		this.#pending = [...this.#pending, pending];
		if (this.#optimistic) this.#projection.append({
			data: {
				createdAt: pending.createdAt,
				message: pending.message,
				submissionId: pending.id
			},
			type: "client.message.submitted"
		});
		return pending.id;
	}
	apply(event) {
		if (event.type !== "message.received") {
			this.#projection.append(event);
			return;
		}
		if (event.data.kind === "execution.background_task") {
			this.#projection.append(event);
			return;
		}
		const matching = this.#matching(event);
		if (matching.length === 0) {
			this.#projection.append(event);
			return;
		}
		return this.#reconcile(matching, event, false);
	}
	correlate(submissionId, deliveryId, events) {
		if (submissionId === void 0) return void 0;
		this.#pending = this.#pending.map((pending) => pending.id === submissionId ? {
			...pending,
			deliveryId,
			requiresDeliveryId: deliveryId !== void 0
		} : pending);
		const pending = this.#pending.find((candidate) => candidate.id === submissionId);
		if (pending === void 0) return void 0;
		for (const event of events.slice(pending.eventStartIndex)) {
			if (event.type !== "message.received" || event.data.kind === "execution.background_task") continue;
			const matching = this.#matching(event);
			if (matching.some((candidate) => candidate.id === submissionId)) return this.#reconcile(matching, event, true);
		}
	}
	fail(error, submissionId) {
		const pending = submissionId === void 0 ? this.#pending[0] : this.#pending.find((candidate) => candidate.id === submissionId);
		if (pending === void 0) return;
		this.#pending = this.#pending.filter((candidate) => candidate.id !== pending.id);
		this.#projection.replace((event) => event.type === "client.message.submitted" && event.data.submissionId === pending.id, {
			data: {
				createdAt: pending.createdAt,
				error: { message: error.message },
				message: pending.message,
				submissionId: pending.id
			},
			type: "client.message.failed"
		});
	}
	failAll(error) {
		for (const pending of this.#pending) this.fail(error, pending.id);
	}
	#matching(event) {
		return this.#pending.filter((pending) => pending.deliveryId === void 0 ? !pending.requiresDeliveryId : event.meta.deliveryIds?.includes(pending.deliveryId) === true);
	}
	#reconcile(submissions, event, alreadyProjected) {
		const ids = submissions.map((pending) => pending.id);
		const idSet = new Set(ids);
		this.#pending = this.#pending.filter((pending) => !idSet.has(pending.id));
		if (alreadyProjected) this.#projection.remove((candidate) => candidate.type === "client.message.submitted" && idSet.has(candidate.data.submissionId));
		else {
			this.#projection.replace((candidate) => candidate.type === "client.message.submitted" && candidate.data.submissionId === ids[0], event);
			this.#projection.remove((candidate) => candidate.type === "client.message.submitted" && idSet.has(candidate.data.submissionId));
		}
		return {
			alreadyProjected,
			event,
			ids
		};
	}
};

//#endregion
//#region src/protocol/event-dedupe.ts
function createEventDeduper() {
	const seen = /* @__PURE__ */ new Set();
	return {
		admit(event) {
			const id = event.meta?.id;
			if (id === void 0) return true;
			if (seen.has(id)) return false;
			seen.add(id);
			return true;
		},
		get size() {
			return seen.size;
		}
	};
}

//#endregion
//#region src/client/eve-agent-store.ts
const detachStore = Symbol("detachEveAgentStore");
const attachStore = Symbol("attachEveAgentStore");
var EveAgentStore = class {
	#client;
	#autoPrewarm;
	#attached = false;
	#stream;
	#pendingAuthorizations = /* @__PURE__ */ new Set();
	#externalSession;
	#optimistic;
	#projection;
	#subscribers = /* @__PURE__ */ new Set();
	#seenEvents = createEventDeduper();
	#activeTurn;
	#callbacks = {};
	#error;
	#events;
	#messageSubmissions;
	#prewarmGeneration = 0;
	#prewarmPromise;
	#prewarmController;
	#resumePromise;
	#session;
	#snapshot;
	#status = "ready";
	constructor(init) {
		this.#autoPrewarm = init.prewarm ?? false;
		this.#externalSession = init.session !== void 0;
		this.#client = this.#externalSession ? void 0 : new Client({
			auth: init.auth,
			headers: init.headers,
			host: init.host ?? ""
		});
		const initialEvents = [];
		for (const event of init.initialEvents ?? []) {
			if (this.#seenEvents.admit(event)) initialEvents.push(event);
			updatePendingAuthorizations(this.#pendingAuthorizations, event);
		}
		this.#events = initialEvents;
		this.#projection = new EveAgentProjection(init.reducer, this.#events);
		this.#optimistic = init.optimistic ?? true;
		this.#messageSubmissions = new OptimisticMessageSubmissions(this.#projection, this.#optimistic);
		this.#session = init.session ?? (init.initialSession === void 0 ? void 0 : this.#client?.sessions.attach(init.initialSession.sessionId, { streamIndex: init.initialSession.streamIndex }));
		this.#snapshot = this.#createSnapshot();
	}
	get snapshot() {
		return this.#snapshot;
	}
	setCallbacks(callbacks) {
		this.#callbacks = callbacks;
	}
	subscribe(callback) {
		this.#subscribers.add(callback);
		return () => {
			this.#subscribers.delete(callback);
		};
	}
	prewarm() {
		if (this.#prewarmPromise !== void 0) return this.#prewarmPromise;
		if (this.#session !== void 0 || this.#externalSession) return Promise.resolve();
		if (this.#activeTurn !== void 0) return this.#activeTurn.response.then((response) => {
			if (response === void 0) throw this.#error ?? new DOMException("Session creation was aborted.", "AbortError");
		});
		const client = this.#client;
		if (client === void 0) return Promise.reject(/* @__PURE__ */ new Error("This eve agent store does not own a session client."));
		const generation = this.#prewarmGeneration;
		const controller = new AbortController();
		this.#prewarmController = controller;
		const promise = (async () => {
			try {
				const created = await client.sessions.create({ signal: controller.signal });
				if (generation !== this.#prewarmGeneration) return;
				this.#session = created.session;
				this.#error = void 0;
				if (this.#status === "error") this.#status = "ready";
				this.#callbacks.onSessionChange?.(created.session.state);
				this.#publish();
				this.#ensureStream();
			} catch (error) {
				if (generation === this.#prewarmGeneration && this.#activeTurn === void 0 && this.#error === void 0) {
					this.#error = toError(error);
					this.#status = "error";
					this.#callbacks.onError?.(this.#error);
					this.#publish();
				}
				throw error;
			}
		})();
		this.#prewarmPromise = promise;
		const clear = () => {
			if (this.#prewarmPromise === promise) {
				this.#prewarmPromise = void 0;
				this.#prewarmController = void 0;
			}
		};
		promise.then(clear, clear);
		return promise;
	}
	async send(input) {
		return await this.#submit(input, this.#callbacks.prepareSend);
	}
	async #submit(input, prepareSend) {
		if (this.#activeTurn !== void 0) {
			if (this.#status === "resuming") throw new Error("eve session is resuming.");
			return await this.#sendFollowUp(this.#activeTurn, input, prepareSend);
		}
		const turn = createActiveTurn((turn) => turn.acceptedFollowUps > 0 && this.#session !== void 0 ? this.#session.cancel() : turn.response.then((response) => response === void 0 ? { status: "no_active_turn" } : response.cancel()));
		this.#activeTurn = turn;
		this.#error = void 0;
		this.#status = "submitted";
		this.#publish();
		let reader;
		try {
			const preparedInput = await (prepareSend === void 0 ? input : waitWithSignal(Promise.resolve(prepareSend(input)), createAbortSignal(input.signal, turn.abortController.signal)));
			assertExclusiveTurnInput(preparedInput);
			if (!this.#isActiveTurn(turn)) return;
			const submissionId = this.#messageSubmissions.submit(preparedInput, this.#events.length);
			this.#projectInputResponses(preparedInput);
			this.#publish();
			const turnInput = {
				...preparedInput,
				signal: createAbortSignal(preparedInput.signal, turn.abortController.signal)
			};
			const dispatched = await this.#dispatchTurn(turnInput);
			const response = dispatched.response;
			reader = dispatched.reader;
			if (!this.#isActiveTurn(turn)) return;
			turn.resolveResponse(response);
			if (this.#handleReconciliation(this.#messageSubmissions.correlate(submissionId, getMessageResponseDeliveryId(response), this.#events))) this.#publish();
			for await (const event of consumeMessageResponse(response, reader)) {
				if (!this.#isActiveTurn(turn)) return;
				turn.receivedFollowUps += turn.receivedFollowUpEvents.get(event) ?? 0;
				turn.receivedFollowUpEvents.delete(event);
			}
			if (!this.#isActiveTurn(turn)) return;
			await followSteeredTurns(turn, reader, () => this.#isActiveTurn(turn));
			if (!this.#isActiveTurn(turn)) return;
			this.#status = this.#error === void 0 ? "ready" : "error";
		} catch (error) {
			if (!this.#isActiveTurn(turn)) return;
			if (isAbortError(error)) {
				this.#status = "ready";
				this.#messageSubmissions.fail(toError(error));
			} else {
				const reported = this.#error !== void 0;
				this.#error ??= toError(error);
				this.#status = "error";
				this.#messageSubmissions.fail(this.#error);
				if (!reported) this.#callbacks.onError?.(this.#error);
			}
		} finally {
			reader?.[Symbol.dispose]();
			this.#finishTurn(turn);
		}
	}
	resume() {
		if (this.#resumePromise !== void 0) return this.#resumePromise;
		const promise = this.#resume();
		this.#resumePromise = promise;
		const clear = () => {
			if (this.#resumePromise === promise) this.#resumePromise = void 0;
		};
		promise.then(clear, clear);
		return promise;
	}
	async #resume() {
		if (this.#status === "resuming" || this.#status === "streaming" || this.#status === "submitted") throw new Error("eve session is already processing a turn.");
		if (this.#session === void 0) throw new Error("An eve session is required before resuming.");
		const session = this.#session;
		const turn = createActiveTurn(() => session.cancel());
		this.#activeTurn = turn;
		turn.resolveResponse(void 0);
		this.#error = void 0;
		this.#status = "resuming";
		this.#publish();
		let reader;
		try {
			const stream = this.#ensureStream({
				catchUp: true,
				startIndex: this.#events.length === session.state.streamIndex ? session.state.streamIndex : 0
			});
			reader = stream.subscribe(turn.abortController.signal);
			await stream.caughtUp;
			if (!this.#isActiveTurn(turn)) return;
			reader.discard();
			const tail = this.#events.at(-1);
			if (tail !== void 0) this.#applyTerminalStreamFailure(tail);
			if (tail !== void 0 && this.#error === void 0 && !isSettledSessionTail(this.#events)) {
				this.#status = "streaming";
				this.#publish();
				for await (const event of reader) {
					if (!this.#isActiveTurn(turn)) return;
					turn.receivedFollowUps += turn.receivedFollowUpEvents.get(event) ?? 0;
					turn.receivedFollowUpEvents.delete(event);
					if (isCurrentTurnBoundaryEvent(event) && this.#pendingAuthorizations.size === 0) break;
				}
			}
			await followSteeredTurns(turn, reader, () => this.#isActiveTurn(turn));
			if (this.#isActiveTurn(turn)) this.#status = this.#error === void 0 ? "ready" : "error";
		} catch (error) {
			if (!this.#isActiveTurn(turn)) return;
			if (isAbortError(error)) this.#status = "ready";
			else {
				this.#error = toError(error);
				this.#status = "error";
				this.#callbacks.onError?.(this.#error);
			}
		} finally {
			reader?.[Symbol.dispose]();
			this.#finishTurn(turn);
		}
	}
	cancel() {
		const turn = this.#activeTurn;
		if (turn === void 0) return this.#status === "streaming" && this.#session !== void 0 ? this.#session.cancel() : Promise.resolve({ status: "no_active_turn" });
		return turn.cancel();
	}
	[attachStore]() {
		this.#attached = true;
		if (this.#autoPrewarm && this.#session === void 0) this.prewarm().catch(() => {});
	}
	[detachStore]() {
		this.#attached = false;
		this.#stream?.close();
		this.#stream = void 0;
		this.#activeTurn?.abortController.abort();
		this.#resetPrewarm();
		this.#resumePromise = void 0;
	}
	reset() {
		this.#stream?.close();
		this.#stream = void 0;
		this.#pendingAuthorizations.clear();
		const turn = this.#activeTurn;
		this.#activeTurn = void 0;
		turn?.resolveResponse(void 0);
		turn?.resolveCompletion();
		turn?.abortController.abort();
		this.#resetPrewarm();
		this.#resumePromise = void 0;
		if (!this.#externalSession) this.#session = void 0;
		this.#events = [];
		this.#seenEvents = createEventDeduper();
		this.#messageSubmissions.reset();
		this.#projection.reset();
		this.#error = void 0;
		this.#status = "ready";
		this.#callbacks.onSessionChange?.(this.#session?.state);
		this.#publish();
		if (this.#autoPrewarm && this.#attached) this.prewarm().catch(() => {});
	}
	async #sendFollowUp(turn, input, prepareSend) {
		if (input.message === void 0 || input.turnPolicy !== "steer") throw new Error("eve session is already processing a turn. Send a message with turnPolicy: \"steer\" to guide it at the next boundary.");
		const generation = this.#prewarmGeneration;
		const signal = createAbortSignal(input.signal, turn.abortController.signal);
		const preparedInput = await waitWithSignal(Promise.resolve(prepareSend?.(input)), signal) ?? input;
		if (generation !== this.#prewarmGeneration) return;
		assertExclusiveTurnInput(preparedInput);
		if (preparedInput.message === void 0 || preparedInput.turnPolicy !== "steer") throw new Error("An in-flight follow-up requires a message with turnPolicy: \"steer\".");
		if (!this.#isActiveTurn(turn)) return await this.#submit(preparedInput);
		const submissionId = this.#messageSubmissions.submit(preparedInput, this.#events.length);
		if (submissionId !== void 0) turn.followUpSubmissionIds.add(submissionId);
		this.#publish();
		this.#ensureStream({
			headers: preparedInput.headers,
			streamReconnectPolicy: preparedInput.streamReconnectPolicy
		});
		let dispatch;
		dispatch = (async () => {
			try {
				const signal = createAbortSignal(preparedInput.signal, turn.abortController.signal);
				await waitWithSignal(turn.response, signal);
				if (!this.#isActiveTurn(turn) || this.#session === void 0) throw new Error("The active eve turn ended before the follow-up could be sent.");
				const { message, ...options } = preparedInput;
				const response = await this.#session.send(message, {
					...options,
					signal
				});
				turn.acceptedFollowUps += 1;
				if (this.#handleReconciliation(this.#messageSubmissions.correlate(submissionId, getMessageResponseDeliveryId(response), this.#events))) this.#publish();
			} catch (error) {
				if (this.#isActiveTurn(turn)) {
					this.#messageSubmissions.fail(toError(error), submissionId);
					this.#publish();
				}
				throw error;
			} finally {
				turn.followUpDispatches.delete(dispatch);
			}
		})();
		turn.followUpDispatches.add(dispatch);
		await dispatch;
		await turn.completion;
	}
	async #dispatchTurn(input) {
		const streamOptions = {
			headers: input.headers,
			streamReconnectPolicy: input.streamReconnectPolicy
		};
		if (this.#prewarmPromise !== void 0) {
			await waitWithSignal(this.#prewarmPromise.catch((error) => {
				if (this.#session !== void 0) throw error;
			}), input.signal);
			input.signal?.throwIfAborted();
		}
		if (this.#session === void 0) {
			if (this.#client === void 0) throw new Error("An external eve session is required before sending.");
			if (input.message === void 0) throw new Error("Cannot answer an input request before the session starts.");
			const created = await this.#client.sessions.create({
				...input,
				message: input.message
			});
			input.signal?.throwIfAborted();
			this.#session = created.session;
			this.#callbacks.onSessionChange?.(created.session.state);
			this.#publish();
			return {
				response: created.response,
				reader: this.#ensureStream(streamOptions).subscribe(input.signal)
			};
		}
		const reader = this.#ensureStream(streamOptions).subscribe(input.signal);
		try {
			if (input.inputResponses === void 0) {
				const { message, ...options } = input;
				return {
					response: await this.#session.send(message, options),
					reader
				};
			}
			const { inputResponses, ...options } = input;
			return {
				response: await this.#session.respond(inputResponses, options),
				reader
			};
		} catch (error) {
			reader[Symbol.dispose]();
			throw error;
		}
	}
	#ensureStream(options = {}) {
		if (this.#stream !== void 0 && !this.#stream.ended) {
			this.#stream.setOptions(options);
			return this.#stream;
		}
		if (this.#session === void 0) throw new Error("A session is required before opening its stream.");
		const session = this.#session;
		const generation = this.#prewarmGeneration;
		this.#stream = new SessionEventStream(session, {
			...options,
			onEvent: (event) => {
				if (generation === this.#prewarmGeneration) this.#acceptServerEvent(event);
			},
			onError: (error) => {
				if (generation !== this.#prewarmGeneration) return;
				this.#stream = void 0;
				if (this.#activeTurn !== void 0) return;
				this.#error = toError(error);
				this.#status = "error";
				this.#callbacks.onError?.(this.#error);
				this.#publish();
			}
		});
		return this.#stream;
	}
	#resetPrewarm() {
		this.#prewarmGeneration += 1;
		this.#prewarmController?.abort();
		this.#prewarmController = void 0;
		this.#prewarmPromise = void 0;
	}
	#finishTurn(turn) {
		if (!this.#isActiveTurn(turn)) return;
		turn.resolveResponse(void 0);
		this.#activeTurn = void 0;
		try {
			this.#callbacks.onSessionChange?.(this.#session?.state);
			this.#publish();
			this.#callbacks.onFinish?.(this.#snapshot);
		} finally {
			turn.resolveCompletion();
		}
	}
	#isActiveTurn(turn) {
		return this.#activeTurn === turn;
	}
	#projectInputResponses(input) {
		if (input.inputResponses === void 0 || input.inputResponses.length === 0) return;
		this.#projection.append({
			data: {
				createdAt: Date.now(),
				responses: input.inputResponses
			},
			type: "client.input.responded"
		});
	}
	#acceptServerEvent(event) {
		if (!this.#seenEvents.admit(event)) return;
		const wasStreaming = this.#status === "streaming";
		updatePendingAuthorizations(this.#pendingAuthorizations, event);
		this.#events = [...this.#events, event];
		this.#handleReconciliation(this.#messageSubmissions.apply(event));
		this.#callbacks.onEvent?.(event);
		this.#applyTerminalStreamFailure(event);
		const settled = isCurrentTurnBoundaryEvent(event) && this.#pendingAuthorizations.size === 0;
		if (this.#status !== "resuming" && this.#error === void 0) {
			if ("data" in event && "turnId" in event.data) this.#status = "streaming";
			if (this.#activeTurn === void 0 && settled) this.#status = "ready";
		}
		this.#callbacks.onSessionChange?.(this.#session?.state);
		this.#publish();
		if (this.#activeTurn === void 0 && wasStreaming && settled) this.#callbacks.onFinish?.(this.#snapshot);
	}
	#handleReconciliation(reconciliation) {
		if (reconciliation === void 0) return false;
		let followed = 0;
		for (const id of reconciliation.ids) if (this.#activeTurn?.followUpSubmissionIds.delete(id)) followed += 1;
		if (followed > 0 && this.#activeTurn !== void 0) {
			if (reconciliation.alreadyProjected) this.#activeTurn.receivedFollowUps += followed;
			else {
				const previous = this.#activeTurn.receivedFollowUpEvents.get(reconciliation.event) ?? 0;
				this.#activeTurn.receivedFollowUpEvents.set(reconciliation.event, previous + followed);
			}
		}
		return true;
	}
	#applyTerminalStreamFailure(event) {
		const error = toTerminalStreamFailureError(event);
		if (error === void 0) return;
		this.#status = "error";
		this.#messageSubmissions.failAll(error);
		if (this.#error === void 0) {
			this.#error = error;
			this.#callbacks.onError?.(error);
		}
	}
	#createSnapshot() {
		return {
			data: this.#projection.data,
			error: this.#error,
			events: this.#events,
			session: this.#session?.state,
			status: this.#status
		};
	}
	#publish() {
		this.#snapshot = this.#createSnapshot();
		for (const subscriber of this.#subscribers) subscriber();
	}
};
function detachEveAgentStore(store) {
	store[detachStore]();
}
function attachEveAgentStore(store) {
	store[attachStore]();
}

//#endregion
//#region src/client/agent-host.ts
const AGENT_NAME_PATTERN = /^[a-z0-9][a-z0-9_-]*$/;
const EVE_NAMED_AGENT_ROUTE_PREFIX = "/eve";
function resolveEveAgentHost(input) {
	if (input.agent === void 0) return input.host ?? "";
	if (input.host !== void 0) throw new Error("useEveAgent cannot combine agent and host. Use one target option.");
	assertValidAgentName(input.agent);
	return `${EVE_NAMED_AGENT_ROUTE_PREFIX}/${input.agent}`;
}
function assertValidAgentName(name) {
	if (!AGENT_NAME_PATTERN.test(name)) throw new Error(`eve agent name ${JSON.stringify(name)} is invalid. Use lowercase letters, numbers, underscores, or hyphens, starting with a letter or number.`);
}

//#endregion
//#region src/client/authorization-message-parts.ts
function createAuthorizationRequiredPart(event) {
	const displayName = event.data.authorization?.displayName ?? formatAuthorizationDisplayName(event.data.name);
	return {
		authorization: event.data.authorization,
		description: normalizeAuthorizationDescription(event.data.description, event.data.name, displayName),
		displayName,
		name: event.data.name,
		state: "required",
		stepIndex: event.data.stepIndex,
		turnId: event.data.turnId,
		type: "authorization"
	};
}
function createAuthorizationCompletedPart(event, existing) {
	const displayName = event.data.authorization?.displayName ?? existing?.displayName ?? formatAuthorizationDisplayName(event.data.name);
	return {
		authorization: existing?.authorization || event.data.authorization ? {
			...existing?.authorization,
			...event.data.authorization
		} : void 0,
		description: existing?.description ?? buildCompletedAuthorizationDescription(displayName, event.data.outcome, event.data.reason),
		displayName,
		name: event.data.name,
		outcome: event.data.outcome,
		reason: event.data.reason,
		state: "completed",
		stepIndex: existing?.stepIndex ?? event.data.stepIndex,
		turnId: existing?.turnId ?? event.data.turnId,
		type: "authorization"
	};
}
function buildCompletedAuthorizationDescription(displayName, outcome, reason) {
	if (outcome === "authorized") return `${displayName} connected.`;
	return `${displayName} authorization ${outcome}${reason !== void 0 ? ` (${reason})` : ""}.`;
}
function normalizeAuthorizationDescription(description, name, displayName) {
	if (description === `Authorization required for ${name}`) return `Authorization required for ${displayName}`;
	return description;
}
function formatAuthorizationDisplayName(name) {
	if (name.length === 0) return name;
	return `${name.charAt(0).toUpperCase()}${name.slice(1)}`;
}

//#endregion
//#region src/client/message-action-parts.ts
function toMessageInputRequest(request) {
	return {
		allowFreeform: request.allowFreeform,
		display: request.display,
		kind: request.kind,
		options: request.options,
		prompt: request.prompt,
		requestId: request.requestId
	};
}
function createToolMetadata(descriptor, extra) {
	return { eve: {
		inputRequest: extra?.inputRequest,
		kind: descriptor.kind,
		name: descriptor.name
	} };
}
function mergeToolMetadata(current, next) {
	const kind = next.eve?.kind ?? current?.eve?.kind ?? "unknown";
	const name = next.eve?.name ?? current?.eve?.name ?? "unknown";
	return { eve: {
		...current?.eve,
		...next.eve,
		inputRequest: next.eve?.inputRequest ?? current?.eve?.inputRequest,
		inputResponse: next.eve?.inputResponse ?? current?.eve?.inputResponse,
		kind,
		name
	} };
}
function approvedApproval(part) {
	if (!part?.approval?.id) return;
	return {
		approved: true,
		id: part.approval.id,
		isAutomatic: part.approval.isAutomatic,
		reason: part.approval.reason
	};
}
function normalizeActionRequest(action) {
	switch (action.kind) {
		case "load-skill": return {
			kind: "load-skill",
			name: "load_skill",
			toolName: "eve:load-skill"
		};
		case "tool-call":
		case "workflow-tool-call": return {
			kind: "tool-call",
			name: action.toolName,
			toolName: action.toolName
		};
		case "subagent-call": return {
			kind: "subagent-call",
			name: action.subagentName,
			toolName: `eve:subagent:${action.subagentName}`
		};
		case "remote-agent-call": return {
			kind: "subagent-call",
			name: action.remoteAgentName,
			toolName: `eve:subagent:${action.remoteAgentName}`
		};
	}
}
function normalizeActionResult(result) {
	switch (result.kind) {
		case "load-skill-result": return {
			kind: "load-skill",
			name: result.name ?? "load_skill",
			toolName: "eve:load-skill"
		};
		case "tool-result": return {
			kind: "tool-call",
			name: result.toolName,
			toolName: result.toolName
		};
		case "subagent-result": return {
			kind: "subagent-call",
			name: result.subagentName,
			toolName: `eve:subagent:${result.subagentName}`
		};
	}
}
function stringifyUnknown(value) {
	if (typeof value === "string") return value;
	try {
		return JSON.stringify(value);
	} catch {
		return "Action failed.";
	}
}

//#endregion
//#region src/client/message-reducer-primitives.ts
function projectReceivedParts(parts, message) {
	return parts?.map((part) => part.type === "text" ? {
		state: "done",
		text: part.text,
		type: "text"
	} : {
		filename: part.filename,
		mediaType: part.mediaType,
		size: part.size,
		type: "file",
		url: part.url
	}) ?? [{
		state: "done",
		text: message,
		type: "text"
	}];
}
function partKey(part) {
	switch (part.type) {
		case "text": return `text:${part.stepIndex ?? 0}`;
		case "reasoning": return `reasoning:${part.stepIndex ?? 0}`;
		case "file": return `file:${part.stepIndex ?? 0}:${part.filename ?? part.url ?? part.mediaType}`;
		case "step-start": return "step-start";
		case "authorization": return `authorization:${part.turnId}:${part.stepIndex}:${part.name}`;
		case "dynamic-tool": return `dynamic-tool:${part.toolCallId}`;
	}
}
function upsertMessage(data, next) {
	const index = data.messages.findIndex((message) => message.id === next.id);
	if (index === -1) return { messages: [...data.messages, next] };
	return { messages: [
		...data.messages.slice(0, index),
		next,
		...data.messages.slice(index + 1)
	] };
}
function removeStreamingToolPartsForTurn(data, turnId) {
	const index = data.messages.findIndex((message) => message.role === "assistant" && message.metadata?.turnId === turnId);
	const message = data.messages[index];
	if (message === void 0) return data;
	return upsertMessage(data, {
		...message,
		parts: message.parts.filter((part) => part.type !== "dynamic-tool" || part.state !== "input-streaming")
	});
}
function optimisticUserMessageId(submissionId) {
	return `optimistic:${submissionId}:user`;
}

//#endregion
//#region src/client/message-run-parts.ts
function append(message, append) {
	const current = latestStreamingRun(message, append.type, append.stepIndex);
	return upsert(message, {
		state: "streaming",
		stepIndex: append.stepIndex,
		text: (current?.text ?? "") + append.delta,
		type: append.type
	});
}
function latestStreamingRun(message, type, stepIndex) {
	for (let index = message.parts.length - 1; index >= 0; index -= 1) {
		const part = message.parts[index];
		if (part?.type === type && part.stepIndex === stepIndex) return part.state === "streaming" ? part : void 0;
	}
}
function upsert(message, next) {
	let lastIndex = -1;
	for (let index = message.parts.length - 1; index >= 0; index -= 1) {
		const part = message.parts[index];
		if (part?.type === next.type && part.stepIndex === next.stepIndex) {
			lastIndex = index;
			break;
		}
	}
	const parts = lastIndex !== -1 && message.parts[lastIndex].state === "streaming" ? [
		...message.parts.slice(0, lastIndex),
		next,
		...message.parts.slice(lastIndex + 1)
	] : [...message.parts, next];
	return {
		...message,
		metadata: {
			...message.metadata,
			status: next.type === "text" && next.state === "done" ? "complete" : "streaming"
		},
		parts
	};
}
const messageRun = {
	append,
	upsert
};

//#endregion
//#region src/client/message-reducer.ts
function receivedMessageEventId(event) {
	return event.meta.id ?? `${event.data.turnId}:${event.data.sequence}`;
}
function defaultMessageReducer() {
	return {
		initial() {
			return { messages: [] };
		},
		reduce(data, event) {
			return reduceMessageData(data, event);
		}
	};
}
function reduceMessageData(data, event) {
	switch (event.type) {
		case "client.message.submitted": return upsertMessage(data, {
			id: optimisticUserMessageId(event.data.submissionId),
			metadata: {
				optimistic: true,
				status: "submitted"
			},
			parts: [{
				type: "text",
				text: event.data.message
			}],
			role: "user"
		});
		case "client.message.failed": return upsertMessage(data, {
			id: optimisticUserMessageId(event.data.submissionId),
			metadata: {
				optimistic: true,
				status: "failed"
			},
			parts: [{
				type: "text",
				text: event.data.message
			}],
			role: "user"
		});
		case "client.input.responded": {
			let next = data;
			for (const response of event.data.responses) next = respondToInputRequest(next, response);
			return next;
		}
		case "input.resolved": {
			let next = data;
			for (const resolution of event.data.resolutions) next = resolveInputRequest(next, resolution);
			return next;
		}
		case "message.received":
			if (event.data.kind === "execution.background_task") return data;
			return upsertMessage(data, {
				id: `${receivedMessageEventId(event)}:user`,
				metadata: {
					status: "complete",
					turnId: event.data.turnId
				},
				parts: projectReceivedParts(event.data.parts, event.data.message),
				role: "user"
			});
		case "step.started": return updateAssistantMessage(data, event.data.turnId, (message) => ensureStepStartPart(message, event.data.stepIndex));
		case "reasoning.appended": return updateAssistantMessage(data, event.data.turnId, (message) => messageRun.append(ensureStepStartPart(message, event.data.stepIndex), {
			delta: event.data.reasoningDelta,
			stepIndex: event.data.stepIndex,
			type: "reasoning"
		}));
		case "reasoning.completed": return updateAssistantMessage(data, event.data.turnId, (message) => messageRun.upsert(ensureStepStartPart(message, event.data.stepIndex), {
			state: "done",
			stepIndex: event.data.stepIndex,
			text: event.data.reasoning,
			type: "reasoning"
		}));
		case "action.input.appended": {
			const existing = findToolPart(data, event.data.callId);
			if (existing !== void 0 && existing.state !== "input-streaming") return data;
			const nextPart = {
				input: void 0,
				inputText: (existing?.state === "input-streaming" ? existing.inputText : "") + event.data.inputTextDelta,
				state: "input-streaming",
				stepIndex: event.data.stepIndex,
				toolCallId: event.data.callId,
				toolMetadata: existing?.toolMetadata ?? { eve: {
					kind: "unknown",
					name: event.data.toolName
				} },
				toolName: event.data.toolName,
				type: "dynamic-tool"
			};
			if (existing !== void 0) return updateToolPart(data, event.data.callId, nextPart);
			return updateAssistantMessage(data, event.data.turnId, (message) => upsertPart(ensureStepStartPart(message, event.data.stepIndex), nextPart));
		}
		case "actions.requested": {
			let next = data;
			for (const action of event.data.actions) {
				const descriptor = normalizeActionRequest(action);
				next = updateAssistantMessage(next, event.data.turnId, (message) => upsertPart(ensureStepStartPart(message, event.data.stepIndex), {
					input: "input" in action ? action.input : void 0,
					state: "input-available",
					stepIndex: event.data.stepIndex,
					toolCallId: action.callId,
					toolMetadata: createToolMetadata(descriptor),
					toolName: descriptor.toolName,
					type: "dynamic-tool"
				}));
			}
			return next;
		}
		case "input.requested": {
			let next = data;
			for (const request of event.data.requests) {
				const descriptor = normalizeActionRequest(request.action);
				next = updateAssistantMessage(next, event.data.turnId, (message) => upsertPart(ensureStepStartPart(message, event.data.stepIndex), {
					approval: { id: request.requestId },
					input: request.action.input,
					state: "approval-requested",
					stepIndex: event.data.stepIndex,
					toolCallId: request.action.callId,
					toolMetadata: createToolMetadata(descriptor, { inputRequest: toMessageInputRequest(request) }),
					toolName: descriptor.toolName,
					type: "dynamic-tool"
				}));
			}
			return next;
		}
		case "approval.candidate": return data;
		case "approval.settled": {
			const existing = findToolPartByApprovalId(data, event.data.requestId);
			if (existing === void 0) return data;
			if (event.data.outcome === "approved") return updateToolPart(data, existing.toolCallId, {
				approval: {
					approved: true,
					id: event.data.requestId,
					reason: void 0
				},
				input: existing.input,
				state: "approval-responded",
				stepIndex: existing.stepIndex,
				toolCallId: existing.toolCallId,
				toolMetadata: existing.toolMetadata,
				toolName: existing.toolName,
				type: "dynamic-tool"
			});
			return updateToolPart(data, existing.toolCallId, {
				approval: {
					approved: false,
					id: event.data.requestId,
					reason: "Tool execution was cancelled."
				},
				input: existing.input,
				state: "output-denied",
				stepIndex: existing.stepIndex,
				toolCallId: existing.toolCallId,
				toolMetadata: existing.toolMetadata,
				toolName: existing.toolName,
				type: "dynamic-tool"
			});
		}
		case "action.result": {
			const descriptor = normalizeActionResult(event.data.result);
			const existing = findToolPart(data, event.data.result.callId);
			const denied = event.data.error?.code === "TOOL_EXECUTION_DENIED";
			const failed = event.data.status === "failed" && !denied;
			const approvalId = existing?.approval?.id ?? event.data.result.callId;
			const toolMetadata = mergeToolMetadata(existing?.toolMetadata, createToolMetadata(descriptor));
			const resultPartBase = {
				input: existing?.input,
				stepIndex: event.data.stepIndex,
				toolCallId: event.data.result.callId,
				toolMetadata,
				toolName: existing?.toolName ?? descriptor.toolName,
				type: "dynamic-tool"
			};
			let nextPart;
			if (denied) nextPart = {
				...resultPartBase,
				approval: {
					approved: false,
					id: approvalId,
					reason: event.data.error?.message
				},
				state: "output-denied"
			};
			else if (failed) nextPart = {
				...resultPartBase,
				approval: approvedApproval(existing),
				errorText: event.data.error?.message ?? stringifyUnknown(event.data.result.output),
				state: "output-error"
			};
			else nextPart = {
				...resultPartBase,
				approval: approvedApproval(existing),
				output: event.data.result.output,
				state: "output-available"
			};
			if (existing !== void 0) return updateToolPart(data, event.data.result.callId, nextPart);
			return updateAssistantMessage(data, event.data.turnId, (message) => upsertPart(ensureStepStartPart(message, event.data.stepIndex), nextPart));
		}
		case "action.partial": {
			const existing = findToolPart(data, event.data.result.callId);
			if (existing !== void 0 && isSettledToolPart(existing)) return data;
			const descriptor = normalizeActionResult(event.data.result);
			const nextPart = {
				approval: approvedApproval(existing),
				input: existing?.input,
				output: event.data.result.output,
				partial: true,
				state: "output-available",
				stepIndex: event.data.stepIndex,
				toolCallId: event.data.result.callId,
				toolMetadata: mergeToolMetadata(existing?.toolMetadata, createToolMetadata(descriptor)),
				toolName: existing?.toolName ?? descriptor.toolName,
				type: "dynamic-tool"
			};
			if (existing !== void 0) return updateToolPart(data, event.data.result.callId, nextPart);
			return updateAssistantMessage(data, event.data.turnId, (message) => upsertPart(ensureStepStartPart(message, event.data.stepIndex), nextPart));
		}
		case "authorization.required": return updateAssistantMessage(data, event.data.turnId, (message) => upsertPart(ensureStepStartPart(message, event.data.stepIndex), createAuthorizationRequiredPart(event)));
		case "authorization.completed": return completeAuthorization(data, event);
		case "message.appended": return updateAssistantMessage(data, event.data.turnId, (message) => messageRun.append(ensureStepStartPart(message, event.data.stepIndex), {
			delta: event.data.messageDelta,
			stepIndex: event.data.stepIndex,
			type: "text"
		}));
		case "message.completed": return updateAssistantMessage(data, event.data.turnId, (message) => {
			if (event.data.message === null) return removeTextPart(message, event.data.stepIndex);
			return messageRun.upsert(ensureStepStartPart(message, event.data.stepIndex), {
				state: "done",
				stepIndex: event.data.stepIndex,
				text: event.data.message,
				type: "text"
			});
		});
		case "result.completed": return updateAssistantMetadata(data, event.data.turnId, { result: event.data.result });
		case "turn.completed": return updateAssistantMessage(data, event.data.turnId, (message) => ({
			...message,
			metadata: {
				...message.metadata,
				status: "complete"
			},
			parts: removeStreamingToolParts(message.parts)
		}));
		case "turn.cancelled": return updateAssistantMessage(data, event.data.turnId, (message) => ({
			...message,
			metadata: {
				...message.metadata,
				status: "complete"
			},
			parts: removeStreamingToolParts(message.parts.map((part) => (part.type === "text" || part.type === "reasoning") && part.state === "streaming" ? {
				...part,
				state: "done"
			} : part))
		}));
		case "turn.failed": return removeStreamingToolPartsForTurn(data, event.data.turnId);
		case "session.failed": return data;
		default: return data;
	}
}
function removeStreamingToolParts(parts) {
	return parts.filter((part) => part.type !== "dynamic-tool" || part.state !== "input-streaming");
}
function respondToInputRequest(data, response) {
	const existing = findToolPartByApprovalId(data, response.requestId);
	if (!existing) return data;
	const approval = { id: response.requestId };
	if (response.text !== void 0) approval.reason = response.text;
	return updateToolPart(data, existing.toolCallId, {
		approval,
		input: existing.input,
		state: "approval-responded",
		stepIndex: existing.stepIndex,
		toolCallId: existing.toolCallId,
		toolMetadata: mergeToolMetadata(existing.toolMetadata, { eve: {
			inputResponse: response,
			kind: existing.toolMetadata?.eve?.kind ?? "unknown",
			name: existing.toolMetadata?.eve?.name ?? existing.toolName
		} }),
		toolName: existing.toolName,
		type: "dynamic-tool"
	});
}
function resolveInputRequest(data, resolution) {
	if (resolution.response !== void 0) return respondToInputRequest(data, resolution.response);
	const existing = findToolPartByApprovalId(data, resolution.requestId);
	if (!existing) return data;
	return updateToolPart(data, existing.toolCallId, {
		input: existing.input,
		output: { status: resolution.outcome },
		state: "output-available",
		stepIndex: existing.stepIndex,
		toolCallId: existing.toolCallId,
		toolMetadata: existing.toolMetadata,
		toolName: existing.toolName,
		type: "dynamic-tool"
	});
}
function updateAssistantMessage(data, turnId, update) {
	const message = data.messages.find((message) => message.role === "assistant" && message.metadata?.turnId === turnId) ?? createAssistantMessage(turnId);
	return upsertMessage(data, update(message));
}
function updateAssistantMetadata(data, turnId, metadata) {
	return updateAssistantMessage(data, turnId, (message) => ({
		...message,
		metadata: {
			...message.metadata,
			...metadata
		}
	}));
}
function createAssistantMessage(turnId) {
	return {
		id: `${turnId}:assistant`,
		metadata: {
			status: "streaming",
			turnId
		},
		parts: [],
		role: "assistant"
	};
}
function ensureStepStartPart(message, stepIndex) {
	const stepStartCount = message.parts.filter((part) => part.type === "step-start").length;
	if (stepStartCount > stepIndex) return message;
	const missingCount = stepIndex - stepStartCount + 1;
	return {
		...message,
		parts: [...message.parts, ...Array.from({ length: missingCount }, () => ({ type: "step-start" }))]
	};
}
function upsertPart(message, next) {
	const index = message.parts.findIndex((part) => partKey(part) === partKey(next));
	const parts = index === -1 ? [...message.parts, next] : [
		...message.parts.slice(0, index),
		next,
		...message.parts.slice(index + 1)
	];
	return {
		...message,
		metadata: {
			...message.metadata,
			status: next.type === "text" && next.state === "done" ? "complete" : "streaming"
		},
		parts
	};
}
function removeTextPart(message, stepIndex) {
	const parts = message.parts.filter((part) => part.type !== "text" || part.stepIndex !== stepIndex);
	if (parts.length === message.parts.length) return message;
	return {
		...message,
		metadata: {
			...message.metadata,
			status: "complete"
		},
		parts
	};
}
function updateToolPart(data, toolCallId, next) {
	const message = data.messages.find((candidate) => candidate.role === "assistant" && candidate.parts.some((part) => part.type === "dynamic-tool" && part.toolCallId === toolCallId));
	if (!message) return data;
	return upsertMessage(data, upsertPart(message, next));
}
function completeAuthorization(data, event) {
	const existing = findLatestPendingAuthorizationPart(data, event.data.name);
	const next = createAuthorizationCompletedPart(event, existing);
	if (existing !== void 0) return updateAuthorizationPart(data, existing, next);
	return updateAssistantMessage(data, event.data.turnId, (message) => upsertPart(ensureStepStartPart(message, event.data.stepIndex), next));
}
function updateAuthorizationPart(data, existing, next) {
	const message = data.messages.find((candidate) => candidate.role === "assistant" && candidate.parts.some((part) => part === existing));
	if (!message) return data;
	return upsertMessage(data, upsertPart(message, next));
}
function findToolPart(data, toolCallId) {
	for (const message of data.messages) for (const part of message.parts) if (part.type === "dynamic-tool" && part.toolCallId === toolCallId) return part;
}
function isSettledToolPart(part) {
	return part.state === "output-denied" || part.state === "output-error" || part.state === "output-available" && part.partial !== true;
}
function findLatestPendingAuthorizationPart(data, name) {
	for (let messageIndex = data.messages.length - 1; messageIndex >= 0; messageIndex -= 1) {
		const message = data.messages[messageIndex];
		if (message?.role !== "assistant") continue;
		for (let partIndex = message.parts.length - 1; partIndex >= 0; partIndex -= 1) {
			const part = message.parts[partIndex];
			if (part?.type === "authorization" && part.state === "required" && part.name === name) return part;
		}
	}
}
function findToolPartByApprovalId(data, approvalId) {
	for (const message of data.messages) for (const part of message.parts) if (part.type === "dynamic-tool" && part.approval?.id === approvalId) return part;
}

//#endregion
//#region src/vue/use-eve-agent.ts
function useEveAgent(options = {}) {
	if (options.resume && options.initialSession === void 0 && options.session === void 0) throw new Error("useEveAgent({ resume: true }) requires initialSession or session.");
	const reducer = options.reducer ?? defaultMessageReducer();
	const store = new EveAgentStore({
		auth: options.auth,
		headers: options.headers,
		host: resolveEveAgentHost({
			agent: options.agent,
			host: options.host
		}),
		initialEvents: options.initialEvents,
		initialSession: options.initialSession,
		optimistic: options.optimistic,
		prewarm: options.prewarm,
		reducer,
		session: options.session
	});
	store.setCallbacks({
		onError: options.onError,
		onEvent: options.onEvent,
		onFinish: options.onFinish,
		onSessionChange: options.onSessionChange,
		prepareSend: options.prepareSend
	});
	const snapshot = shallowRef(store.snapshot);
	if ("window" in globalThis) {
		const unsubscribe = store.subscribe(() => {
			snapshot.value = store.snapshot;
		});
		attachEveAgentStore(store);
		if (options.resume) store.resume();
		onScopeDispose(() => {
			unsubscribe();
			detachEveAgentStore(store);
		});
	}
	return {
		cancel: () => store.cancel(),
		data: computed(() => snapshot.value.data),
		error: computed(() => snapshot.value.error),
		events: computed(() => snapshot.value.events),
		prewarm: () => store.prewarm(),
		reset: () => store.reset(),
		respond: (inputResponses, options) => store.send({
			...options,
			inputResponses
		}),
		resume: () => store.resume(),
		send: (message, options) => store.send({
			...options,
			message
		}),
		session: computed(() => snapshot.value.session),
		status: computed(() => snapshot.value.status)
	};
}

//#endregion
export { defaultMessageReducer as n, useEveAgent as t };