Skip to content

Conversation

@ammar-agent
Copy link
Collaborator

@ammar-agent ammar-agent commented Feb 7, 2026

Summary

Continues the decomposition of the monolithic AIService.streamMessage() method, extracting self-contained concerns into focused modules and simplifying the orchestration code that remains.

Background

AIService was 1,367 lines with streamMessage() accounting for ~900 of those. Previous PRs (#2242) extracted agent resolution and stream context building. This PR continues with simulation, tool assembly, model resolution, and structural cleanup.

Implementation

Commit 1: Extract simulation + tool assembly

  • streamSimulation.ts (185 lines): simulateContextLimitError and simulateToolPolicyNoop β€” synthetic stream event sequences for OpenAI SDK testing features (forceContextLimitError, simulateToolPolicyNoop).
  • toolAssembly.ts (235 lines): applyToolPolicyAndExperiments (tool policy + PTC lazy-loading) and captureMcpToolTelemetry (MCP stats + telemetry emission). Moves the PTC singleton (getPTCModules) entirely out of aiService.ts.

Commit 2: Model resolution + MCP telemetry + DRY cleanup

  • providerModelFactory.ts: Added resolveAndCreateModel() combining xAI Grok variant mapping, gateway resolution, and model creation into a single call.
  • Event forwarding: Replaced 9 individual one-liner event forwarding calls with a single for-of loop.
  • Abort handling: Consolidated two identical 7-line blocks into a deleteAbortedPlaceholder helper.
  • JSDoc: Trimmed 18-line @param block, removed backward-compat re-export.

Commit 3: Options bag + safeClone + inline cleanup

  • StreamMessageOptions: Converted streamMessage() from 19 positional parameters to a typed options bag. Call sites are now self-documenting with named fields instead of undefined placeholders.
  • safeClone<T>(): Extracted DRY utility for the duplicated structuredClone-with-JSON-fallback pattern (used in 2 debug snapshot capture sites).
  • Inline cleanups: Removed providerForMessages alias, no-op OpenAI debug block, unused workspace variable, stale comments. Moved assistantMessageId creation before PTC callback for clearer closure capture.

Metrics

Metric Before After Change
aiService.ts lines 1,367 1,111 βˆ’256 (βˆ’19%)
New module lines 0 420 +420
Net LoC change β€” β€” +164 (complexity moved, not duplicated)

Validation

  • All 3,446 tests pass (make test)
  • All static checks pass (make static-check)
  • Purely mechanical extraction β€” no behavioral changes

Generated with mux β€’ Model: anthropic:claude-opus-4-6 β€’ Thinking: xhigh β€’ Cost: $251.22

…essage()

Extract two more cohesive blocks from the monolithic streamMessage() method:

1. streamSimulation.ts: Synthetic stream event sequences for testing
   - simulateContextLimitError(): context-exceeded error simulation
   - simulateToolPolicyNoop(): tool-policy-disabled noop response
   - Shared SimulationContext + deduplicated StreamStartEvent construction

2. toolAssembly.ts: Tool policy application + PTC experiment handling
   - applyToolPolicyAndExperiments(): merges extra tools, applies policy,
     lazy-loads PTC (typescript/prettier/QuickJS WASM) only when needed
   - Moves the entire PTC lazy-loading singleton out of aiService.ts

Additional cleanup:
- Simplified 9 one-liner event forwards into a for-of loop
- Removed backwards-compat re-export (test now imports directly)
- Removed 12 PTC/simulation-specific imports from aiService.ts

aiService.ts: 1367 β†’ 1180 lines (βˆ’187, βˆ’14%)
All 3,446 tests pass.
…bort-delete

1. Move model string resolution into ProviderModelFactory.resolveAndCreateModel():
   - xAI Grok variant mapping (reasoning vs non-reasoning based on thinking level)
   - Gateway model string resolution
   - Model creation
   Removes normalizeGatewayModel + parseModelString imports from aiService.ts.

2. Extract MCP telemetry capture into captureMcpToolTelemetry() in toolAssembly.ts:
   - Stats computation (effective MCP stats, tool counts)
   - Telemetry event emission
   - Tool configuration logging
   Removes getRuntimeTypeForTelemetry + roundToBase2 imports from aiService.ts.

3. Trim 18-line @param JSDoc block on streamMessage() β€” type signatures
   are self-documenting, the comments just repeated parameter names.

4. DRY the duplicate abort-delete-placeholder pattern:
   Two identical 7-line blocks consolidated into a local helper closure.

aiService.ts: 1180 β†’ 1101 lines (βˆ’79, cumulative βˆ’266 from 1367 on main)
- Convert streamMessage() from 19 positional params to typed StreamMessageOptions bag.
  The old call sites (agentSession, replay-history CLI) are now self-documenting β€” no more
  `undefined` placeholder args or positional confusion.

- Extract safeClone<T>() utility to DRY the structuredClone-with-JSON-fallback pattern
  (used in both debug snapshot capture sites).

- Inline cleanups:
  - Remove providerForMessages alias (was just canonicalProviderName)
  - Remove no-op OpenAI debug log block
  - Simplify workspace existence check (drop unused variable)
  - Move assistantMessageId creation before PTC callback for clarity
  - Trim stale comments

- Update postCompactionRetry tests: access options bag fields by name instead of
  positional indices.
@ammar-agent ammar-agent changed the title πŸ€– refactor: extract simulation + tool policy/PTC from AIService.streamMessage() πŸ€– refactor: decompose AIService.streamMessage() β€” Phase 1b Part 2 Feb 7, 2026
@ammario ammario merged commit b3fe453 into main Feb 7, 2026
23 checks passed
@ammario ammario deleted the refactor/extract-simulation-and-tools-from-aiservice branch February 7, 2026 22:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants