import { createLogger } from "../../utils/logger/index.js";
import { init_logger } from "../../utils/logger.js";
import { init_session_key, parseSessionKey } from "../../routing/session-key.js";
import { createReadFileTool } from "./read.js";
import { createWriteFileTool } from "./write.js";
import { createEditFileTool } from "./edit.js";
import { createListDirTool } from "./list-dir.js";
import { createShellTool } from "./shell.js";
import { createMemoryGetTool, createMemorySearchTool } from "./memory-tool.js";
import { createCuratedMemoryTool } from "./curated-memory-tool.js";
import { createSessionSearchTool } from "./session-search-tool.js";
import { createGrepTool } from "./grep.js";
import { createFindTool } from "./find.js";
import { createWebFetchTool, createWebSearchTool } from "./web.js";
import { createWebExtractTool } from "./web-extract.js";
import { createMessageTool } from "./communication.js";
import { createSendMediaTool } from "./send-media.js";
import { createCreateShareTool, isShareToolAvailable } from "./create-share-tool.js";
import { createTodoTool } from "./todo-tool.js";
import { createSessionStatusTool } from "./session-status-tool.js";
import { createDreamingTool } from "./dreaming-tool.js";
import { createClarifyTool } from "./clarify-tool.js";
import { BrowserManager } from "../../browser/manager.js";
import { resolveBrowserBackendFromConfig } from "../../browser/backend-from-config.js";
import { checkBrowserReadiness } from "../../browser/readiness.js";
import { CdpSupervisor } from "../../browser/cdp-supervisor.js";
import "../../browser/index.js";
import { createDelegateTool } from "./delegate-tool.js";
import { createWorkflowCatalog } from "../workflow/catalog.js";
import { createWorkflowTool } from "./workflow-tool.js";
import { buildSandboxToolMap, createExecuteCodeTool } from "./execute-code-tool.js";
import { createCronjobTool } from "./cronjob-tool.js";
import { createSkillViewTool, createSkillsListTool } from "./skills-tools.js";
import { createSkillManageTool } from "./skill-manage-tool.js";
import { createImageTool } from "./image-tool.js";
import { createImageGenerateTool } from "./image-generate-tool.js";
import "./index.js";
import { shouldRegisterCuratedMemoryTool } from "../memory/memory-config.js";
import { createBrowserUseTool } from "./browser/tool/browser-use-tool.js";
import { wrapToolsWithProtection } from "./executor.js";
import { mergeTtsConfigFromAppConfig } from "../../voice/tts/merge-config.js";
import { createTextToSpeechTool } from "./tts-tool.js";
//#region src/agent/tools/factory.ts
init_session_key();
init_logger();
const log = createLogger("AgentToolsFactory");
/** Channels where `clarify` can block for a user answer (web UI, Telegram, CLI readline). */
const CLARIFY_SUPPORTED_CHANNELS = new Set([
	"webchat",
	"telegram",
	"cli"
]);
function clarifyTransportSource(sessionKey) {
	const parsed = parseSessionKey(sessionKey);
	if (parsed) return parsed.source;
	const first = sessionKey.split(":").filter(Boolean)[0] ?? "";
	if (first === "cli" || first === "webchat") return first;
}
var AgentToolsFactory = class AgentToolsFactory {
	browserManager = null;
	/** One dialog/console supervisor per chat session (browser tab). */
	browserTaskSupervisors = /* @__PURE__ */ new Map();
	/** Cached readiness probe — keyed by backend mode + extension host:port. */
	browserReadinessCache = null;
	constructor(deps) {
		this.deps = deps;
	}
	browserReadinessKey() {
		const cfg = this.deps.getConfig?.();
		const backend = resolveBrowserBackendFromConfig(cfg);
		const ext = cfg?.agents?.defaults?.browser?.extension;
		const host = typeof ext?.host === "string" && ext.host.trim() ? ext.host.trim() : "127.0.0.1";
		const port = typeof ext?.port === "number" ? ext.port : 19820;
		const cdpUrl = backend.mode === "cdp" ? backend.config.wsEndpoint : "";
		const cloudKind = backend.mode === "cloud" ? backend.config.type : "";
		return `${backend.mode}@${host}:${port}|${cdpUrl}|${cloudKind}`;
	}
	async checkBrowserReadinessCached() {
		const key = this.browserReadinessKey();
		const now = Date.now();
		const cached = this.browserReadinessCache;
		if (cached && cached.key === key && cached.expiresAt > now && cached.inflight === void 0) return cached.result ?? null;
		if (cached && cached.key === key && cached.inflight) return cached.inflight;
		const inflight = checkBrowserReadiness(this.deps.getConfig?.());
		this.browserReadinessCache = {
			key,
			expiresAt: now + 3e4,
			inflight
		};
		try {
			const result = await inflight;
			this.browserReadinessCache = {
				key,
				expiresAt: Date.now() + 3e4,
				result
			};
			return result;
		} catch (e) {
			this.browserReadinessCache = null;
			log.warn({ err: e }, "browserReadiness probe failed");
			return null;
		}
	}
	/** Invalidate the readiness cache (config hot-reload, settings-page save, etc.). */
	invalidateBrowserReadinessCache() {
		this.browserReadinessCache = null;
	}
	browserSupervisorForTask(taskId) {
		let s = this.browserTaskSupervisors.get(taskId);
		if (!s) {
			const b = this.deps.getConfig?.()?.agents?.defaults?.browser;
			s = new CdpSupervisor({
				dialogPolicy: b?.dialogPolicy === "must_respond" || b?.dialogPolicy === "auto_accept" || b?.dialogPolicy === "auto_dismiss" ? b.dialogPolicy : "auto_dismiss",
				dialogTimeoutSeconds: typeof b?.dialogTimeoutSeconds === "number" && Number.isFinite(b.dialogTimeoutSeconds) && b.dialogTimeoutSeconds >= 1 ? Math.floor(b.dialogTimeoutSeconds) : 300
			});
			this.browserTaskSupervisors.set(taskId, s);
		}
		return s;
	}
	async acquireBrowserPage() {
		const taskId = this.deps.getCurrentContext()?.sessionKey ?? "default";
		const mgr = this.ensureBrowserManager();
		await mgr.ensureConnected();
		if (mgr.getExtensionProvider()) return null;
		const page = await mgr.getPage(taskId);
		this.browserSupervisorForTask(taskId).attach(page);
		return page;
	}
	ensureBrowserManager() {
		if (!this.browserManager) this.browserManager = new BrowserManager({
			getHeadless: () => this.deps.getConfig?.()?.agents?.defaults?.browser?.headless === true,
			getBackend: () => resolveBrowserBackendFromConfig(this.deps.getConfig?.())
		});
		return this.browserManager;
	}
	/** Close Playwright and all pages (gateway stop, agent manager dispose, or config hot-reload). */
	async shutdownBrowser() {
		this.browserReadinessCache = null;
		if (!this.browserManager) return;
		await this.browserManager.shutdown();
		this.browserManager = null;
		this.browserTaskSupervisors.clear();
	}
	/** Drop the tab for a session when its agent instance is removed. */
	async closeBrowserPageForSession(sessionKey) {
		this.browserTaskSupervisors.delete(sessionKey);
		await this.browserManager?.closePage(sessionKey);
	}
	createCoreTools(options) {
		const workspace = options?.workspace ?? this.deps.workspace;
		const { bus } = this.deps;
		const getPrimary = options?.getPrimaryModel ?? this.deps.getPrimaryModel;
		const getBuiltin = options?.getBuiltinMemoryStore ?? this.deps.getBuiltinMemoryStore;
		const memoriesDir = (getBuiltin?.())?.memoriesDir;
		const getMemMgr = options?.getMemoryManager ?? this.deps.getMemoryManager;
		const getSkillMgr = options?.getSkillManager;
		const disabled = options?.disabledTools;
		const primary = getPrimary?.();
		const modelHasVision = primary?.input?.includes("image") ?? false;
		const cfg = this.deps.getConfig?.();
		const optionalTools = [createImageTool({
			config: cfg,
			workspace,
			modelHasVision
		}), createImageGenerateTool({
			config: cfg,
			workspace
		})].filter((t) => t != null);
		const readTool = createReadFileTool(workspace, { profileMarkdownRoot: options?.profileMarkdownRoot });
		const writeTool = createWriteFileTool(workspace);
		const editTool = createEditFileTool(workspace);
		const listDir = createListDirTool(workspace);
		const grep = createGrepTool(workspace);
		const find = createFindTool(workspace);
		return filterToolsByDisabledSet([
			createSessionStatusTool(),
			createDreamingTool({
				getWorkspace: () => workspace,
				getConfig: () => this.deps.getConfig?.()
			}),
			createClarifyTool({ resolveAskUser: () => {
				const req = this.deps.gatewayClarify?.requestClarification;
				if (!req) return null;
				const ctx = this.deps.getCurrentContext();
				if (!ctx?.sessionKey) return null;
				const source = clarifyTransportSource(ctx.sessionKey);
				if (!source || !CLARIFY_SUPPORTED_CHANNELS.has(source)) return null;
				return (r) => req(ctx.sessionKey, r);
			} }),
			createTodoTool({ getSessionKey: () => this.deps.getCurrentContext()?.sessionKey }),
			...getSkillMgr ? [
				createSkillsListTool({
					getSkillManager: getSkillMgr,
					getSkillIndexingContext: this.deps.getSkillIndexingContext
				}),
				createSkillViewTool({
					getSkillManager: getSkillMgr,
					getSkillIndexingContext: this.deps.getSkillIndexingContext,
					registerSkillEnvPassthrough: this.deps.registerSkillEnvPassthrough
				}),
				createSkillManageTool({
					getSkillManager: getSkillMgr,
					getWorkspace: () => workspace,
					onSkillsFilesystemMutate: this.deps.onSkillsFilesystemMutate
				})
			] : [],
			readTool,
			writeTool,
			editTool,
			listDir,
			grep,
			find,
			createShellTool(workspace, { getSkillPassthroughEnvVarNames: this.deps.getSkillPassthroughEnvVarNames }),
			createWebSearchTool(() => this.deps.getConfig?.()),
			createWebFetchTool(() => this.deps.getConfig?.()),
			createWebExtractTool({ getConfig: () => this.deps.getConfig?.() }),
			createMessageTool(bus, () => this.deps.getCurrentContext()),
			...mergeTtsConfigFromAppConfig(cfg?.messages?.tts).enabled ? [createTextToSpeechTool({
				bus,
				getContext: () => this.deps.getCurrentContext(),
				getConfig: () => this.deps.getConfig?.()
			})] : [],
			createSendMediaTool(workspace, bus, () => this.deps.getCurrentContext()),
			...isShareToolAvailable(cfg) ? [createCreateShareTool({
				workspace,
				getConfig: () => this.deps.getConfig?.()
			})] : [],
			createMemorySearchTool({
				workspaceDir: workspace,
				memoriesDir
			}),
			createMemoryGetTool({
				workspaceDir: workspace,
				memoriesDir
			}),
			...getBuiltin && shouldRegisterCuratedMemoryTool(this.deps.getConfig?.()) ? [createCuratedMemoryTool(getBuiltin, { onMemoryWrite: (action, target, content) => {
				getMemMgr?.().onMemoryWrite(action, target, content);
			} })] : [],
			...getMemMgr?.().getAdditionalTools() ?? [],
			...this.deps.getSessionStore ? [createSessionSearchTool({
				getSessionStore: this.deps.getSessionStore,
				getConfig: this.deps.getConfig,
				getCurrentSessionKey: () => this.deps.getCurrentContext()?.sessionKey
			})] : [],
			...this.deps.getCronService ? [createCronjobTool({ getCronService: this.deps.getCronService })] : [],
			...cfg?.agents?.defaults?.browser?.enabled !== false ? [createBrowserUseTool({
				getManager: () => this.ensureBrowserManager(),
				getPageForTask: () => this.acquireBrowserPage(),
				getTaskId: () => this.deps.getCurrentContext()?.sessionKey ?? "default",
				getConfig: () => this.deps.getConfig?.(),
				getReadiness: () => this.checkBrowserReadinessCached(),
				getSupervisor: () => this.browserSupervisorForTask(this.deps.getCurrentContext()?.sessionKey ?? "default"),
				notifyBrowserPageClosed: (taskId) => {
					this.browserTaskSupervisors.delete(taskId);
				}
			})] : [],
			...cfg?.agents?.defaults?.workflow?.enabled !== false && primary ? [createWorkflowTool({
				workspace,
				bus: this.deps.bus,
				getConfig: () => this.deps.getConfig?.(),
				catalog: createWorkflowCatalog(),
				getCurrentSessionKey: () => this.deps.getCurrentContext()?.sessionKey,
				getSubagentModel: () => {
					const m = (options?.getPrimaryModel ?? this.deps.getPrimaryModel)?.();
					if (!m) throw new Error("No primary model configured for workflow");
					return m;
				},
				toolExecutorConfig: this.deps.toolExecutorConfig,
				buildChildTools: (childOpts) => {
					return new AgentToolsFactory({
						workspace: childOpts.workspace,
						bus: childOpts.bus,
						getCurrentContext: () => null,
						getConfig: childOpts.getConfig,
						getPrimaryModel: () => childOpts.model,
						toolExecutorConfig: childOpts.toolExecutorConfig
					}).createAllTools({
						workspace: childOpts.workspace,
						getPrimaryModel: () => childOpts.model,
						disabledTools: new Set(["extensions"])
					});
				}
			})] : [],
			...cfg?.agents?.defaults?.delegate?.enabled === true && primary ? [createDelegateTool({
				workspace,
				getSubagentModel: () => {
					const m = (options?.getPrimaryModel ?? this.deps.getPrimaryModel)?.();
					if (!m) throw new Error("No primary model configured for delegate_task");
					return m;
				},
				bus: this.deps.bus,
				getConfig: () => this.deps.getConfig?.(),
				getCurrentContext: () => this.deps.getCurrentContext?.() ?? null,
				hookRunner: this.deps.hookRunner,
				toolExecutorConfig: this.deps.toolExecutorConfig,
				buildChildTools: (childOpts) => {
					return new AgentToolsFactory({
						workspace: childOpts.workspace,
						bus: childOpts.bus,
						getCurrentContext: () => null,
						getConfig: childOpts.getConfig,
						getPrimaryModel: () => childOpts.model,
						toolExecutorConfig: childOpts.toolExecutorConfig
					}).createAllTools({
						workspace: childOpts.workspace,
						getPrimaryModel: () => childOpts.model,
						disabledTools: new Set(["extensions"])
					});
				}
			})] : [],
			...optionalTools
		], disabled);
	}
	createAllTools(coreOptions) {
		const coreTools = this.createCoreTools(coreOptions);
		const disableExtensions = coreOptions?.disabledTools?.has("extensions");
		const cfg = this.deps.getConfig?.();
		let bundled;
		if (!this.deps.extensionRegistry || disableExtensions) bundled = coreTools;
		else {
			const extensionTools = this.deps.extensionRegistry.getAllTools();
			log.info({ count: extensionTools.length }, "Loaded extension tools");
			bundled = [...coreTools, ...extensionTools];
		}
		const wrapped = wrapToolsWithProtection(bundled, this.deps.toolExecutorConfig);
		if (cfg?.agents?.defaults?.executeCode?.enabled === true && !coreOptions?.disabledTools?.has("execute_code")) {
			const sandboxMap = buildSandboxToolMap(wrapped);
			const wrappedExecute = wrapToolsWithProtection([createExecuteCodeTool({ getSandboxToolMap: () => sandboxMap })], this.deps.toolExecutorConfig);
			return [...wrapped, ...wrappedExecute];
		}
		return wrapped;
	}
};
function filterToolsByDisabledSet(tools, disabled) {
	if (!disabled || disabled.size === 0) return tools;
	return tools.filter((t) => !disabled.has(t.name));
}
//#endregion
export { AgentToolsFactory };

//# sourceMappingURL=factory.js.map