Skip to content

feat(backends): add NativeToolEngine abstract base class for subprocess engines#1019

Merged
aaight merged 2 commits intodevfrom
feature/native-tool-engine-base-class
Mar 23, 2026
Merged

feat(backends): add NativeToolEngine abstract base class for subprocess engines#1019
aaight merged 2 commits intodevfrom
feature/native-tool-engine-base-class

Conversation

@aaight
Copy link
Copy Markdown
Collaborator

@aaight aaight commented Mar 23, 2026

Summary

  • Creates NativeToolEngine abstract base class in src/backends/shared/NativeToolEngine.ts that consolidates shared patterns from Claude Code, Codex, and OpenCode engines
  • Barrel export at src/backends/shared/index.ts and re-exported from src/backends/index.ts
  • Unit tests in tests/unit/backends/NativeToolEngine.test.ts with a StubEngine extends NativeToolEngine

What was implemented

src/backends/shared/NativeToolEngine.ts

Abstract base class implementing AgentEngine with:

  • Abstract methods: getAllowedEnvExact(), getExtraEnvVars(), resolveEngineModel(), execute()
  • Shared resolveModel(): delegates to resolveEngineModel() so the AgentEngine contract is met
  • Shared supportsAgentType(): returns true (all native-tool engines support all agent types), overridable
  • Shared buildEnv(): calls buildEngineEnv() with engine-specific allowlist and extra vars
  • Shared afterExecute(): calls cleanupContextFiles() — engines with additional cleanup override and call super.afterExecute()

src/backends/shared/index.ts

New barrel export for the shared module.

src/backends/index.ts

Re-exports NativeToolEngine from the shared barrel.

Test plan

  • 19 unit tests in NativeToolEngine.test.ts covering all shared methods via a StubEngine stub
  • All 6,717 unit tests pass (no regressions)
  • TypeScript type checking passes with zero errors
  • Lint passes with zero errors

Notes

  • LLMist is intentionally excluded — it's an in-process SDK, not a subprocess engine
  • Existing engine implementations (Claude Code, Codex, OpenCode) are NOT migrated in this story (separate downstream stories)
  • The AgentEngine interface is unchanged

Trello card: https://trello.com/c/cWjLnCjl/537-as-a-developer-i-want-a-nativetoolengine-abstract-base-class-so-that-shared-subprocess-engine-logic-is-consolidated

🤖 Generated with Claude Code

🕵️ claude-code · claude-sonnet-4-6 · run details

@codecov
Copy link
Copy Markdown

codecov Bot commented Mar 23, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

Copy link
Copy Markdown
Collaborator

@nhopeatall nhopeatall left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary

Clean, well-structured abstract base class that correctly consolidates shared native-tool engine patterns. All CI checks pass, type checking is clean, and the 19 unit tests cover all shared methods well. No blocking issues.

Should Fix

  • src/backends/shared/NativeToolEngine.ts:5 — Doc claims the class provides "System/task prompt building via buildSystemPrompt / buildTaskPrompt" but the class does not actually expose or delegate to these functions — they remain standalone imports from nativeToolPrompts.ts that each engine calls directly in its own execute(). Consider removing this bullet (it describes a codebase pattern, not a class responsibility) or, if a future story will move prompt building into the base class, noting that explicitly.

  • src/backends/shared/NativeToolEngine.ts:15 — Doc says subclasses must implement executeTurn() but the actual abstract method is execute() (line 108). This looks like a leftover from an earlier design where the base class would own the continuation loop and delegate single turns to subclasses. Please update to match the actual contract.

🕵️ claude-code · claude-opus-4-6 · run details

Remove the erroneous bullet about buildSystemPrompt/buildTaskPrompt (those
functions are standalone imports used by each engine's own execute(), not a
base class responsibility). Also correct the abstract method name from
executeTurn() to execute() to match the actual contract.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown
Collaborator

@nhopeatall nhopeatall left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary

LGTM — clean, well-designed abstract base class that correctly consolidates the shared subprocess engine patterns.

The NativeToolEngine accurately captures the common surface across Claude Code, Codex, and OpenCode engines:

  • buildEnv() delegates to buildEngineEnv with the same signature pattern used by the existing per-engine env builders (e.g., codex/env.ts:buildEnv, claude-code/env.ts:buildClaudeEnv). The allowedEnvExact parameter correctly expects only engine-specific vars since buildEngineEnv already merges SHARED_ALLOWED_ENV_EXACT internally.
  • afterExecute() implements the shared minimum (cleanupContextFiles), leaving space for subclasses to override and call super.afterExecute() for engine-specific cleanup (persisted sessions, token capture, etc.).
  • resolveModel()resolveEngineModel() delegation is a clean template-method pattern that satisfies the AgentEngine contract without forcing subclasses to know about the interface method name.
  • beforeExecute and getSettingsSchema are correctly omitted from the base class since not all engines implement them (OpenCode has no beforeExecute).

Interface conformance is correct — required AgentEngine members are covered (abstract definition, abstract execute, concrete supportsAgentType), and optional members (resolveModel, afterExecute) are implemented where the shared pattern applies.

Tests are thorough (19 tests covering all shared methods via StubEngine), mocks are clean, and CI is fully green.

🕵️ claude-code · claude-opus-4-6 · run details

@aaight aaight merged commit 8b3925a into dev Mar 23, 2026
9 checks passed
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