Skip to content

[A3] Move AgentBuilder, AgentExecutor and resumeAfterApproval to ./executor #240

Description

@LinuxDevil

Goal

createAgent() is the API the README and the quick start teach, but the root also exports the lower-level executor API (AgentBuilder, AgentExecutor, resumeAfterApproval, ToolRegistry), and 14 guides used to open with it. After G2 the guides teach createAgent() first and keep executor examples under "Advanced: the executor API" headings. This ticket makes the import path say the same thing: the executor API moves to @lousho/build-ai-agent/executor, and the root keeps createAgent() and the types its results use. Audit evidence: .agent-loop/audit2/our-report.md section 4 "Legacy API in the guides" and section 5 rows AgentBuilder and AgentExecutor.

Current state

Verified on main at cc5ddb8:

  • src/index.ts:12 export * from './core' (src/core/index.ts: export * from './AgentBuilder'), :21 export * from './tools', :31 export * from './execution'.
  • src/execution/index.ts:6 export * from './AgentExecutor' (exports PropagatingToolError re-export :92, ExecutionEventType :101, ExecutionFinishReason :132, ExecutionEvent :149, ExecuteOptions :190, ExecutionResult :594, AgentExecutor :625); :11 export * from './resume' (ResumeExecuteOptions :67, resumeAfterApproval :122, streamResumeAfterApproval :203, ResumeRequest :219, resumeRequest :229).
  • src/tools/index.ts:1 export * from './ToolRegistry' (ToolRegistry :9, globalToolRegistry :128). About 45 files in src/ import ToolRegistry from the '../tools' barrel (grep import .*ToolRegistry.* from '(\.\./)+tools'), and scripts/pack-smoke.ts:231 imports type ToolRegistry from @lousho/build-ai-agent/tools.
  • ./core is a one-export subpath (package.json exports["./core"], tsup.config.ts entry 'core/index'); src/providers/importGraph.test.ts:29 lists 'core/index' in ENTRY_POINTS.
  • Types the root must keep because createAgent()'s public types use them: ExecutionResult (src/createAgent.ts:500,543, src/createAgentApprovals.ts:48,59, src/channels/defineChannel.ts:108, src/evals/remoteTarget.ts:15) and ExecutionFinishReason (a field of ExecutionResult).
  • src/providers/sharedChunks.test.ts:30 asserts same(root, tools, 'globalToolRegistry') && same(root, tools, 'ToolRegistry').
  • scripts/verify-docs-snippets.ts:64-65 declares placeholders registry and toolRegistry as import('@lousho/build-ai-agent').ToolRegistry.
  • src/deploy/bundle.ts:72 maps only the bare @lousho/build-ai-agent specifier to the SDK source when bundling an agent directory.

Consumers that import a moving name from the root today (grep of import { ... } from '@lousho/build-ai-agent'). G2a/G2b/G2c rewrite many of these guides first; re-grep after they merge and update whatever executor imports remain:

  • Agent Forge: apps/agent-forge/server/buildAgent.ts:17 (AgentBuilder, ToolRegistry), server/runRegistry.ts:13 (AgentExecutor, ToolRegistry, resumeAfterApproval), server/compileHooks.test.ts:2 (AgentExecutor, ToolRegistry, AgentBuilder), server/__tests__/approvalFlow.test.ts:21 (AgentExecutor, ToolRegistry, AgentBuilder, resumeAfterApproval). server/chatTriggerAdapter.ts:43 imports ExecutionResult, which stays in the root.
  • Examples: examples/openrouter/index.ts:11 (AgentBuilder from '../../src/index'). The other examples import deep paths ('../../src/core', '../../src/tools', '../../src/execution/AgentExecutor') that keep working.
  • Docs: api-overview.md:539; approvals.md:331; compaction.md:71; durable-execution.md:11,95,121,263; guardrails.md:135; observability.md:20,165; providers.md:95; quick-start.md:159; sessions.md:266; skills.md:47; streaming.md:164 (streamResumeAfterApproval), :430, :563; structured-output.md:125; sub-agents.md:413; tools.md:146 (ToolRegistry); workspace-tools.md:11. Prose: api-overview.md:44-48 (table rows for AgentBuilder, AgentExecutor.execute, resumeAfterApproval).

Scope

In:

  • New subpath ./executor: src/executor/index.ts re-exports AgentBuilder (../core/AgentBuilder), AgentExecutor and type ExecuteOptions (../execution/AgentExecutor), resumeAfterApproval, streamResumeAfterApproval, resumeRequest, type ResumeExecuteOptions, type ResumeRequest (../execution/resume), ToolRegistry, globalToolRegistry (../tools/ToolRegistry), and for convenience type ExecutionResult, type ExecutionFinishReason (also still in the root). Name decided: ./executor (the plan's first option; it names the class users import from it, where ./advanced would say nothing about the contents).
  • package.json exports: add "./executor" (same shape as the others); remove "./core". tsup.config.ts: add 'executor/index': 'src/executor/index.ts', remove 'core/index'. Keep the file src/core/index.ts (internal tests import '../core').
  • Root: remove export * from './core'. In src/execution/index.ts, replace export * from './AgentExecutor' with export { PropagatingToolError } from './propagatingToolError' and export type { ExecutionResult, ExecutionFinishReason } from './AgentExecutor', and remove export * from './resume'.
  • ToolRegistry and globalToolRegistry leave the root but stay in ./tools: it is the tools subpath, JiraTools / GitHubTools extend ToolRegistry, and ~45 internal imports use the '../tools' barrel. Implement by moving everything src/tools/index.ts exports except ./ToolRegistry into a new src/tools/rootTools.ts; src/tools/index.ts becomes export * from './rootTools'; export * from './ToolRegistry';; root src/index.ts replaces export * from './tools' with export * from './tools/rootTools'.
  • src/providers/importGraph.test.ts:29: replace 'core/index' with 'executor/index'. src/providers/sharedChunks.test.ts: compare ToolRegistry / globalToolRegistry between the executor and tools entries instead of root and tools (both ESM and CJS cases).
  • scripts/verify-docs-snippets.ts:64-65: placeholders registry / toolRegistry become import('@lousho/build-ai-agent/executor').ToolRegistry.
  • Agent Forge: the four files above import the executor names from @lousho/build-ai-agent/executor; examples/openrouter/index.ts:11 imports AgentBuilder from '../../src/executor'.
  • Docs: every executor import in docs/*.md and README.md uses @lousho/build-ai-agent/executor (docs/tools.md:146 imports ToolRegistry from @lousho/build-ai-agent/tools). docs/api-overview.md: the AgentBuilder, AgentExecutor.execute, resumeAfterApproval rows say "from @lousho/build-ai-agent/executor". Add the ./executor row to the entry-point table A1 added in docs/installation.md, and remove the ./core row.
  • Append the 10 moved names to src/publicSurface.test.ts / .test-d.ts (absent from the root, present in ./executor).
  • CHANGELOG ### Breaking entry with the migration note below.

Out:

  • Deprecating or changing AgentExecutor itself: it stays the engine createAgent() runs on.
  • Guide restructuring: G2a/G2b/G2c. This ticket changes import lines and the sentences that name the import path, nothing else.
  • Subpath mapping in src/deploy/bundle.ts for agent directories (see Notes): open an issue if you confirm the problem, do not fix it here.

Acceptance criteria

  • import { createAgent, defineTool, mockModel } ... code paths are unchanged: npm run docs:verify-snippets -- --skip-build passes and the quick start runs in pack-smoke.
  • Root exports exactly 10 fewer names (both numbers in the pull request); ./executor exports the 12 names listed above; ./core is gone from exports and dist/.
  • grep -rn "from '@lousho/build-ai-agent'" docs README.md apps/agent-forge examples | grep -E "AgentExecutor|AgentBuilder|resumeAfterApproval|streamResumeAfterApproval|ToolRegistry" returns nothing.
  • src/providers/importGraph.test.ts and sharedChunks.test.ts pass with the new entry (npm run build first).
  • Full verification list in BRIEF-2.md passes, including npm run pack-smoke and the four Agent Forge checks.
  • npm run docs:llms re-run; CHANGELOG ### Breaking entry:

    The executor API moved out of the package root to @lousho/build-ai-agent/executor: AgentExecutor, AgentBuilder, ExecuteOptions, resumeAfterApproval, streamResumeAfterApproval, resumeRequest, ResumeExecuteOptions, ResumeRequest, ToolRegistry and globalToolRegistry. Change import { AgentExecutor, AgentBuilder } from '@lousho/build-ai-agent' to import { AgentExecutor, AgentBuilder } from '@lousho/build-ai-agent/executor'. ToolRegistry is also still in @lousho/build-ai-agent/tools. The @lousho/build-ai-agent/core subpath is removed: import AgentBuilder from @lousho/build-ai-agent/executor. createAgent(), ExecutionResult and every type createAgent() uses stay in the root. To move off the executor API entirely, see docs/migrating.md (G5).

Live test

None: this ticket spends nothing.

Dependencies

  • G2a, G2b, G2c (guides no longer open with the executor API) and G5 (the migration page the CHANGELOG note links) must merge first.
  • A1, A2a, A2b, A2c must merge first (same files: src/index.ts, src/execution/index.ts, src/publicSurface.test.ts, CHANGELOG.md, the installation entry-point table).
  • Owner decision required before starting (see Notes).
  • Conflicts: N-wave tickets that add exports to src/execution/index.ts or src/tools/index.ts; rebase and keep their additions in the right barrel (rootTools.ts for tool exports).

Notes for the implementer

  • Owner question (record the answer in the issue before starting): "May A3 move the executor API (AgentExecutor, AgentBuilder, resumeAfterApproval, ToolRegistry, ...) from the root to a new ./executor subpath and remove the ./core subpath (an exports removal) in the next alpha?"
  • If G5 chose a different file name than docs/migrating.md, use its real name in the CHANGELOG note.
  • export * and explicit re-exports of the same binding from two barrels are fine; a name exported by two different export * sources with different bindings is an error tsup reports. Run npm run build early.
  • ExecutionResult is generic (ExecutionResult<TObject = unknown>); re-export it as a type only.
  • Pitfall seen while reading: an agent directory bundled by lousho build resolves @lousho/build-ai-agent to the SDK source (src/deploy/bundle.ts:72) but resolves subpaths such as @lousho/build-ai-agent/executor through node_modules, which can give a second copy of shared classes. Verify with an agent-directory fixture that imports a subpath; if it splits classes, open an issue (do not widen this ticket).
  • G7 may have split docs/api-overview.md; update the rows wherever they now live.

Round 2 ticket A3. Before starting, read the agent brief (worktree rules, verification list, live-test budget) and the plan. One ticket is one pull request; put Closes #<this issue> in it.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    breakingBreaking change: CHANGELOG entry with migration notemodel:opusRun loop, security or API design; needs Opusowner-decisionNeeds the owner's answer before work startsround-2Round 2 plan ticketwave-4Round 2, wave 4

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions