Skip to content

refactor: unify AddResult and RemovalResult into Result<T>#1088

Draft
Hweinstock wants to merge 1 commit intoaws:mainfrom
Hweinstock:refactor/unified-result-type
Draft

refactor: unify AddResult and RemovalResult into Result<T>#1088
Hweinstock wants to merge 1 commit intoaws:mainfrom
Hweinstock:refactor/unified-result-type

Conversation

@Hweinstock
Copy link
Copy Markdown
Contributor

@Hweinstock Hweinstock commented May 1, 2026

Description

Introduces a unified Result<T> discriminated union type that replaces both AddResult<T> and RemovalResult, inspired by Rust's Result<T, E>.

export type Result<T = void> = T extends void
  ? { success: true } | { success: false; error: Error }
  : { success: true; data: T } | { success: false; error: Error };

Key changes:

  • Error fields carry Error objects instead of raw strings — enables stack traces, cause chains, and instanceof narrowing
  • data field wraps success payload instead of intersection spread — no more field name collisions
  • data is required on the success branch when T is not void (compiler-enforced), absent when T is void (removals)
  • AddResult<T> and RemovalResult labeled as proxies to shared Result shape.

Why

  • inconsistent result types across the codebase leads to bloated code implementations to handle all possible types (ex. telemetry).
  • error information is lost by distilling it to a string, instead of maintaining full error context (stack trace, type, etc).

Related Issue

Closes #

Documentation PR

N/A — internal type refactor, no user-facing changes.

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation update
  • Other (please describe): Internal type refactor

Testing

How have you tested the change?

  • I ran npm run test:unit and npm run test:integ
  • I ran npm run typecheck
  • I ran npm run lint
  • If I modified src/assets/, I ran npm run test:update-snapshots and committed the updated snapshots

Checklist

  • I have read the CONTRIBUTING document
  • I have added any necessary tests that prove my fix is effective or my feature works
  • I have updated the documentation accordingly
  • I have added an appropriate example to the documentation to outline the feature, or no new docs are needed
  • My changes generate no new warnings
  • Any dependent changes have been merged and published

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the
terms of your choice.

@github-actions github-actions Bot added size/l PR size: L agentcore-harness-reviewing AgentCore Harness review in progress labels May 1, 2026
@agentcore-cli-automation
Copy link
Copy Markdown

Thanks for the refactor — the shape of Result<T> is nice. A couple of issues in the implementation that I think should be fixed before merging, both of which undercut one of the PR's stated goals ("stack traces, cause chains, and instanceof narrowing"):

1. Catch blocks discard the original Error and rebuild a fresh one

Five call sites use this pattern:

} catch (err) {
  const message = err instanceof Error ? err.message : 'Unknown error';
  return { success: false, error: new Error(message) };
}

When err is already an Error (the common case), this extracts its .message and wraps it in a brand-new Error, throwing away the original class, stack trace, and any cause. That's exactly the opposite of what the PR is trying to enable.

Locations:

  • src/cli/primitives/AgentPrimitive.tsx:169-170 (in remove)
  • src/cli/primitives/CredentialPrimitive.tsx:122-123
  • src/cli/primitives/GatewayPrimitive.ts:89-90
  • src/cli/primitives/GatewayTargetPrimitive.ts:229-230
  • src/cli/operations/remove/remove-gateway-target.ts:203-204

Other catch blocks in the same PR already use the correct shape:

} catch (err) {
  return { success: false, error: err instanceof Error ? err : new Error(getErrorMessage(err)) };
}

Suggest converting the five sites above to that form so the original Error flows through unchanged.

2. NoProjectError is wrapped in a generic Error in AgentPrimitive.add

In src/cli/primitives/AgentPrimitive.tsx lines 122 and 128:

return { success: false, error: new Error(new NoProjectError().message) };

This constructs a NoProjectError, reads its .message, and then discards it to build a generic Error. Callers can't instanceof NoProjectError on the result and the custom class serves no purpose here.

Interestingly, src/cli/tui/screens/agent/useAddAgent.ts — changed in the same PR — handles the same situation correctly:

return { success: false, error: new NoProjectError() };

Suggest making AgentPrimitive.add consistent and returning new NoProjectError() directly in both branches.


Both of these are mechanical fixes and don't affect the public shape of Result<T>, so no test changes should be required beyond what's already in the PR.

@github-actions github-actions Bot removed the agentcore-harness-reviewing AgentCore Harness review in progress label May 1, 2026
@Hweinstock Hweinstock force-pushed the refactor/unified-result-type branch from a2eccff to 530a76e Compare May 1, 2026 19:26
@github-actions github-actions Bot added size/l PR size: L and removed size/l PR size: L labels May 1, 2026
@Hweinstock Hweinstock force-pushed the refactor/unified-result-type branch from 530a76e to 4c58c70 Compare May 1, 2026 19:28
@github-actions github-actions Bot added size/l PR size: L and removed size/l PR size: L labels May 1, 2026
@Hweinstock Hweinstock force-pushed the refactor/unified-result-type branch from 4c58c70 to 6255734 Compare May 1, 2026 19:31
@github-actions github-actions Bot added size/l PR size: L and removed size/l PR size: L labels May 1, 2026
@Hweinstock
Copy link
Copy Markdown
Contributor Author

addressed missed migrations, and avoided rewrapping error.

@Hweinstock Hweinstock force-pushed the refactor/unified-result-type branch from 6255734 to 7a6c9df Compare May 1, 2026 20:24
@github-actions github-actions Bot added size/l PR size: L and removed size/l PR size: L labels May 1, 2026
@Hweinstock Hweinstock force-pushed the refactor/unified-result-type branch from 7a6c9df to e2bafea Compare May 1, 2026 20:48
@github-actions github-actions Bot added size/m PR size: M and removed size/l PR size: L labels May 1, 2026
@Hweinstock Hweinstock force-pushed the refactor/unified-result-type branch from e2bafea to 0ba5c9c Compare May 1, 2026 21:01
@github-actions github-actions Bot added size/l PR size: L and removed size/m PR size: M labels May 1, 2026
@Hweinstock Hweinstock force-pushed the refactor/unified-result-type branch from 0ba5c9c to b47e7fc Compare May 1, 2026 21:22
@github-actions github-actions Bot added size/l PR size: L and removed size/l PR size: L labels May 1, 2026
- Introduce Result<T> discriminated union with data field (Rust-inspired)
- Error fields now carry Error objects instead of raw strings
- AddResult<T> and RemovalResult preserved as deprecated aliases
- data is required on success branch when T is not void
- No data field when T is void (removals)

44 files changed, all tests passing (3901 tests)
@Hweinstock Hweinstock force-pushed the refactor/unified-result-type branch from b47e7fc to d4898a7 Compare May 1, 2026 22:11
@github-actions github-actions Bot added size/xl PR size: XL and removed size/l PR size: L labels May 1, 2026
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.

2 participants