Skip to content

feat(project): add project-aware invoke - #2115

Open
aidandaly24 wants to merge 15 commits into
aws:refactorfrom
aidandaly24:feat/project-aware-invoke
Open

feat(project): add project-aware invoke#2115
aidandaly24 wants to merge 15 commits into
aws:refactorfrom
aidandaly24:feat/project-aware-invoke

Conversation

@aidandaly24

@aidandaly24 aidandaly24 commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

Description

Add project-aware invocation for Runtimes and Harnesses declared by the project enclosing the current directory.

  • add agentcore project invoke as an interactive picker for deployed project Runtimes and Harnesses on the default target
  • add explicit headless child commands:
    • agentcore project invoke runtime --name <name> --payload <payload>
    • agentcore project invoke harness --name <name> --prompt <prompt>
  • allow --name to be omitted when the project declares exactly one resource of that type
  • resolve logical project names to deployed physical IDs and regions through the selected deployment target and live CloudFormation stack
  • preserve the existing Runtime payload, content-type, response, output-file, and JSON behavior
  • preserve the existing Harness prompt, session, transcript, and chat behavior
  • reuse the Runtime and Harness invoke operations and TUI consoles instead of adding a third transport or presentation path
  • document project invoke in the CLI and generated Runtime templates

This PR intentionally does not define a project-specific Runtime payload or response contract. Runtime responses retain the existing raw invoke behavior, including raw SSE. Gateway project invoke remains outside this scope.

The project deployment prerequisites are already present on refactor:

Related Issue

N/A

Documentation PR

N/A - documentation is included.

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation update
  • Other

Testing

  • bun test src: 2236 pass, 0 fail
  • focused project/Runtime/Harness invoke suites: 149 pass, 0 fail
  • bun run typecheck
  • bun run lint:check
  • bun run format:check
  • bun run secrets:check
  • bun run build
  • git diff --check

Live verification in account 603141041947, region us-west-2, using the retained InvokeMatrix827 project:

  • Runtime headless invoke omitted --name, preserved the native raw SSE response, and returned REBASED_RUNTIME_OK
  • Harness headless invoke omitted --name, preserved the transcript response, and returned REBASED_HARNESS_OK
  • the 120x40 TUI harness listed the project Runtime and Harness with type, protocol, and source
  • Runtime selection opened the existing endpoint picker and JSON console
  • Harness selection opened the existing chat
  • Escape returned from both embedded consoles to the project picker without leaving the TUI process

Checklist

  • I have added tests that prove the feature works
  • I have updated relevant documentation
  • I have verified direct Runtime and Harness behavior remains green
  • I have run live deployment and TUI verification
  • Dependent changes have been merged and published

@github-actions github-actions Bot added the size/xl PR size: XL label Aug 26, 2026
@agentcore-devx-automation agentcore-devx-automation Bot added agentcore-harness-reviewing AgentCore Harness review in progress claude-security-reviewing Claude Code /security-review in progress labels Aug 26, 2026
@agentcore-devx-automation

Copy link
Copy Markdown
Contributor

Claude Security Review: no high-confidence findings. (run)

@agentcore-devx-automation agentcore-devx-automation Bot removed the claude-security-reviewing Claude Code /security-review in progress label Aug 26, 2026
@codecov-commenter

codecov-commenter commented Aug 26, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 97.56098% with 13 lines in your changes missing coverage. Please review.
✅ Project coverage is 97.25%. Comparing base (b18bb4b) to head (98f2da8).
⚠️ Report is 2 commits behind head on refactor.

Files with missing lines Patch % Lines
src/handlers/project/invoke/runtime.tsx 97.14% 4 Missing ⚠️
src/handlers/project/invoke/selection.ts 85.71% 4 Missing ⚠️
src/handlers/project/invoke/index.tsx 87.50% 3 Missing ⚠️
src/handlers/project/invoke/harness.tsx 98.36% 1 Missing ⚠️
src/handlers/project/invoke/screen.tsx 99.17% 1 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##           refactor    #2115      +/-   ##
============================================
- Coverage     97.25%   97.25%   -0.01%     
============================================
  Files           472      479       +7     
  Lines         29018    29491     +473     
============================================
+ Hits          28221    28681     +460     
- Misses          797      810      +13     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@agentcore-devx-automation agentcore-devx-automation 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.

AgentCore Harness Review

Verdict: Looks good

Nice split: the shared invokeRuntimeTarget / invokeHarnessTurn helpers cleanly refactor the existing handlers into reusable operations, the new project-level invoke composes those without duplication, and the resolveDeployedResource layering (manager → backend → deployment helpers) is easy to follow. Tests use real temp dirs + fake backends, and only mock at true I/O boundaries (readStack, per the guidelines).

