{"version":3,"file":"agentClass.js","sources":["../../../src/vite/agentClass.ts"],"sourcesContent":["import { readFileSync } from 'node:fs';\nimport { DEFAULT_EXPORT, type ModuleShape, shapeFromAst, shapeFromSource, type SuperRef } from './moduleShape';\nimport type { ProgramBody } from './transform';\n\n/**\n * Agent base classes, keyed by the module specifier they are imported from. A class extending any\n * of these — directly or through a chain of local/imported subclasses — is an `agents` Agent rather\n * than a plain Durable Object.\n *\n * `McpAgent`, `AIChatAgent` and `Think` all extend `Agent` themselves, but they live in packages\n * whose sources we never walk into (see {@link followImport}), so each needs its own entry.\n */\nconst AGENT_BASE_CLASSES: Record> = {\n agents: new Set(['Agent']),\n 'agents/mcp': new Set(['McpAgent']),\n '@cloudflare/ai-chat': new Set(['AIChatAgent']),\n '@cloudflare/think': new Set(['Think']),\n};\n\n/**\n * How many modules deep the base-class chain is followed. Guards against pathological module graphs;\n * real Agent hierarchies are only a few levels deep.\n */\nconst MAX_DEPTH = 8;\n\n/**\n * The subset of the Vite/Rollup plugin context needed to walk the module graph.\n *\n * `resolve` is optional: without it detection still works, but only for base-class chains declared\n * inside the entry module itself. `readFile` is injectable for tests and defaults to reading disk.\n *\n * Deliberately **no `load`**: awaiting the plugin context's `load()` from inside a `transform` hook\n * deadlocks the build — the module cannot finish loading while its own transform is still pending\n * (Rollup documents this hazard, and Vite's Rolldown pipeline is stricter still). Sibling modules\n * are therefore read straight off disk; see {@link getModuleShape}.\n */\nexport interface ModuleResolver {\n parse(code: string): ProgramBody;\n resolve?(source: string, importer: string): Promise<{ id: string } | null | undefined>;\n readFile?(id: string): string | undefined;\n}\n\ninterface DetectContext {\n resolver: ModuleResolver;\n modules: Map;\n}\n\n/**\n * Find which of `candidates` (top-level class names in the entry module) are Cloudflare\n * [`agents`](https://www.npmjs.com/package/agents) Agents.\n *\n * An Agent is a Durable Object under the hood, so wrangler configures it as one and the transform\n * would otherwise reach for `instrumentDurableObjectWithSentry`. Detecting the Agent base chain lets\n * it pick `instrumentAgentWithSentry` instead, which adds the Agent-specific telemetry on top.\n *\n * Unlike `WorkerEntrypoint` detection, the chain is followed *across* modules: base classes commonly\n * live in their own file (`import { MyBase } from './base'`), and there is no runtime fallback that\n * would catch a missed one. Resolution stops at package boundaries — a base class imported from\n * `node_modules` is only recognized when it is one of {@link AGENT_BASE_CLASSES}.\n */\nexport async function detectAgentClasses(\n ast: ProgramBody,\n entryId: string,\n candidates: Iterable,\n resolver: ModuleResolver,\n): Promise> {\n // The entry's shape comes from the AST Vite already handed us (TypeScript stripped, full\n // fidelity); only sibling modules fall back to source scanning.\n const ctx: DetectContext = { resolver, modules: new Map([[entryId, shapeFromAst(ast)]]) };\n\n const detected = new Set();\n for (const name of candidates) {\n // A fresh cycle guard per candidate: a shared one would record \"not an Agent\" for bindings\n // visited while resolving an earlier candidate that turned out to be unrelated.\n if (await isAgentBinding(ctx, entryId, name, 0, new Set())) {\n detected.add(name);\n }\n }\n return detected;\n}\n\n/**\n * The entry-module binding names a configured class name could refer to — a class declared under\n * that name, an import of it from another module, a `export { X } from './x'` re-export, or the\n * local binding an `export { Local as Configured }` specifier aliases.\n *\n * Keeps detection (which reads and scans other modules) off names no binding points at.\n */\nexport function collectAgentCandidates(ast: ProgramBody, configuredNames: Iterable): Set {\n const shape = shapeFromAst(ast);\n const candidates = new Set();\n\n const isResolvable = (name: string): boolean =>\n shape.classes.has(name) || shape.imports.has(name) || shape.reexports.has(name);\n\n for (const configured of configuredNames) {\n if (isResolvable(configured)) {\n candidates.add(configured);\n }\n const local = shape.localExports.get(configured);\n if (local && isResolvable(local)) {\n candidates.add(local);\n }\n }\n\n return candidates;\n}\n\nasync function isAgentBinding(\n ctx: DetectContext,\n moduleId: string,\n name: string,\n depth: number,\n visited: Set,\n): Promise {\n if (depth > MAX_DEPTH) return false;\n\n const key = `${moduleId} ${name}`;\n if (visited.has(key)) return false;\n visited.add(key);\n\n const shape = await getModuleShape(ctx, moduleId);\n if (!shape) return false;\n\n if (shape.classes.has(name)) {\n return extendsAgent(ctx, shape, moduleId, shape.classes.get(name), depth, visited);\n }\n\n const imported = shape.imports.get(name);\n if (imported) {\n return followImport(ctx, moduleId, imported.source, imported.imported, depth, visited);\n }\n\n if (name === DEFAULT_EXPORT) {\n if (shape.defaultExportIsClass) {\n return extendsAgent(ctx, shape, moduleId, shape.defaultExportSuper, depth, visited);\n }\n if (shape.defaultExportName) {\n return isAgentBinding(ctx, moduleId, shape.defaultExportName, depth + 1, visited);\n }\n }\n\n // `export { Local as Requested }` — the caller asked by exported name.\n const localName = shape.localExports.get(name);\n if (localName) {\n return isAgentBinding(ctx, moduleId, localName, depth + 1, visited);\n }\n\n const reexport = shape.reexports.get(name);\n if (reexport) {\n return followImport(ctx, moduleId, reexport.source, reexport.imported, depth, visited);\n }\n\n // Barrel modules (`export * from './base'`) don't name the binding, so every star source is a\n // candidate home for it.\n for (const source of shape.starExports) {\n if (await followImport(ctx, moduleId, source, name, depth, visited)) {\n return true;\n }\n }\n\n return false;\n}\n\n/**\n * Whether a superclass reference resolves to an Agent base — a bare identifier (imported, or a\n * subclass declared in the same module) or `ns.Agent` off a namespace import.\n */\nasync function extendsAgent(\n ctx: DetectContext,\n shape: ModuleShape,\n moduleId: string,\n superClass: SuperRef | undefined,\n depth: number,\n visited: Set,\n): Promise {\n if (!superClass) return false;\n\n if (superClass.kind === 'identifier') {\n return isAgentBinding(ctx, moduleId, superClass.name, depth + 1, visited);\n }\n\n const source = shape.namespaces.get(superClass.object);\n if (source) {\n return followImport(ctx, moduleId, source, superClass.property, depth, visited);\n }\n\n return false;\n}\n\n/** Resolve an import to its module and continue the search there, stopping at package boundaries. */\nasync function followImport(\n ctx: DetectContext,\n importerId: string,\n source: string,\n importedName: string,\n depth: number,\n visited: Set,\n): Promise {\n if (AGENT_BASE_CLASSES[source]?.has(importedName)) return true;\n\n if (!ctx.resolver.resolve) return false;\n\n let resolved: { id: string } | null | undefined;\n try {\n resolved = await ctx.resolver.resolve(source, importerId);\n } catch {\n return false;\n }\n if (!resolved?.id) return false;\n\n // Third-party sources are not walked: they are large, may not be plain JS by the time we see\n // them, and any Agent base worth knowing about is listed in AGENT_BASE_CLASSES.\n if (resolved.id.includes('/node_modules/') || resolved.id.includes('\\\\node_modules\\\\')) return false;\n\n return isAgentBinding(ctx, resolved.id, importedName, depth + 1, visited);\n}\n\nasync function getModuleShape(ctx: DetectContext, moduleId: string): Promise {\n if (ctx.modules.has(moduleId)) return ctx.modules.get(moduleId);\n\n let shape: ModuleShape | undefined;\n try {\n const code = ctx.resolver.readFile\n ? ctx.resolver.readFile(moduleId)\n : readFileSync(moduleId.replace(/[?#].*$/, ''), 'utf8');\n if (typeof code === 'string') {\n shape = shapeFromSource(code);\n }\n } catch {\n // Unreadable or not a source file — treat as \"not an Agent\" rather than failing the build.\n }\n\n ctx.modules.set(moduleId, shape);\n return shape;\n}\n"],"names":["shapeFromAst","DEFAULT_EXPORT","readFileSync","shapeFromSource"],"mappings":"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"}