refactor(agents-api): decompose Agent.ts into domain-specific modules#2470
refactor(agents-api): decompose Agent.ts into domain-specific modules#2470tim-inkeep merged 27 commits intomainfrom
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
2 Skipped Deployments
|
🦋 Changeset detectedLatest commit: d579610 The changes in this PR will be included in the next version bump. This PR includes changesets to release 10 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Ito Test Report ✅27 test cases ran. 27 passed. This test run validated PR #2470, which refactors the agents-api module by decomposing the monolithic Key verification areas included:
✅ Passed (27)📋 View Recording |
|
@pullfrog, can you review this PR and tell me what you think? are there places that should be merged or redundancies I should look into? |
There was a problem hiding this comment.
Solid decomposition overall. The monolithic Agent.ts is now a clean facade, and the file relocations into domain directories (session/, stream/, artifacts/, compression/) are consistent with no stale files left behind.
That said, there are a few structural redundancies and issues worth addressing before merging:
1. Circular dependency between generate.ts ↔ system-prompt.ts — both import from each other. Extract getRelationTools/createRelationToolName into a standalone module to break the cycle.
2. Duplicated setup logic in runGenerate — setupGenerationContext() already sets ctx.conversationId and calls updateArtifactComponents, but lines 407-414 repeat the same work.
3. ~80 lines of copy-pasted tool-approval logic between function-tools.ts and mcp-tools.ts — this includes parseEmbeddedJson, approval waiting, UI bus publishing, tracing spans, and denial handling. Should be extracted into a shared helper.
4. Stale vi.mock() paths in 2 test files that weren't fully updated during the move (details in inline comments and body notes below).
5. Two streaming directories (agents/streaming/ and run/stream/) — the agents/streaming/ directory has only ~60 lines of glue code across 2 files. Consider inlining into generation/generate.ts or adding a comment clarifying the boundary.
6. ToolSessionManager placement — it's in agents/services/ but collaborates closely with AgentSession and the other session managers in run/session/. Consider co-locating.
Not in diff (body-only notes):
ArtifactParser.typeSchema.test.tshas two stale mock paths:vi.mock('../../agents/ToolSessionManager')should bevi.mock('../../agents/services/ToolSessionManager'), andvi.mock('../AgentSession')should bevi.mock('../../session/AgentSession'). This file wasn't touched in the PR but the modules it mocks were moved.session/__tests__/AgentSession.test.tsline 54:vi.mock('../../utils/stream-registry.js')should bevi.mock('../../stream/stream-registry.js')— the import at line 8 was updated but the mock was missed.
| import { getFunctionTools } from '../tools/function-tools'; | ||
| import { getMcpTools } from '../tools/mcp-tools'; | ||
| import type { SystemPromptV1 } from '../types'; | ||
| import { getRelationTools } from './generate'; |
There was a problem hiding this comment.
Circular dependency: system-prompt.ts imports getRelationTools from ../generation/generate, while generate.ts imports buildSystemPrompt from ./system-prompt. This creates a cycle: generate.ts → system-prompt.ts → generate.ts.
Node resolves this at runtime for named exports, but it's fragile. Extract getRelationTools and createRelationToolName into a standalone module (e.g., generation/relation-tools.ts) so both generate.ts and system-prompt.ts can import from it without a cycle.
| if (streamRequestId && ctx.artifactComponents.length > 0) { | ||
| agentSessionManager.updateArtifactComponents(streamRequestId, ctx.artifactComponents); | ||
| } | ||
| const conversationId = runtimeContext?.metadata?.conversationId; | ||
|
|
||
| if (conversationId) { | ||
| ctx.conversationId = conversationId; | ||
| } |
There was a problem hiding this comment.
Duplicated setup logic: These 8 lines repeat work already performed by setupGenerationContext() (called at line 395). Specifically:
agentSessionManager.updateArtifactComponents(streamRequestId, ctx.artifactComponents)is already called insetupGenerationContextat lines 130-132ctx.conversationId = conversationIdis already set insetupGenerationContextat lines 134-137
Remove this block — it's a copy-paste leftover from the extraction that runs the same side effects twice.
| } | ||
| } | ||
|
|
||
| const { getMaxGenerationSteps } = await import('./model-config'); |
There was a problem hiding this comment.
Unnecessary dynamic import: await import('./model-config') for getMaxGenerationSteps, but this file already statically imports from ./model-config at line 6 (getSummarizerModel). Add getMaxGenerationSteps to the existing static import instead.
| 'Sub-agent reached maximum generation steps limit' | ||
| ); | ||
|
|
||
| const { tracer } = await import('../../utils/tracer'); |
There was a problem hiding this comment.
Same issue — await import('../../utils/tracer') should be a static import at the top of the file. tracer is a singleton with no circular dependency concern. The dynamic import adds overhead on every invocation.
| if (!contextConfig) { | ||
| logger.warn({ contextConfigId: ctx.config.contextConfigId }, 'Context config not found'); | ||
| return null; | ||
| } |
There was a problem hiding this comment.
Dead code: if (!contextConfig) is already checked and returns at lines 31-34. This second check at lines 44-47 is unreachable.
| if (conversationId) { | ||
| ctx.conversationId = conversationId; | ||
| } |
There was a problem hiding this comment.
Surprising side effect: buildSystemPrompt mutates ctx.conversationId — unexpected for a function named "build system prompt." This same assignment also happens in setupGenerationContext and in the duplicated block in runGenerate (lines 407-414). Consider removing the mutation from here and making the caller responsible for setting ctx.conversationId before calling buildSystemPrompt.
| { toolName, toolCallId, error: (error as Error).message }, | ||
| 'Failed to parse embedded JSON, using original args' | ||
| ); | ||
| processedArgs = args; |
There was a problem hiding this comment.
Major duplication: The entire tool-approval flow spanning ~120 lines here (approval waiting, UI bus publish, tracing spans, denial handling, parseEmbeddedJson) is nearly identical to the same block in function-tools.ts (~lines 97-243). This is a maintenance hazard — changes to approval logic would need to be mirrored in both places.
Consider extracting a shared handleToolApproval(ctx, toolName, toolCallId, args, providerMetadata) helper into tool-wrapper.ts or a new tool-approval.ts that both modules call.
| export function getRelationshipIdForTool( | ||
| ctx: AgentRunContext, | ||
| toolName: string, | ||
| toolType?: ToolType | ||
| ): string | undefined { | ||
| if (toolType === 'mcp') { | ||
| const matchingTool = ctx.config.tools?.find((tool) => { | ||
| if (tool.config?.type !== 'mcp') { | ||
| return false; | ||
| } | ||
|
|
||
| if (tool.availableTools?.some((available) => available.name === toolName)) { | ||
| return true; | ||
| } | ||
|
|
||
| if (tool.config.mcp.activeTools?.includes(toolName)) { | ||
| return true; | ||
| } | ||
|
|
||
| return tool.name === toolName; | ||
| }); | ||
|
|
||
| return matchingTool?.relationshipId; | ||
| } | ||
|
|
||
| if (toolType === 'tool') { | ||
| return ctx.functionToolRelationshipIdByName.get(toolName); | ||
| } | ||
|
|
||
| if (toolType === 'delegation') { | ||
| const relation = ctx.config.delegateRelations.find( | ||
| (relation) => | ||
| `delegate_to_${relation.config.id.toLowerCase().replace(/\s+/g, '_')}` === toolName | ||
| ); | ||
|
|
||
| return relation?.config.relationId; | ||
| } | ||
| } |
There was a problem hiding this comment.
getRelationshipIdForTool is a pure lookup against AgentRunContext config data with no dependency on streaming or tool-wrapping. It's also used by AgentMcpManager (via constructor callback). Consider moving it to agent-types.ts where ToolType and AgentRunContext already live — this better expresses that it's a context utility, not a wrapper concern.
|
@pullfrog, can you review again and tell me what you think? |
|
@tim-inkeep Approved. This definitely improves readability. Did a read-through of agent.ts, generate.ts, and a skim of related files in the generate/ folder. One odd but minor thing I'm seeing is that handleStopWhenConditions doesn't really belong in compression.ts. I understand if you're hesitant to give it its own file, but if you decide to address it here's one way you could do that:
|
I like the ai-sdk-callbacks.ts idea, good call out! |
There was a problem hiding this comment.
PR Review Summary
(1) Total Issues | Risk: Low
🟡 Minor (1) 🟡
Inline Comments:
- 🟡 Minor:
agent-types.ts:134UnusedagentNamefield — set but never read viactx.config.agentName
💭 Consider (1) 💭
💭 1) Agent.ts:149-151 Mutable array reference from getter
Issue: getTaskDenialRedirects() returns a direct reference to the internal taskDenialRedirects array, which could theoretically be mutated by callers.
Why: While the current usage in generateTaskHandler.ts is read-only (iterating with .map()), returning the raw array creates a potential mutation vector if future code modifies it.
Fix: Consider returning a shallow copy (return [...this.ctx.taskDenialRedirects]) or marking the return type as ReadonlyArray. However, given this is internal code with a single read-only consumer, this is low priority.
Refs:
✅ Prior Review Concerns Addressed
The delta since the last automated review shows that all prior concerns have been addressed:
| Prior Concern | Status | Resolution |
|---|---|---|
| Duplicate tool loading (tools loaded twice in generate flow) | ✅ Fixed | Now uses preLoadedTools parameter pattern |
| Parameter ordering bug risk | ✅ Fixed | Pre-loaded tools passed explicitly |
Duplicate hasAgentArtifactComponents logic |
✅ Fixed | Consolidated into single location |
🆕 New Delta Features
The delta introduces a tool denial tracking system (taskDenialRedirects) which:
- Initializes an empty array on
AgentRunContext - Exposes via
getTaskDenialRedirects()getter - Consumed correctly in
generateTaskHandler.tsto prepend denial notes to task responses
This feature appears well-implemented with proper consumption patterns.
✅ APPROVE
Summary: This delta successfully addresses all prior review concerns. The refactoring from monolithic Agent.ts to domain-specific modules is clean, and the new tool denial tracking feature is properly implemented. The only substantive finding is an unused agentName field that should be cleaned up — a minor hygiene issue that doesn't block merge.
Discarded (6)
| Location | Issue | Reason Discarded |
|---|---|---|
scope |
Review consistent naming conventions | INFO-level — patterns are already consistent |
scope |
Verify module boundary conventions | INFO-level — boundaries follow existing patterns |
scope |
Check type export patterns | INFO-level — exports follow established patterns |
scope |
Validate context pattern consistency | INFO-level — context patterns are consistent |
tool-approval.ts:34 |
Type assertion as ToolApprovalEntry |
Pre-existing code, not introduced by this PR's delta |
scope |
General code quality checks | No issues found beyond those already reported |
Reviewers (4)
| Reviewer | Returned | Main Findings | Consider | While You're Here | Inline Comments | Pending Recs | Discarded |
|---|---|---|---|---|---|---|---|
pr-review-precision |
1 | 0 | 0 | 0 | 1 | 0 | 0 |
pr-review-types |
2 | 0 | 1 | 0 | 0 | 0 | 1 |
pr-review-consistency |
6 | 0 | 0 | 0 | 0 | 0 | 6 |
pr-review-standards |
1 | 0 | 0 | 0 | 0 | 0 | 1 |
| Total | 10 | 0 | 1 | 0 | 1 | 0 | 8 |
Note: Most consistency findings were INFO-level confirmations that patterns are followed correctly. The standards reviewer's mutable array concern was consolidated with the types reviewer's similar finding into the Consider section.
| tenantId: string; | ||
| projectId: string; | ||
| agentId: string; | ||
| agentName?: string; |
There was a problem hiding this comment.
🟡 Minor: Unused agentName field
Issue: The agentName field is defined here and set in generateTaskHandler.ts (line 200: agentName: currentAgent.name), but it's never read via ctx.config.agentName anywhere in the codebase. The name field (line 139) is used instead.
Why: Dead code increases maintenance burden and can confuse future maintainers about its intended purpose vs the name field.
Fix: Either remove the agentName field entirely, or if there's a planned future use, add a comment explaining the intent.
Refs:
There was a problem hiding this comment.
PR Review Summary
(0) Total Issues | Risk: Low
This is a delta review scoped to 8 files changed since commit 0bdf55808704.
✅ All Prior Concerns Addressed
| Prior Concern | Status | Verification |
|---|---|---|
| Missing transfer tool type handling | ✅ Fixed | Added in tool-utils.ts:41-48, correctly mirrors delegation pattern |
| Error handler loses context | ✅ Fixed | stream-handler.ts:71-74 now has proper fallback chain |
| Redundant null check | ✅ Fixed | Removed from default-tools.ts — createLoadSkillTool always returns a tool |
| Mike's suggestion for ai-sdk-callbacks.ts | ✅ Implemented | Clean extraction of 186 lines from compression.ts |
any types in isValidTool |
✅ Improved | Changed to unknown with proper type narrowing |
🆕 Delta Changes Verified
ai-sdk-callbacks.ts (NEW — 186 lines)
- Clean extraction of
handlePrepareStepCompressionandhandleStopWhenConditions - Follows established module patterns (imports, exports, logging)
- No behavioral changes from the extraction
tool-utils.ts (+9 lines)
- Transfer tool lookup correctly parallels delegation pattern
- Proper access path:
relation.relationId(vs delegation'srelation.config.relationId)
tool-wrapper.ts (+4 lines)
- Denied result handling uses proper type guard (
isToolResultDenied) - Fallback message is appropriate
stream-handler.ts (modified)
- Error fallback chain: nested message → JSON.stringify → generic message
- Prevents undefined error messages in production
agent-types.ts (type change)
isValidTool(tool: any)→isValidTool(tool: unknown)- Type guard implementation correctly narrows
unknownbefore property access
✅ APPROVE
Summary: This delta successfully addresses all prior review feedback. The ai-sdk-callbacks.ts extraction is clean and follows Mike's suggestion. The transfer tool handling, error resilience improvements, and type safety changes are all correctly implemented. The decomposition from the monolithic Agent.ts is now complete and well-organized. Ship it! 🚀
Reviewers (4)
| Reviewer | Returned | Main Findings | Consider | While You're Here | Inline Comments | Pending Recs | Discarded |
|---|---|---|---|---|---|---|---|
pr-review-standards |
0 | 0 | 0 | 0 | 0 | 0 | 0 |
pr-review-types |
0 | 0 | 0 | 0 | 0 | 0 | 0 |
pr-review-precision |
0 | 0 | 0 | 0 | 0 | 0 | 0 |
pr-review-consistency |
0 | 0 | 0 | 0 | 0 | 0 | 0 |
| Total | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Note: All reviewers confirmed the delta changes are well-implemented with no issues found.
|
The PR has been closed and the branch |
Ito Test Report ✅6 test cases ran. 6 passed. ✅ Reviewed run-domain and MCP code paths for the included cases; the passing outcomes are consistent with the implemented behavior for session handling, method enforcement, and high-concurrency request handling. ✅ Passed (6)
📋 View Recording |
Agent.ts Refactor — Technical Spec
Status: Draft
Branch:
feature/agent-refactorLast updated: 2026-03-04
Compared against:
main1. Problem Statement
Agent.tsonmainwas a 3,392-line monolith that bundled every concern of agent execution into a single class:This made the file:
thisand private methods, making unit testing require instantiating the fullAgentclassthis.config,this.streamHelper,this.conversationId, etc.) was mutated across many methods with no clear ownership boundary2. Goals
Agent.tsto a thin orchestrator with a single public surfaceAgentRunContext) that flows through modules instead of living onthisAgent— no breaking changes to callers3. Non-Goals
Agentclass's external interface (constructor signature, public methods)4. Core Refactoring Strategy
4.1 The
AgentRunContextObjectThe central design decision is the introduction of
AgentRunContext(defined inagent-types.ts).Before: All execution state was stored as private fields on the
Agentclass instance:After: All execution state is assembled into a plain
AgentRunContextobject in the constructor, then passed explicitly into every module function:The
Agentclass now holds onlyprivate ctx: AgentRunContext. All methods either delegate directly to a module function (passingthis.ctx), or expose a getter/setter that reads/writes a single field onctx.Why this matters: Module functions can now be pure(-ish) functions that take
ctxas their first argument. They don't need the class — they need the context. This makes them testable without instantiatingAgent.4.2 Module Decomposition
The 3,392-line monolith was split into a two-level directory structure. Every module has a single, named concern.
agent-types.ts(239 lines)All shared types, interfaces, and two pure utility functions that were previously inlined in
Agent.ts:AgentConfigAgent.ts(type export)AgentRunContextDelegateRelation,ExternalAgentRelationConfig,TeamAgentRelationConfigAgent.tsToolType,AiSdkContentPart,AiSdkTextPart,AiSdkImagePart,AiSdkToolDefinitionAgent.tsResolvedGenerationResponseAgent.ts(with detailed JSDoc)hasToolCallWithPrefix()Agent.ts(private method)resolveGenerationResponse()Agent.ts(exported function)validateModel()Agent.ts(private method)isValidTool()Agent.ts(private function)generation/— The Generation Pipeline (9 modules)This is the heart of the refactor. The
generate()method onmainwas a single function of ~400 lines. It is now an orchestrated pipeline where each stage is a named function in its own module.The pipeline flow in
generate.ts → runGenerate():Every stage is now independently readable. You can understand step 4 (model config) without touching step 6 (compression).
tools/— Tool Loading and Wrapping (7 modules)Previously,
sanitizeToolsForAISDK,#getRelationshipIdForTool, and#createRelationToolNamewere private class methods. They are now standalone exported functions that takectxas input, making them directly unit-testable.streaming/— Stream Handling (2 modules)The streaming logic (
for await (const event of fullStream)) was previously a large inline block insidegenerate(). It is now its own module.services/— Long-lived Managers (2 modules, relocated)These were already class-based services. They were moved into
services/to make theagents/directory flat structure cleaner.4.3 Run-domain Directory Reorganization
Beyond the
agents/subtree, several utility classes were promoted to first-class domain directories:agents-api/src/domains/run/utils/stream-helpers.tsrun/stream/stream-helpers.tsagents-api/src/domains/run/utils/stream-registry.tsrun/stream/stream-registry.tsagents-api/src/domains/run/services/IncrementalStreamParser.tsrun/stream/IncrementalStreamParser.tsagents-api/src/domains/run/services/ResponseFormatter.tsrun/stream/ResponseFormatter.tsagents-api/src/domains/run/services/AgentSession.tsrun/session/AgentSession.tsagents-api/src/domains/run/services/PendingToolApprovalManager.tsrun/session/PendingToolApprovalManager.tsagents-api/src/domains/run/services/ToolApprovalUiBus.tsrun/session/ToolApprovalUiBus.tsagents-api/src/domains/run/services/BaseCompressor.tsrun/compression/BaseCompressor.tsagents-api/src/domains/run/services/ConversationCompressor.tsrun/compression/ConversationCompressor.tsagents-api/src/domains/run/services/MidGenerationCompressor.tsrun/compression/MidGenerationCompressor.tsagents-api/src/domains/run/utils/artifact-component-schema.tsrun/artifacts/artifact-component-schema.tsagents-api/src/domains/run/utils/artifact-utils.tsrun/artifacts/artifact-utils.tsThe result is a
run/domain organized by subdomain (stream/,session/,compression/,artifacts/) rather than a flatutils/andservices/bucket.5. The Agent Class After Refactor (211 lines)
The
Agentclass is now a thin facade. Its entire job is:AgentRunContextfrom the input parametersstreamRequestIdandmcpManageras pass-throughs toctxThe re-exports at the bottom of
Agent.tspreserve backward compatibility for any importers that were consuming types or functions fromAgent.tsdirectly:6. Key Design Decisions
D1: Plain context object over class inheritance / mixins
Decision: Use
AgentRunContextas a passed plain object, not a base class or mixin.Rationale: Avoids the complexity of
super()chains and prototype coupling. Module functions that takectxare easy to test by constructing a minimal partial context. Class hierarchy would have made testing harder.D2: Mutable context fields (
streamRequestId,conversationId, etc.) remain on the objectDecision:
AgentRunContexthas mutable fields (written bysetupGenerationContextand external setters).Rationale: These fields represent per-request state that is set before
generate()is called and then read throughout the pipeline. Passing them as separate function arguments through every call frame would require refactoring every function signature — high noise, no gain. The context object is the right home for request-scoped state.D3:
Agentclass retained (not replaced with plain functions)Decision: Keep
Agentas a class, not convert to a factory function + module exports.Rationale: External callers (
executionHandler.ts,generateTaskHandler.ts, etc.) already instantiateAgentwithnew. Changing to a factory function would require updating every call site without changing behavior. The class shell is preserved; only its innards changed.D4: Re-export types from
Agent.tsfor backward compatibilityDecision: Types moved to
agent-types.tsare re-exported fromAgent.ts.Rationale: External code imports types from
'./Agent'or'../agents/Agent'. Moving the types without re-exporting would break those imports silently in TypeScript if not caught bypnpm check.D5: Parallel tool loading in
loadToolsAndPromptsDecision: All four tool sources (MCP, function, relation, default) are fetched with
Promise.all.Rationale: This was already the behavior on
main— the refactor preserved it explicitly by wiring the parallel fetch throughtool-loading.ts. Making it explicit makes the intent visible rather than buried.7. Impact Surface
Files changed on this branch (run-domain only)
Core refactor targets:
agents/Agent.ts— 3,392 → 211 lines (−94%)agents/agent-types.ts— NEW (239 lines, extracted types + utilities)New modules (generation pipeline):
agents/generation/generate.tsagents/generation/compression.tsagents/generation/conversation-history.tsagents/generation/model-config.tsagents/generation/response-formatting.tsagents/generation/schema-builder.tsagents/generation/system-prompt.tsagents/generation/tool-loading.tsagents/generation/tool-result.tsNew modules (tools):
agents/tools/function-tools.tsagents/tools/mcp-tools.tsagents/tools/relation-tools.tsagents/tools/default-tools.tsagents/tools/tool-approval.tsagents/tools/tool-utils.tsagents/tools/tool-wrapper.tsNew modules (streaming):
agents/streaming/stream-handler.tsagents/streaming/stream-parser.tsRelocated services:
agents/services/AgentMcpManager.ts(wasagents/AgentMcpManager.ts)agents/services/ToolSessionManager.ts(wasagents/ToolSessionManager.ts)Promoted run-domain directories (renamed/moved, not rewritten):
run/stream/(fromrun/utils/+run/services/)run/session/(fromrun/services/)run/compression/(fromrun/services/)run/artifacts/(fromrun/utils/)No changes to:
Agentpublic interface (constructor,generate,getFunctionTools,getRelationTools,cleanup)generateTaskHandler.tscall patternsexecutionHandler.tscall patterns8. Test Coverage
All test files were updated to reflect new import paths. The refactor preserves all existing test cases. The new module structure enables future unit tests to test individual pipeline stages (
buildSystemPrompt,configureModelSettings,setupCompression, etc.) without instantiating a fullAgent.Relevant test files updated:
agents-api/src/__tests__/run/agents/Agent.test.tsagents-api/src/__tests__/run/agents/AgentMcpManager.test.tsagents-api/src/__tests__/run/agents/functionToolApprovals.test.tsagents-api/src/__tests__/run/agents/generateTaskHandler.test.tsagents-api/src/__tests__/run/agents/relationTools.test.tsagents-api/src/__tests__/run/stream/(new location)agents-api/src/__tests__/run/session/(new location)agents-api/src/__tests__/run/compression/(new location)9. Verification
Run
pnpm checkfrom the monorepo root. All of the following must pass:pnpm typecheck— confirms import paths and type compatibility after extractionpnpm lint— confirms no new lint violations from the restructuringpnpm test— confirms no regressions in agent generation, streaming, compression, or tool handlingEvidence: File Inventory
Agent.ts line counts
Diff stats (Agent.ts only)
All files changed on this branch (git diff main...HEAD --name-only)
agents-api/src/domains/run/agents/Agent.ts
agents-api/src/domains/run/agents/agent-types.ts (NEW)
agents-api/src/domains/run/agents/generateTaskHandler.ts
agents-api/src/domains/run/agents/generation/compression.ts (NEW)
agents-api/src/domains/run/agents/generation/conversation-history.ts (NEW)
agents-api/src/domains/run/agents/generation/generate.ts (NEW)
agents-api/src/domains/run/agents/generation/model-config.ts (NEW)
agents-api/src/domains/run/agents/generation/response-formatting.ts (NEW)
agents-api/src/domains/run/agents/generation/schema-builder.ts (NEW)
agents-api/src/domains/run/agents/generation/system-prompt.ts (NEW)
agents-api/src/domains/run/agents/generation/tool-loading.ts (NEW)
agents-api/src/domains/run/agents/generation/tool-result.ts (NEW)
agents-api/src/domains/run/agents/relationTools.ts
agents-api/src/domains/run/agents/services/AgentMcpManager.ts (relocated)
agents-api/src/domains/run/agents/services/ToolSessionManager.ts (relocated)
agents-api/src/domains/run/agents/streaming/stream-handler.ts (NEW)
agents-api/src/domains/run/agents/streaming/stream-parser.ts (NEW)
agents-api/src/domains/run/agents/tools/default-tools.ts (NEW)
agents-api/src/domains/run/agents/tools/function-tools.ts (NEW)
agents-api/src/domains/run/agents/tools/mcp-tools.ts (NEW)
agents-api/src/domains/run/agents/tools/relation-tools.ts (NEW)
agents-api/src/domains/run/agents/tools/tool-approval.ts (NEW)
agents-api/src/domains/run/agents/tools/tool-utils.ts (NEW)
agents-api/src/domains/run/agents/tools/tool-wrapper.ts (NEW)
agents-api/src/domains/run/artifacts/ArtifactParser.ts
agents-api/src/domains/run/artifacts/ArtifactService.ts
agents-api/src/domains/run/artifacts/artifact-component-schema.ts (relocated)
agents-api/src/domains/run/artifacts/artifact-utils.ts (relocated)
agents-api/src/domains/run/compression/BaseCompressor.ts (relocated)
agents-api/src/domains/run/compression/ConversationCompressor.ts (relocated)
agents-api/src/domains/run/compression/MidGenerationCompressor.ts (relocated)
agents-api/src/domains/run/session/AgentSession.ts (relocated)
agents-api/src/domains/run/session/PendingToolApprovalManager.ts (relocated)
agents-api/src/domains/run/session/ToolApprovalUiBus.ts (relocated)
agents-api/src/domains/run/stream/IncrementalStreamParser.ts (relocated)
agents-api/src/domains/run/stream/ResponseFormatter.ts (relocated)
agents-api/src/domains/run/stream/stream-helpers.ts (relocated)
agents-api/src/domains/run/stream/stream-registry.ts (relocated)
(+ test files and route files reflecting updated import paths)
AgentRunContext fields (agent-types.ts:222-238)
config, executionContext, mcpManager, contextResolver,
credentialStoreRegistry, credentialStuffer, systemPromptBuilder,
streamHelper, streamRequestId, conversationId, delegationId,
isDelegatedAgent, artifactComponents, currentCompressor,
functionToolRelationshipIdByName