import { createLogger } from "../utils/logger/index.js";
import { init_logger } from "../utils/logger.js";
import { resolveStateDir } from "../config/paths-state.js";
import { expandWorkspacePathString, init_workspace_path } from "../config/workspace-path.js";
import { init_agent_scope, resolveAgentProfileDir } from "./agent-scope.js";
import { init_paths, resolveBundledSkillsDir } from "../config/paths.js";
import { CredentialResolver, init_credentials } from "../auth/credentials.js";
import { getAgentDefaultModelRef, init_schema } from "../config/schema.js";
import { init_sync_provider_auth, resolveProviderApiKeySync } from "../auth/sync-provider-auth.js";
import { applyConfigOverrides } from "../config/runtime-overrides.js";
import { resolveEffectiveAgentProfileForSession } from "../config/agent-profile.js";
import { getApiKeySync, getDefaultModelSync, init_providers, resolveModel } from "../providers/index.js";
import { createExtensionAwareStreamFn } from "../providers/extension-stream-bridge.js";
import { extractTextContent, loadProfileMarkdownFiles } from "./context/workspace.js";
import { resolveBootstrapContextSync } from "./bootstrap/bootstrap-files.js";
import { createSkillConfigManager } from "./skills/config.js";
import { isValidSkillEnvVarName } from "./skills/required-env-vars.js";
import { resolveLocalizedSkillMarkdown, resolveLocalizedSkillMeta } from "./skills/skill-view-path.js";
import { isMemorySubsystemEnabled, shouldRegisterCuratedMemoryTool } from "./memory/memory-config.js";
import { AgentToolsFactory } from "./tools/factory.js";
import { parseMcpToolName } from "./mcp/bundle-mcp-policy.js";
import { disposeAllSessionMcpRuntimes, retireSessionMcpRuntimeForSessionKey } from "./mcp/bundle-mcp-runtime.js";
import "./mcp/bundle-mcp-tools.js";
import { evictAllEmbeddedSessionRunners, evictEmbeddedSessionRunner } from "./embedded/session-runner.js";
import { loadSkillsLock } from "./skills/hub-lock.js";
import { isUnderManagedSkillsDir } from "./skills/managed-store.js";
import { MemoryPrefetchCoordinator } from "./memory/prefetch-coordinator.js";
import { WorkspaceRuntimeRegistry } from "./workspace-runtime/registry.js";
import { BackgroundReviewCoordinator } from "./background-review/coordinator.js";
import { basename, resolve, sep } from "node:path";
import { Agent } from "@earendil-works/pi-agent-core";
//#region src/agent/agent-manager.ts
/**
* Agent Manager - Manages Agent instances per session
*
* Each session gets its own Agent instance for true isolation
* and concurrent processing across sessions.
*/
init_schema();
init_agent_scope();
init_workspace_path();
init_logger();
init_sync_provider_auth();
init_providers();
init_credentials();
init_paths();
const log = createLogger("AgentManager");
var AgentManager = class {
	agents = /* @__PURE__ */ new Map();
	config;
	toolsFactory;
	mergedConfig() {
		const base = this.config.config;
		return base ? applyConfigOverrides(base) : void 0;
	}
	/** Default agent workspace (effective profile for `getDefaultAgentId`). */
	baseWorkspacePath;
	/** Per-session absolute markdown workspace when `SessionAgentConfig.workingDirectoryOverride` is set. */
	sessionWorkspaceOverrides = /* @__PURE__ */ new Map();
	defaultModel;
	credentialCache = /* @__PURE__ */ new Map();
	credentialResolver;
	workspaceRuntimes;
	memoryPrefetch;
	backgroundReview;
	constructor(config) {
		this.config = config;
		this.baseWorkspacePath = this.computeBaseWorkspacePath();
		this.workspaceRuntimes = new WorkspaceRuntimeRegistry({
			getConfig: () => this.config.config,
			bundledSkillsDir: resolveBundledSkillsDir()
		});
		this.memoryPrefetch = new MemoryPrefetchCoordinator({
			getConfig: () => this.config.config,
			getMemoryManagerForSession: (sk) => this.getMemoryManagerForSession(sk),
			getLastAssistantContent: (sk) => this.getLastAssistantContent(sk)
		});
		this.backgroundReview = new BackgroundReviewCoordinator({
			getConfig: () => this.mergedConfig(),
			onSkillsFilesystemMutate: () => this.refreshSkillsAfterDiskChange()
		});
		this.toolsFactory = new AgentToolsFactory(this.buildToolsFactoryDeps());
		this.defaultModel = config.model || getDefaultModelSync(config.config);
		this.credentialResolver = new CredentialResolver();
		this.warmCredentialCache().catch((err) => {
			const em = err instanceof Error ? err.message : String(err);
			log.warn({
				err,
				errorMessage: em
			}, `Credential cache pre-warm failed: ${em}`);
		});
	}
	computeBaseWorkspacePath() {
		const cfg = this.config.config;
		if (!cfg) return expandWorkspacePathString(this.config.workspace);
		return resolveEffectiveAgentProfileForSession(cfg, null).resolvedWorkspacePath;
	}
	/**
	* Workspace root for inbound attachments / side effects for this session's agent id.
	* Uses in-memory session workspace overrides when the session has a persisted `workingDirectoryOverride`.
	*/
	getResolvedWorkspaceForSession(sessionKey) {
		const cfg = this.config.config;
		const fromMap = this.sessionWorkspaceOverrides.get(sessionKey);
		if (fromMap !== void 0) return fromMap;
		return resolveEffectiveAgentProfileForSession(cfg, sessionKey).resolvedWorkspacePath;
	}
	/**
	* Sync in-memory workspace override from session config (after load or PATCH).
	* Pass `null` to clear when the session has no `workingDirectoryOverride` on disk.
	*/
	setSessionWorkspaceOverride(sessionKey, absolutePath) {
		if (absolutePath === null || absolutePath === "") this.sessionWorkspaceOverrides.delete(sessionKey);
		else this.sessionWorkspaceOverrides.set(sessionKey, absolutePath);
	}
	/** Merged `thinkingDefault` for this session's agent id (defaults + `agents.list`). */
	getThinkingDefaultForSession(sessionKey) {
		const cfg = this.mergedConfig();
		if (!cfg) return;
		return resolveEffectiveAgentProfileForSession(cfg, sessionKey).thinkingDefault;
	}
	pickDefaultModelRef() {
		const cfg = this.mergedConfig();
		return getAgentDefaultModelRef(cfg)?.trim() || getDefaultModelSync(cfg);
	}
	resolveModelStringToModel(modelRef) {
		try {
			return resolveModel(modelRef);
		} catch {
			const fallback = getDefaultModelSync(this.mergedConfig());
			log.warn({
				modelRef,
				fallback
			}, "Model not found, using default");
			return resolveModel(fallback);
		}
	}
	/**
	* Keep defaults in sync when config is hot-reloaded or saved from the UI.
	*
	* The previous implementation rebuilt the entire `AgentToolsFactory` (80+ lines
	* of dependency wiring) on every reload. The factory's deps are now built from
	* a single helper ({@link buildToolsFactoryDeps}) and read `this.*` through
	* closures, so existing instances automatically see the new config without
	* reconstruction. The browser is still shut down because its cached settings
	* (headless mode, backend choice) come from the config snapshot at connect time.
	*/
	updateAgentDefaults(config) {
		this.config.config = config;
		const ref = getAgentDefaultModelRef(config);
		this.config.model = ref;
		this.defaultModel = ref || getDefaultModelSync(config);
		this.baseWorkspacePath = this.computeBaseWorkspacePath();
		this.toolsFactory.shutdownBrowser();
		this.workspaceRuntimes.clearAll();
	}
	/**
	* Construct the dep bag passed to `AgentToolsFactory`. Closures reference
	* `this.*` so they remain valid across hot reloads (no rebuild needed).
	*/
	buildToolsFactoryDeps() {
		return {
			workspace: this.baseWorkspacePath,
			extensionRegistry: this.config.extensionRegistry,
			getCurrentContext: this.config.getCurrentContext,
			hookRunner: this.config.hookRunner,
			bus: this.config.bus,
			getConfig: () => this.mergedConfig(),
			getPrimaryModel: () => this.resolveModelStringToModel(this.pickDefaultModelRef()),
			getBuiltinMemoryStore: () => this.workspaceRuntimes.getOrCreate(this.baseWorkspacePath).builtinMemoryStore,
			getMemoryManager: () => this.workspaceRuntimes.getOrCreate(this.baseWorkspacePath).memoryManager,
			getSessionStore: this.config.getSessionStore,
			gatewayClarify: this.config.gatewayClarify,
			getCronService: this.config.getCronService,
			getSkillIndexingContext: () => {
				const ctx = this.config.getCurrentContext?.();
				if (!ctx?.sessionKey) return void 0;
				const inst = this.agents.get(ctx.sessionKey);
				if (!inst) return void 0;
				return {
					registeredToolNames: inst.registeredToolNames,
					skillAllowlist: inst.effectiveProfile.skillsAllowlist
				};
			},
			onSkillsFilesystemMutate: () => {
				this.refreshSkillsAfterDiskChange();
			},
			getSkillPassthroughEnvVarNames: () => {
				const ctx = this.config.getCurrentContext?.();
				if (!ctx?.sessionKey) return [];
				return [...this.agents.get(ctx.sessionKey)?.skillEnvPassthroughKeys ?? []];
			},
			registerSkillEnvPassthrough: (names) => {
				const ctx = this.config.getCurrentContext?.();
				if (!ctx?.sessionKey) return;
				const inst = this.agents.get(ctx.sessionKey);
				if (!inst) return;
				for (const n of names) if (isValidSkillEnvVarName(n)) inst.skillEnvPassthroughKeys.add(n.trim());
			}
		};
	}
	getMemoryManager() {
		return this.workspaceRuntimes.getOrCreate(this.baseWorkspacePath).memoryManager;
	}
	getMemoryManagerForSession(sessionKey) {
		const path = this.getResolvedWorkspaceForSession(sessionKey);
		return this.workspaceRuntimes.getOrCreate(path).memoryManager;
	}
	/**
	* Prefix the user turn with fenced prefetched memory (external providers).
	* Delegates to {@link MemoryPrefetchCoordinator}.
	*/
	applyMemoryPrefetchToUserMessage(userMessage, sessionKey) {
		return this.memoryPrefetch.applyToUserMessage(userMessage, sessionKey);
	}
	/**
	* After a completed turn: sync external providers and queue next-turn prefetch.
	* Delegates to {@link MemoryPrefetchCoordinator}.
	*/
	afterAgentTurn(sessionKey, userPlainText) {
		this.memoryPrefetch.afterTurn(sessionKey, userPlainText);
	}
	/**
	* Call once per user turn before the main `agent.prompt` (via {@link runAgentTurnWithModelFallbacks} `beforeUserPrompt`).
	* Delegates to {@link BackgroundReviewCoordinator}.
	*/
	beginBackgroundReviewUserTurn(sessionKey) {
		const inst = this.agents.get(sessionKey);
		if (!inst) return;
		this.backgroundReview.beginUserTurn(sessionKey, inst.registeredToolNames);
	}
	/**
	* After a successful main turn (after memory sync via `afterAgentTurn`), may run a quiet follow-up for memory/skills.
	* Delegates to {@link BackgroundReviewCoordinator}.
	*/
	scheduleBackgroundReviewAfterUserTurn(sessionKey) {
		const inst = this.agents.get(sessionKey);
		if (!inst) return;
		this.backgroundReview.scheduleAfterUserTurn({
			sessionKey,
			agent: inst.agent,
			registeredToolNames: inst.registeredToolNames,
			skillAllowlist: inst.effectiveProfile.skillsAllowlist,
			workspacePath: inst.resolvedWorkspacePath,
			lastAssistantText: this.getLastAssistantContent(sessionKey),
			workspaceRuntime: this.workspaceRuntimes.getOrCreate(inst.resolvedWorkspacePath)
		});
	}
	/**
	* Expand `/skill:name` user text into the full skill block for the current turn (WebChat, channels).
	*/
	expandSkillUserText(text) {
		const ctx = this.config.getCurrentContext?.();
		const path = ctx?.sessionKey ? this.getResolvedWorkspaceForSession(ctx.sessionKey) : this.baseWorkspacePath;
		return this.workspaceRuntimes.getOrCreate(path).skillManager.expandCommand(text);
	}
	/**
	* Structured SKILL.md preview for the gateway console.
	* When `lang` is provided (e.g. "zh"), tries SKILL-{lang}.md first; falls back to SKILL.md.
	*/
	getSkillMarkdownSource(skillName, lang) {
		const skill = this.workspaceRuntimes.getOrCreate(this.baseWorkspacePath).skillManager.findSkill(skillName);
		if (!skill) return null;
		if (lang) {
			const localized = resolveLocalizedSkillMarkdown(skill, lang);
			if (localized) return localized;
		}
		return {
			name: skill.name,
			description: skill.description,
			bodyMarkdown: skill.content,
			disableModelInvocation: skill.disableModelInvocation,
			metadata: skill.metadata,
			toolConditions: skill.toolConditions,
			requiredEnvVarNames: skill.requiredEnvVarNames
		};
	}
	loadProfileMarkdownForProfile(profile) {
		const cfg = this.config.config;
		return loadProfileMarkdownFiles(resolveAgentProfileDir(cfg, profile.agentId));
	}
	resolveContextFilesForSession(sessionKey, profile, excludeHeartbeat) {
		const cfg = this.config.config;
		const profileDir = resolveAgentProfileDir(cfg, profile.agentId);
		const heartbeatEnabled = cfg.gateway?.heartbeat?.includeSystemPromptSection ?? false;
		const { contextFiles } = resolveBootstrapContextSync({
			profileDir,
			config: cfg,
			sessionKey,
			excludeHeartbeat: excludeHeartbeat ?? !heartbeatEnabled
		});
		return contextFiles;
	}
	getSkillCatalog(lang) {
		const skillsConfig = createSkillConfigManager(resolveStateDir()).load();
		const lock = loadSkillsLock();
		return this.workspaceRuntimes.getOrCreate(this.baseWorkspacePath).skillManager.getSkills().map((s) => {
			const base = resolve(s.baseDir);
			const managed = isUnderManagedSkillsDir(s.baseDir);
			const directoryId = base.split(sep).filter(Boolean).pop() || s.name;
			const enabled = !(skillsConfig.entries?.[s.name]?.enabled === false);
			const hubKey = managed ? basename(base) : "";
			const hub = managed && hubKey ? lock.entries[hubKey] : void 0;
			const localized = lang ? resolveLocalizedSkillMeta(s, lang) : null;
			return {
				directoryId,
				name: localized?.name ?? s.name,
				description: localized?.description ?? s.description,
				category: s.category,
				source: s.source,
				path: s.baseDir,
				managed,
				enabled,
				disableModelInvocation: s.disableModelInvocation,
				...hub ? { hub } : {}
			};
		});
	}
	/**
	* After ~/.xopc/skills.json changes (enable/disable), refresh `<available_skills>` on active agents.
	*/
	refreshSkillsAfterSkillConfigChange() {
		const cfg = this.config.config;
		const touched = /* @__PURE__ */ new Set();
		for (const instance of this.agents.values()) {
			const rt = this.workspaceRuntimes.getOrCreate(instance.resolvedWorkspacePath);
			if (!touched.has(instance.resolvedWorkspacePath)) {
				rt.skillManager.refreshPromptFromConfig();
				touched.add(instance.resolvedWorkspacePath);
			}
			const contextFiles = this.resolveContextFilesForSession(instance.sessionKey, instance.effectiveProfile);
			const newPrompt = rt.systemPromptBuilder.build(contextFiles, {
				externalMemoryInstructions: rt.memoryManager.buildExternalSystemPrompt(),
				workspaceOverride: instance.resolvedWorkspacePath,
				profileMarkdownPathRoot: resolveAgentProfileDir(cfg, instance.effectiveProfile.agentId),
				systemPromptOverride: instance.effectiveProfile.systemPromptOverride,
				skillAllowlist: instance.effectiveProfile.skillsAllowlist,
				registeredToolNames: instance.registeredToolNames
			});
			instance.agent.state.systemPrompt = newPrompt;
		}
		log.info({ agents: this.agents.size }, "Skill toggles applied; system prompt updated");
	}
	/**
	* Reload skills from disk and refresh system prompt on all active Agent instances.
	*/
	refreshSkillsAfterDiskChange() {
		const cfg = this.config.config;
		for (const rt of this.workspaceRuntimes.values()) rt.skillManager.reload();
		const touched = /* @__PURE__ */ new Set();
		for (const instance of this.agents.values()) {
			const rt = this.workspaceRuntimes.getOrCreate(instance.resolvedWorkspacePath);
			if (!touched.has(instance.resolvedWorkspacePath)) touched.add(instance.resolvedWorkspacePath);
			const contextFiles = this.resolveContextFilesForSession(instance.sessionKey, instance.effectiveProfile);
			const newPrompt = rt.systemPromptBuilder.rebuild(contextFiles, {
				externalMemoryInstructions: rt.memoryManager.buildExternalSystemPrompt(),
				workspaceOverride: instance.resolvedWorkspacePath,
				profileMarkdownPathRoot: resolveAgentProfileDir(cfg, instance.effectiveProfile.agentId),
				systemPromptOverride: instance.effectiveProfile.systemPromptOverride,
				skillAllowlist: instance.effectiveProfile.skillsAllowlist,
				registeredToolNames: instance.registeredToolNames
			});
			instance.agent.state.systemPrompt = newPrompt;
		}
		log.info({ agents: this.agents.size }, "Skills refreshed; system prompt updated");
	}
	/**
	* Get or create an Agent instance for a session
	*/
	getOrCreateAgent(sessionKey) {
		const cfg = this.config.config;
		const targetPath = this.getResolvedWorkspaceForSession(sessionKey);
		const existing = this.agents.get(sessionKey);
		if (existing) if (existing.resolvedWorkspacePath !== targetPath) this.removeAgent(sessionKey);
		else {
			existing.lastUsedAt = Date.now();
			log.debug({ sessionKey }, "Reusing existing agent instance");
			return existing.agent;
		}
		const profile = resolveEffectiveAgentProfileForSession(cfg, sessionKey);
		const resolvedPath = targetPath;
		const rt = this.workspaceRuntimes.getOrCreate(resolvedPath);
		if (isMemorySubsystemEnabled(cfg)) rt.memoryManager.initializeAll(sessionKey, { workspace: resolvedPath }).catch((err) => log.warn({
			err,
			sessionKey
		}, "memory initializeAll failed"));
		if (isMemorySubsystemEnabled(cfg) && shouldRegisterCuratedMemoryTool(cfg)) rt.builtinMemoryStore.loadFromDiskSync();
		const { agent, registeredToolNames } = this.createAgentForProfile(sessionKey, profile, resolvedPath, rt);
		this.agents.set(sessionKey, {
			agent,
			sessionKey,
			createdAt: Date.now(),
			lastUsedAt: Date.now(),
			effectiveProfile: profile,
			resolvedWorkspacePath: resolvedPath,
			registeredToolNames,
			skillEnvPassthroughKeys: /* @__PURE__ */ new Set()
		});
		this.backgroundReview.attachToAgent(sessionKey, agent, registeredToolNames);
		const modelRef = profile.primaryModelRef?.trim() || this.defaultModel;
		this.config.getModelManager?.().setSessionProfileDefault(sessionKey, modelRef);
		log.debug({
			sessionKey,
			totalAgents: this.agents.size,
			agentId: profile.agentId
		}, "Created new agent instance");
		return agent;
	}
	/**
	* Get existing agent for a session (if any)
	*/
	getAgent(sessionKey) {
		return this.agents.get(sessionKey)?.agent;
	}
	/**
	* Check if an agent exists for a session
	*/
	hasAgent(sessionKey) {
		return this.agents.has(sessionKey);
	}
	/**
	* Remove an agent instance
	*/
	removeAgent(sessionKey) {
		const instance = this.agents.get(sessionKey);
		if (instance) {
			this.backgroundReview.forgetSession(sessionKey);
			this.toolsFactory.closeBrowserPageForSession(sessionKey);
			retireSessionMcpRuntimeForSessionKey({
				sessionKey,
				reason: "agent-evict"
			});
			instance.agent.abort();
			evictEmbeddedSessionRunner(sessionKey, "agent_removed");
			this.agents.delete(sessionKey);
			this.memoryPrefetch.forgetSession(sessionKey);
			this.config.getModelManager?.().clearSessionProfileDefault(sessionKey);
			log.info({
				sessionKey,
				totalAgents: this.agents.size
			}, "Removed agent instance");
			return true;
		}
		return false;
	}
	/**
	* Get all active session keys
	*/
	getActiveSessions() {
		return Array.from(this.agents.keys());
	}
	/**
	* Get agent count
	*/
	getAgentCount() {
		return this.agents.size;
	}
	/**
	* Set thinking level for a session's agent
	*/
	setThinkingLevel(sessionKey, level) {
		const instance = this.agents.get(sessionKey);
		if (instance) {
			instance.agent.state.thinkingLevel = level;
			log.debug({
				sessionKey,
				thinkingLevel: level
			}, "Set thinking level for agent");
		}
	}
	/**
	* Dispose all agents
	*/
	dispose() {
		this.toolsFactory.shutdownBrowser();
		disposeAllSessionMcpRuntimes().catch(() => {});
		evictAllEmbeddedSessionRunners("agent_manager_dispose");
		this.backgroundReview.clear();
		for (const instance of this.agents.values()) instance.agent.abort();
		this.agents.clear();
		this.memoryPrefetch.clear();
		this.sessionWorkspaceOverrides.clear();
		this.workspaceRuntimes.clearAll();
		log.debug("All agent instances disposed");
	}
	async warmCredentialCache() {
		const profiles = await this.credentialResolver.listProfiles();
		for (const profile of profiles) {
			const secret = profile.key?.trim() ? profile.key.trim() : profile.envVar ? process.env[profile.envVar]?.trim() : void 0;
			if (secret) this.credentialCache.set(profile.provider.toLowerCase(), secret);
		}
		log.debug({ count: this.credentialCache.size }, "Credential cache warmed");
	}
	async refreshCredentials() {
		this.credentialCache.clear();
		await this.warmCredentialCache();
	}
	resolveApiKeyWithCache(provider) {
		const key = provider.toLowerCase();
		const cached = this.credentialCache.get(key);
		if (cached) return cached;
		const fromDisk = resolveProviderApiKeySync(provider);
		if (fromDisk) {
			this.credentialCache.set(key, fromDisk);
			return fromDisk;
		}
		const fromRegistryOrEnv = getApiKeySync(provider);
		if (fromRegistryOrEnv) {
			this.credentialCache.set(key, fromRegistryOrEnv);
			return fromRegistryOrEnv;
		}
	}
	createAgentForProfile(sessionKey, profile, resolvedWorkspacePath, rt) {
		const modelRef = profile.primaryModelRef?.trim() || this.defaultModel;
		const model = this.resolveModelStringToModel(modelRef);
		const contextFiles = this.resolveContextFilesForSession(sessionKey, profile);
		const tools = this.toolsFactory.createAllTools({
			workspace: resolvedWorkspacePath,
			profileMarkdownRoot: resolveAgentProfileDir(this.config.config, profile.agentId),
			disabledTools: profile.tools.disable,
			getPrimaryModel: () => this.resolveModelStringToModel(modelRef),
			getBuiltinMemoryStore: () => rt.builtinMemoryStore,
			getMemoryManager: () => rt.memoryManager,
			getSkillManager: () => rt.skillManager
		});
		const registeredToolNames = tools.map((t) => t.name);
		const thinkingLevel = profile.thinkingDefault ?? this.config.thinkingLevel ?? "medium";
		return {
			agent: new Agent({
				initialState: {
					systemPrompt: rt.systemPromptBuilder.build(contextFiles, {
						externalMemoryInstructions: rt.memoryManager.buildExternalSystemPrompt(),
						workspaceOverride: resolvedWorkspacePath,
						profileMarkdownPathRoot: resolveAgentProfileDir(this.config.config, profile.agentId),
						systemPromptOverride: profile.systemPromptOverride,
						skillAllowlist: profile.skillsAllowlist,
						registeredToolNames
					}),
					model,
					thinkingLevel,
					tools,
					messages: []
				},
				streamFn: createExtensionAwareStreamFn(),
				getApiKey: (provider) => this.resolveApiKeyWithCache(provider),
				beforeToolCall: async ({ toolCall, args }) => {
					if (!this.config.hookRunner) return;
					const toolName = toolCall.name;
					const parsed = parseMcpToolName(toolName);
					const hookResult = await this.config.hookRunner.runBeforeToolCall(toolName, args ?? {}, {
						sessionKey,
						isMcpTool: parsed !== null,
						mcpServerId: parsed?.serverId
					});
					if (!hookResult.allowed) return {
						block: true,
						reason: hookResult.reason ?? "Tool call blocked by policy hook."
					};
				}
			}),
			registeredToolNames
		};
	}
	/**
	* Set model for a specific session
	*/
	setModelForSession(sessionKey, modelId) {
		const instance = this.agents.get(sessionKey);
		if (!instance) {
			log.warn({
				sessionKey,
				modelId,
				activeSessionCount: this.agents.size
			}, `setModelForSession: no agent instance for session (create session / run turn first); modelId=${modelId}`);
			return false;
		}
		try {
			const model = resolveModel(modelId);
			instance.agent.state.model = model;
			log.info({
				sessionKey,
				modelId
			}, "Model set for session");
			return true;
		} catch (err) {
			log.error({
				err,
				sessionKey,
				modelId
			}, "Failed to set model for session");
			return false;
		}
	}
	/**
	* Get last assistant content from a session's agent
	*/
	getLastAssistantContent(sessionKey) {
		const instance = this.agents.get(sessionKey);
		if (!instance) return null;
		const messages = instance.agent.state.messages;
		for (let i = messages.length - 1; i >= 0; i--) {
			const msg = messages[i];
			if (msg.role === "assistant") {
				const content = msg.content;
				if (Array.isArray(content)) return extractTextContent(content);
				return String(content);
			}
		}
		return null;
	}
	/**
	* Replace messages for a session's agent
	*/
	replaceMessages(sessionKey, messages) {
		const instance = this.agents.get(sessionKey);
		if (!instance) return false;
		instance.agent.state.messages = messages;
		return true;
	}
	/**
	* Get messages for a session's agent
	*/
	getMessages(sessionKey) {
		const instance = this.agents.get(sessionKey);
		if (!instance) return null;
		return instance.agent.state.messages;
	}
	/**
	* Subscribe to agent events for a session
	*/
	subscribeToSession(sessionKey, callback) {
		const instance = this.agents.get(sessionKey);
		if (!instance) return null;
		return instance.agent.subscribe(callback);
	}
};
//#endregion
export { AgentManager };

//# sourceMappingURL=agent-manager.js.map