One thing worth double-checking before this fully lights up end-to-end:

  • src/core/project/backends/cdk/deployment.ts:28 looks up harnesses by CloudFormation export name ${stackName}-Harness-${resourceName}-Id. Scanning agentcore-l3-cdk-constructs, the harness constructs (AgentCoreHarnessEnvironment, AgentCoreHarnessRole, AgentCoreApplication) currently only emit Harness-<name>-RoleArn and Harness-<name>-ImageUri outputs — no Harness-<name>-Id. Runtime lookup will work today (AgentEnvironment.ts emits <agentName>-RuntimeId), but agentcore invoke --harness ... will always fail with the "not deployed" error until the L3 emits that export. If a coordinated L3 change is in flight this is fine; if not, this handler and its export-name contract will need to land together with the construct change (and ideally the runtime path in AgentEnvironment.ts should probably also be prefixed like -Runtime-<name>-Id for symmetry with Harness-<name>-Id, but that's a naming choice).

Not blocking — tests all pass with a fake backend, and if the harness export is a known follow-up this is just a heads-up. Everything else (validation, mutual-exclusion, --json requiring content, session-id length rule, bearer-token restricted to runtime, TUI launch with inputMode: "prompt", region override from the resolved target) reads correctly.

@agentcore-devx-automation agentcore-devx-automation Bot removed the agentcore-harness-reviewing AgentCore Harness review in progress label Aug 26, 2026
@aidandaly24
aidandaly24 force-pushed the feat/project-aware-invoke branch from f2c164c to c6796be Compare August 26, 2026 22:02
@github-actions github-actions Bot added size/xl PR size: XL and removed size/xl PR size: XL labels Aug 26, 2026
@agentcore-devx-automation agentcore-devx-automation Bot added the claude-security-reviewing Claude Code /security-review in progress label Aug 26, 2026
@agentcore-devx-automation

Copy link
Copy Markdown
Contributor

Claude Security Review: no high-confidence findings. (run)

@agentcore-devx-automation agentcore-devx-automation Bot removed the claude-security-reviewing Claude Code /security-review in progress label Aug 26, 2026
@github-actions github-actions Bot added size/xl PR size: XL and removed size/xl PR size: XL labels Aug 26, 2026
@agentcore-devx-automation agentcore-devx-automation Bot added the claude-security-reviewing Claude Code /security-review in progress label Aug 26, 2026
@agentcore-devx-automation

Copy link
Copy Markdown
Contributor

Claude Security Review: no high-confidence findings. (run)

@agentcore-devx-automation agentcore-devx-automation Bot removed the claude-security-reviewing Claude Code /security-review in progress label Aug 26, 2026
@github-actions github-actions Bot added size/xl PR size: XL and removed size/xl PR size: XL labels Aug 27, 2026
@agentcore-devx-automation agentcore-devx-automation Bot added the claude-security-reviewing Claude Code /security-review in progress label Aug 27, 2026
@agentcore-devx-automation

Copy link
Copy Markdown
Contributor

Claude Security Review: no high-confidence findings. (run)

@agentcore-devx-automation agentcore-devx-automation Bot removed the claude-security-reviewing Claude Code /security-review in progress label Aug 27, 2026
@agentcore-devx-automation

Copy link
Copy Markdown
Contributor

Claude Security Review: no high-confidence findings. (run)

@agentcore-devx-automation

Copy link
Copy Markdown
Contributor

Claude Security Review: no high-confidence findings. (run)

@agentcore-devx-automation

Copy link
Copy Markdown
Contributor

Claude Security Review: no high-confidence findings. (run)

@agentcore-devx-automation

Copy link
Copy Markdown
Contributor

Claude Security Review: no high-confidence findings. (run)

@agentcore-devx-automation

Copy link
Copy Markdown
Contributor

Claude Security Review: no high-confidence findings. (run)

@agentcore-devx-automation

Copy link
Copy Markdown
Contributor

Claude Security Review: no high-confidence findings. (run)

@agentcore-devx-automation

Copy link
Copy Markdown
Contributor

Claude Security Review: no high-confidence findings. (run)

@agentcore-devx-automation

Copy link
Copy Markdown
Contributor

Claude Security Review: no high-confidence findings. (run)

@agentcore-devx-automation

Copy link
Copy Markdown
Contributor

Claude Security Review: no high-confidence findings. (run)

@Hweinstock Hweinstock 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.

thanks for making this change, I know its a big, but critical one. I honestly didn't get to all of it, but saw a few patterns I wanted to comment on:

  • not all of the invoke runtime logic lives in core, so we end up importing across handlers, and breaking dependency inversion boundary to share this functionality, but it feels like we're fighting the framework/architecture. Might be worth chatting w/ @AlexanderRichey to hear his vision on where this logic should live since he knows it best.
  • the tui being conditionally rendered rather than only on no flags adds a lot of complexity downstream with that launch context being passed around, and I'm wondering if this is required?

Comment thread src/handlers/project/invoke/index.tsx Outdated
qualifier: flags.qualifier,
bearerToken,
};
await renderInvokeTui(

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.

wouldn't this mean if I do agentcore project invoke --session-id .. --qualifier .. --target .. --bearer-token we would open the TUI?

I thought the convention was that no flags => open TUI.

I'm open to breaking this, but I do think we need to be consistent since it might confuse a customer (or their agent) if it varies by command what determines if a TUI opens.

On the flip side, I do think this existing convention helps keep things simple. For example, we don't need the branching logic here to conditionally render the tui in a few places.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yeah this is legacy from the old CLI. Runtime and Harness invoke already treat session, qualifier, authentication, and target values as TUI launch configuration. Project invoke is consistent with those commands.

I definitely agree with the concern about the pattern, like you mention. But I also agree with what you say where it keeps things simple. This makes it so that I am able to do things like pass a bearer token or an session id, before i open the TUI. If this wasn't an option we would need to provide a way for the user to do that within the TUI. Which we wanted to avoid for right now.

Comment thread src/handlers/project/invoke/index.tsx Outdated
throw new InputValidationError("--bearer-token is only valid with --runtime");
}
if (
selected.resourceType === "harness" &&

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.

doesn't a similar constraint also apply to runtime (with a higher cap)? https://docs.aws.amazon.com/bedrock-agentcore/latest/APIReference/API_InvokeAgentRuntime.html#API_InvokeAgentRuntime_RequestSyntax

unreleated to changes here but I wonder why they are different max length?

Comment thread src/handlers/project/invoke/index.tsx Outdated

function targetContext(ctx: Context, region: string): Context {
return ctx.withValue(RegionKey, region);
}

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.

what's the advantage of making this a function? I feel like it adds an unnecessary layer of indirection.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thought I had removed this. Will fix this.

Comment thread src/handlers/project/invoke/index.tsx Outdated
import { argument, createHandler, flag, ProjectKey, type Context } from "../../../router";
import { JsonRendererKey, renderTuiAt } from "../../../tui";
import { RuntimeInvokeLaunchContextKey } from "../../runtime/invoke/launchContext";
import { invokeRuntimeTarget } from "../../runtime/invoke/operation";

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.

this feels strange to me. I'm not sure we want handlers from project depending on imperative handlers. I feel like core should be where this shared functionality lives.

My understanding of the setup was that handlers serve as a "ui shell" over the functionality that handle routing and validation, with core implementing the core logic. However, I think @AlexanderRichey would know better.

@aidandaly24 aidandaly24 Aug 28, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yeah, I had the same concern. I extracted these operations because duplicating the Runtime and Harness invocation flows under project felt incorrect. I agree the dependency direction is unusual, though, and invokeRuntimeTarget in particular may belong behind CoreRuntimeClient.

The complication is that the current Runtime operation composes handler-owned request normalization, while the Harness operation folds service events into the handler-owned transcript model. I don’t think source resolution, terminal output, TUI state, or transcript presentation should move into Core, but there
may be a cleaner split where Core owns the Runtime lookup/normalization/invocation workflow and handlers retain presentation policy.

I’d definitely like to check with @AlexanderRichey before changing this too much so we follow the intended architecture

Comment thread src/handlers/project/invoke/index.tsx Outdated
}

if (selected.resourceType === "harness") {
const result = await invokeHarnessTurn(

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.

where we do handle user cancellations for harness? I see the wrapper for runtime below.

Comment thread README.md Outdated
agentcore project invoke

# The project-aware shorthand has the same behavior inside a project.
agentcore invoke

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.

thanks for updating the docs!

Also, I like this idea of making it project aware, but I wonder if we should revisit this with all project commands together to make sure the behavior is consistent. If the team has already aligned this is where we're heading than I'm good to leave it in.

Comment thread src/errors/errors.test.tsx Outdated
expect(UserCancellationError.resolve(new Error("failed"))).toBeUndefined();
});

test("RuntimeAgentResponseError is a visible service failure", () => {

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.

nit: could this be part of the test.each below? Its doing the same thing with one more check for a check for silent, which could be added as a parameter to the tabled test.

ex.

test.each([
...
[
  "RuntimeAgentResponseError", 
   new RuntimeAgentResponseError("Model access denied"),
   "service", 
   false" // not silent
]
...

Comment thread src/core/project/manager.test.ts Outdated
});

describe("FsProjectManager.resolveDeployedResource", () => {
const targets: AwsDeploymentTarget[] = [

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.

q: what behavior are we testing here, that we don't get through the handlers?

@@ -0,0 +1,125 @@
import { parseAgentEvent } from "../../../core/project/agentEventParser";

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.

isn't this breaking the dependency inversion?

Comment thread src/core/project/agentEventParser.ts Outdated
@@ -0,0 +1,60 @@
export type AgentEvent =

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.

I'm kind of confused where this fits in. Isn't this assuming a certain response shape from the customer's runtime?

@agentcore-devx-automation

Copy link
Copy Markdown
Contributor

Claude Security Review: no high-confidence findings. (run)

@agentcore-devx-automation

Copy link
Copy Markdown
Contributor

Claude Security Review: no high-confidence findings. (run)

@agentcore-devx-automation

Copy link
Copy Markdown
Contributor

Claude Security Review: no high-confidence findings. (run)

@agentcore-devx-automation

Copy link
Copy Markdown
Contributor

Claude Security Review: no high-confidence findings. (run)

@agentcore-devx-automation

Copy link
Copy Markdown
Contributor

Claude Security Review: no high-confidence findings. (run)

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

Labels

size/xl PR size: XL

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants