Skip to content

fix(core): resolve harness v1 agents by id#17678

Open
wardpeet wants to merge 1 commit into
mainfrom
fix/harness-v1-agent-id-resolution
Open

fix(core): resolve harness v1 agents by id#17678
wardpeet wants to merge 1 commit into
mainfrom
fix/harness-v1-agent-id-resolution

Conversation

@wardpeet

@wardpeet wardpeet commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Fixes Harness v1 agent id resolution so modes and subagents can use the agentId-based config shape.

The harness now resolves mode agent ids from either a Mastra instance or the inline agents map when creating sessions. Subagent agent lookup still happens during tool execution, so missing subagent agents return the expected recoverable tool error instead of failing during harness construction.

Test plan:

  • pnpm test:unit src/harness/v1/harness.tools.test.ts
  • pnpm test:unit src/harness/v1/harness.state-workspace.test.ts src/harness/v1/harness.tools.test.ts
  • pnpm test:unit src/harness/v1
  • pnpm --filter ./packages/core check

ELI5

This PR makes it easier to tell the Harness which agent to use by allowing you to just specify an agent ID instead of having to pass the entire agent object. The system now knows how to look up the actual agent from a registry, similar to how you might look up a phone number by a name instead of having to write out the whole contact card.

Changes

Configuration Updates

  • HarnessConfig now makes the default agent field optional in both configuration styles (when using a Mastra instance or inline agents registry)
  • HarnessMode now supports an optional agentId field to specify the backing agent for sessions entered into that mode

Harness v1 Implementation

  • The Harness class now stores an inline agents registry when provided in config
  • Added private helper methods to resolve agents dynamically:
    • #agentForMode(mode) - prefers a mode-specific agentId, falls back to the harness-level agent
    • #tryResolveAgent(agentId) - looks up agents via the Mastra instance or inline registry
    • Updated #resolveAgent to use the new lookup mechanism
  • Session construction now passes per-mode agents instead of a single global agent

Changeset

  • Updated .changeset/dry-paws-wash.md to document the patch release for @mastra/core

Resolve Harness v1 mode and subagent agent ids from Mastra or inline agent registries so harness construction can defer missing subagent failures to tool execution.

This keeps mode-backed sessions working for the agentId-based V1 config shape and preserves recoverable subagent tool errors for missing agents.

Co-Authored-By: Mastra Code (openai/gpt-5.5) <noreply@mastra.ai>
@vercel

vercel Bot commented Jun 8, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
mastra-docs-1.x Ready Ready Preview, Comment Jun 8, 2026 3:50pm
mastra-playground-ui Ready Ready Preview, Comment Jun 8, 2026 3:50pm

Request Review

@changeset-bot

changeset-bot Bot commented Jun 8, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 1c034a8

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 20 packages
Name Type
@mastra/core Patch
mastracode Patch
@mastra/mcp-docs-server Patch
@internal/playground Patch
@mastra/client-js Patch
@mastra/opencode Patch
@mastra/longmemeval Patch
mastra Patch
@mastra/deployer-cloud Patch
@mastra/react Patch
@mastra/playground-ui Patch
@mastra/server Patch
@mastra/deployer Patch
create-mastra Patch
@mastra/express Patch
@mastra/fastify Patch
@mastra/hono Patch
@mastra/koa Patch
@mastra/nestjs Patch
@mastra/temporal Patch

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

@coderabbitai

coderabbitai Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

Harness v1 now supports per-mode agent selection. Modes can specify backing agents via optional agentId, config makes default agents optional, and the harness resolves mode agents with fallback to harness-level agents via Mastra or inline registries.

Changes

Per-Mode Agent Selection

Layer / File(s) Summary
Mode and configuration interfaces
packages/core/src/harness/v1/mode.ts, packages/core/src/harness/v1/harness.types.ts
HarnessMode adds optional agentId field; HarnessConfig makes the default backing agent optional in both mastra: Mastra and inline-agents configuration branches.
Harness field structure and initialization
packages/core/src/harness/v1/harness.ts
Harness class stores optional inline agents registry (#agents) and optional harness-level agent (#agent); constructor initializes both from config when present and branches agent setup on Mastra instance availability.
Mode-aware agent resolution and session setup
packages/core/src/harness/v1/harness.ts
New #agentForMode prefers mode-specific agentId with fallback to harness-level agent; #tryResolveAgent looks up agents via Mastra or inline registry; session creation uses #agentForMode(mode) to pass the selected agent.
Release documentation
.changeset/dry-paws-wash.md
Patch release entry documents the fix for Harness v1 mode subagent agent lookup when agent IDs are used.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes


Suggested labels

tests: no tests added, complexity: medium


Suggested reviewers

  • dane-ai-mastra
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix(core): resolve harness v1 agents by id' is concise (42 characters), uses proper imperative mood with 'resolve', follows conventional commit format, and directly describes the main change in the changeset.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/harness-v1-agent-id-resolution

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint install failed. For unrecoverable errors, disable the tool in CodeRabbit configuration.


Comment @coderabbitai help to get the list of available commands and usage tips.

@dane-ai-mastra dane-ai-mastra Bot added the complexity: low Low-complexity PR label Jun 8, 2026
@dane-ai-mastra

dane-ai-mastra Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

PR triage

Linked issue check skipped for core contributor @wardpeet.


PR complexity score

Factor Value Score impact
Files changed 4 +8
Lines changed 47 +0
Author merged PRs 587 -20
Test files changed No -0
Final score -12

Applied label: complexity: low


Changed test gate

No changed test files were detected.

Label: tests: no tests added

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/core/src/harness/v1/harness.ts (1)

54-128: 🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Missing validation: Modes without agentId must have a harness-level default agent.

The constructor doesn't validate that modes can resolve to agents. When a mode lacks agentId and the harness config provides no default agent, #agentForMode will fail at runtime (see previous comment).

Consider adding validation during construction to ensure every mode either has a valid agentId or the harness has a valid default #agent.

🔍 Proposed validation logic

Add after line 128:

// Validate that all modes can resolve to agents
for (const mode of modes) {
  if (!mode.agentId && !this.#agent) {
    throw new Error(
      `Mode "${mode.id}" has no agentId and harness has no default agent. ` +
      `Either set mode.agentId or provide a harness-level agent in config.`
    );
  }
  // If mode has agentId, validate it's resolvable when using inline agents
  if (mode.agentId && !this.#mastra && !this.#agents?.[mode.agentId]) {
    throw new Error(
      `Mode "${mode.id}" references unknown agent "${mode.agentId}". ` +
      `Agent must be present in config.agents registry.`
    );
  }
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/harness/v1/harness.ts` around lines 54 - 128, Add
validation in the constructor to ensure every mode can resolve to an agent:
after populating this.#modesById (the modes loop in the constructor), iterate
modes and for each mode check that either mode.agentId is set or this.#agent is
present; if neither, throw a descriptive Error referencing mode.id;
additionally, when mode.agentId is set and the harness is using inline agents
(this.#mastra is falsy), verify this.#agents?.[mode.agentId] exists and throw an
Error if it does not. Use the constructor, this.#agent, this.#modesById,
this.#mastra and this.#agents symbols to locate where to insert these checks.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.changeset/dry-paws-wash.md:
- Line 5: Update the changeset description to be user-facing: replace "ids" with
"IDs", remove internal jargon like "agent lookup", and clearly state the
user-visible problem and outcome (e.g., in Harness v1 mode subagents using agent
IDs failed to resolve, and now subagents referenced by agent IDs resolve
correctly), referencing the existing phrases "Harness v1 mode", "subagent", and
"agent IDs" so reviewers can find and replace the current line.

In `@packages/core/src/harness/v1/harness.ts`:
- Around line 315-321: The method `#agentForMode` currently asserts this.#agent as
Agent and can return undefined; change it to validate at runtime: call
this.#tryResolveAgent(mode.agentId) and if it returns an Agent return it, but if
mode.agentId was provided and resolution failed throw a descriptive Error
mentioning the unresolved agentId and the HarnessMode; if mode.agentId is not
provided and this.#agent is undefined throw an Error stating no default agent is
configured; remove the unsafe "as Agent" assertion and ensure the method either
returns a valid Agent or throws so callers (e.g. Session) never receive
undefined.

---

Outside diff comments:
In `@packages/core/src/harness/v1/harness.ts`:
- Around line 54-128: Add validation in the constructor to ensure every mode can
resolve to an agent: after populating this.#modesById (the modes loop in the
constructor), iterate modes and for each mode check that either mode.agentId is
set or this.#agent is present; if neither, throw a descriptive Error referencing
mode.id; additionally, when mode.agentId is set and the harness is using inline
agents (this.#mastra is falsy), verify this.#agents?.[mode.agentId] exists and
throw an Error if it does not. Use the constructor, this.#agent,
this.#modesById, this.#mastra and this.#agents symbols to locate where to insert
these checks.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 549a1c7a-0aa2-4318-ab5c-5c3ebbcbd7d2

📥 Commits

Reviewing files that changed from the base of the PR and between 91bbc38 and 1c034a8.

📒 Files selected for processing (4)
  • .changeset/dry-paws-wash.md
  • packages/core/src/harness/v1/harness.ts
  • packages/core/src/harness/v1/harness.types.ts
  • packages/core/src/harness/v1/mode.ts

'@mastra/core': patch
---

Fixed Harness v1 mode and subagent agent lookup when using agent ids.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Improve the description to highlight the user-facing outcome.

The current description has several issues:

  1. "ids" should be capitalized as "IDs"
  2. The phrase "agent lookup" is internal terminology
  3. It doesn't explain what was broken or what now works for users

As per coding guidelines, changesets should "highlight outcomes" and avoid focusing on "internal implementation details." The description should explain what now works for developers using Harness v1.

✍️ Suggested revision
-Fixed Harness v1 mode and subagent agent lookup when using agent ids.
+Fixed Harness v1 modes and subagents to correctly resolve agents when configured with agent IDs instead of inline agent objects.

Alternatively, focus even more on the outcome:

-Fixed Harness v1 mode and subagent agent lookup when using agent ids.
+Harness v1 modes and subagents now work correctly when using the agent ID–based configuration shape.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Fixed Harness v1 mode and subagent agent lookup when using agent ids.
Fixed Harness v1 modes and subagents to correctly resolve agents when configured with agent IDs instead of inline agent objects.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.changeset/dry-paws-wash.md at line 5, Update the changeset description to
be user-facing: replace "ids" with "IDs", remove internal jargon like "agent
lookup", and clearly state the user-visible problem and outcome (e.g., in
Harness v1 mode subagents using agent IDs failed to resolve, and now subagents
referenced by agent IDs resolve correctly), referencing the existing phrases
"Harness v1 mode", "subagent", and "agent IDs" so reviewers can find and replace
the current line.

Source: Coding guidelines

Comment on lines +315 to +321
#agentForMode(mode: HarnessMode): Agent {
if (mode.agentId) {
const agent = this.#tryResolveAgent(mode.agentId);
if (agent) return agent;
}
return this.#agent as Agent;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Critical: Unsafe type assertion can return undefined as Agent.

The #agentForMode method uses as Agent on line 320, but this.#agent is optional (#agent?: Agent). When both conditions are true:

  1. mode.agentId is either undefined or doesn't resolve to an agent (line 317 returns undefined)
  2. this.#agent is undefined

...the method returns undefined while claiming the return type is Agent. This will cause runtime errors when Session attempts to use the agent.

Additionally, when a mode explicitly specifies an agentId that cannot be resolved (line 317-318), the code silently falls back to this.#agent instead of failing. This masks configuration errors where a mode's agentId is misspelled or references a non-existent agent.

🛡️ Proposed fix with proper validation
 `#agentForMode`(mode: HarnessMode): Agent {
   if (mode.agentId) {
     const agent = this.#tryResolveAgent(mode.agentId);
-    if (agent) return agent;
+    if (!agent) {
+      throw new Error(`Mode "${mode.id}" references unknown agent "${mode.agentId}"`);
+    }
+    return agent;
   }
-  return this.#agent as Agent;
+  if (!this.#agent) {
+    throw new Error(`Mode "${mode.id}" has no agentId and harness has no default agent`);
+  }
+  return this.#agent;
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/harness/v1/harness.ts` around lines 315 - 321, The method
`#agentForMode` currently asserts this.#agent as Agent and can return undefined;
change it to validate at runtime: call this.#tryResolveAgent(mode.agentId) and
if it returns an Agent return it, but if mode.agentId was provided and
resolution failed throw a descriptive Error mentioning the unresolved agentId
and the HarnessMode; if mode.agentId is not provided and this.#agent is
undefined throw an Error stating no default agent is configured; remove the
unsafe "as Agent" assertion and ensure the method either returns a valid Agent
or throws so callers (e.g. Session) never receive undefined.

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

Labels

complexity: low Low-complexity PR tests: no tests added PR does not change test files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant