Skip to content

fix(terminal-service): gracefully handle missing agent profiles in CAO store#186

Merged
haofeif merged 2 commits into
awslabs:mainfrom
anilkmr-a2z:fix/agent-profile-not-found
Apr 18, 2026
Merged

fix(terminal-service): gracefully handle missing agent profiles in CAO store#186
haofeif merged 2 commits into
awslabs:mainfrom
anilkmr-a2z:fix/agent-profile-not-found

Conversation

@anilkmr-a2z

Copy link
Copy Markdown
Contributor

Problem

load_agent_profile() raises FileNotFoundError for agents whose profiles
only exist as .json files (e.g. ~/.kiro/agents/my-agent.json). The call
in terminal_service.create_terminal() was unguarded, causing terminal
creation to fail with:

Failed to create terminal: Agent profile not found: my-agent

This was introduced in #145 when profile loading was hoisted to a top-level
call outside the allowed_tools block, but the FileNotFoundError guard
was not moved with it.

Fix

Wrap load_agent_profile() in try/except FileNotFoundError and gate
allowed_tools resolution on profile is not None. For kiro_cli, the
profile is resolved natively by kiro-cli itself — CAO not finding it in
its own store is expected and non-fatal.

This matches the documented behavior in docs/kiro-cli.md:

If the agent is not found, CAO gracefully falls back — kiro-cli resolves
.json profiles natively

Changes

  • services/terminal_service.py: guard load_agent_profile() call
  • test/cli/commands/test_launch.py: update test to reflect that CWD is
    always passed (working-directory inheritance behavior)

@codecov-commenter

codecov-commenter commented Apr 18, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
⚠️ Please upload report for BASE (main@d472f64). Learn more about missing BASE report.

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #186   +/-   ##
=======================================
  Coverage        ?   91.71%           
=======================================
  Files           ?       55           
  Lines           ?     4394           
  Branches        ?        0           
=======================================
  Hits            ?     4030           
  Misses          ?      364           
  Partials        ?        0           
Flag Coverage Δ
unittests 91.71% <100.00%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 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.

@anilkmr-a2z anilkmr-a2z force-pushed the fix/agent-profile-not-found branch from 4ede555 to 2c78115 Compare April 18, 2026 00:09
@haofeif

haofeif commented Apr 18, 2026

Copy link
Copy Markdown
Contributor

@anilkmr-a2z thanks for the great work. just some minor comments:

1 — Unrelated test_launch.py assertion change — Priority: Medium

# before
assert params["working_directory"] == os.path.realpath(os.getcwd())
# after
assert params["working_directory"] == os.getcwd()

Why this is worth flagging:

  • Production at src/cli_agent_orchestrator/cli/commands/launch.py:53 still calls os.path.realpath(os.getcwd()) — unchanged by this PR.
  • The new assertion no longer verifies the realpath() behavior. On platforms where CWD is a symlink (e.g. macOS /tmp → /private/tmp), the test will assert the unresolved path while production sends the resolved path — the opposite of what we want.
  • On typical dev/CI paths (/Users/..., /home/..., /workspace/...) there are no symlinks, so both old and new assertions pass — which is probably why this slipped past local validation. It's not currently red, but it's a weakened contract.
  • The PR description frames this as reflecting "working-directory inheritance behavior," but realpath() resolves symlinks, not inheritance — the stated rationale doesn't match what the code change does.

Scope concern: this change has nothing to do with the agent-profile fix. Mixing an unrelated assertion rewrite into a targeted regression fix makes the PR harder to revert cleanly if something downstream breaks.

Suggested action (pick one):

  1. Preferred — revert this hunk; the agent-profile fix stands on its own.
  2. If there's a real reason to drop realpath() (e.g. symlink-resolution caused a real incident), change production instead and document it in a separate PR.
  3. If keeping the change, update the commit body to explain why the assertion was weakened so future readers understand.

2 — Dead except FileNotFoundErrorPriority: Low

After the new outer guard, the inner handler is unreachable:

try:
    profile = load_agent_profile(agent_profile)   # ← now handled by outer guard
except FileNotFoundError:
    profile = None

...

if allowed_tools is None and profile is not None:
    try:
        from cli_agent_orchestrator.utils.tool_mapping import resolve_allowed_tools

        mcp_server_names = list(profile.mcpServers.keys()) if profile.mcpServers else None
        allowed_tools = resolve_allowed_tools(
            profile.allowedTools, profile.role, mcp_server_names
        )
    except FileNotFoundError:   # ← dead: resolve_allowed_tools is pure list/dict manipulation
        pass

Confirmed by reading src/cli_agent_orchestrator/utils/tool_mapping.py:75-115resolve_allowed_tools() is pure list/dict manipulation sourced from ROLE_TOOL_DEFAULTS, no file I/O, cannot raise FileNotFoundError.

Suggested action: remove the inner try/except, de-indent the resolve_allowed_tools call. Cosmetic only — fine as a follow-up if preferred.

…O store

load_agent_profile() raises FileNotFoundError for agents whose profiles
only exist as .json files (e.g. ~/.kiro/agents/my-agent.json). The call
in terminal_service.create_terminal() was unguarded, causing terminal
creation to fail with:

    Failed to create terminal: Agent profile not found: my-agent

This was introduced in awslabs#145 when profile loading was hoisted to a top-level
call outside the allowed_tools block, but the FileNotFoundError guard
was not moved with it.

Wrap load_agent_profile() in try/except FileNotFoundError and gate
allowed_tools resolution on profile is not None. For kiro_cli, the
profile is resolved natively by kiro-cli itself — CAO not finding it in
its own store is expected and non-fatal.

This matches the documented behavior in docs/kiro-cli.md:
  If the agent is not found, CAO gracefully falls back — kiro-cli resolves
  .json profiles natively
@anilkmr-a2z anilkmr-a2z force-pushed the fix/agent-profile-not-found branch from 71f308a to 9c95b1e Compare April 18, 2026 03:02
@haofeif haofeif added the bug Something isn't working label Apr 18, 2026
@anilkmr-a2z

Copy link
Copy Markdown
Contributor Author

@anilkmr-a2z thanks for the great work. just some minor comments:

1 — Unrelated test_launch.py assertion change — Priority: Medium

# before
assert params["working_directory"] == os.path.realpath(os.getcwd())
# after
assert params["working_directory"] == os.getcwd()

Why this is worth flagging:

* Production at `src/cli_agent_orchestrator/cli/commands/launch.py:53` still calls `os.path.realpath(os.getcwd())` — unchanged by this PR.

* The new assertion no longer verifies the `realpath()` behavior. On platforms where CWD is a symlink (e.g. macOS `/tmp → /private/tmp`), the test will assert the _unresolved_ path while production sends the _resolved_ path — the opposite of what we want.

* On typical dev/CI paths (`/Users/...`, `/home/...`, `/workspace/...`) there are no symlinks, so both old and new assertions pass — which is probably why this slipped past local validation. It's not _currently_ red, but it's a weakened contract.

* The PR description frames this as reflecting "working-directory inheritance behavior," but `realpath()` resolves symlinks, not inheritance — the stated rationale doesn't match what the code change does.

Scope concern: this change has nothing to do with the agent-profile fix. Mixing an unrelated assertion rewrite into a targeted regression fix makes the PR harder to revert cleanly if something downstream breaks.

Suggested action (pick one):

1. **Preferred** — revert this hunk; the agent-profile fix stands on its own.

2. If there's a real reason to drop `realpath()` (e.g. symlink-resolution caused a real incident), change production instead and document it in a separate PR.

3. If keeping the change, update the commit body to explain _why_ the assertion was weakened so future readers understand.

2 — Dead except FileNotFoundErrorPriority: Low

After the new outer guard, the inner handler is unreachable:

try:
    profile = load_agent_profile(agent_profile)   # ← now handled by outer guard
except FileNotFoundError:
    profile = None

...

if allowed_tools is None and profile is not None:
    try:
        from cli_agent_orchestrator.utils.tool_mapping import resolve_allowed_tools

        mcp_server_names = list(profile.mcpServers.keys()) if profile.mcpServers else None
        allowed_tools = resolve_allowed_tools(
            profile.allowedTools, profile.role, mcp_server_names
        )
    except FileNotFoundError:   # ← dead: resolve_allowed_tools is pure list/dict manipulation
        pass

Confirmed by reading src/cli_agent_orchestrator/utils/tool_mapping.py:75-115resolve_allowed_tools() is pure list/dict manipulation sourced from ROLE_TOOL_DEFAULTS, no file I/O, cannot raise FileNotFoundError.

Suggested action: remove the inner try/except, de-indent the resolve_allowed_tools call. Cosmetic only — fine as a follow-up if preferred.

Good catch. Fixed these.

@haofeif haofeif 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 @anilkmr-a2z looks great to me

@haofeif haofeif merged commit 23075f3 into awslabs:main Apr 18, 2026
8 checks passed
erikmackinnon pushed a commit to erikmackinnon/cli-agent-orchestrator that referenced this pull request Apr 18, 2026
…O store (awslabs#186)

load_agent_profile() raises FileNotFoundError for agents whose profiles
only exist as .json files (e.g. ~/.kiro/agents/my-agent.json). The call
in terminal_service.create_terminal() was unguarded, causing terminal
creation to fail with:

    Failed to create terminal: Agent profile not found: my-agent

This was introduced in awslabs#145 when profile loading was hoisted to a top-level
call outside the allowed_tools block, but the FileNotFoundError guard
was not moved with it.

Wrap load_agent_profile() in try/except FileNotFoundError and gate
allowed_tools resolution on profile is not None. For kiro_cli, the
profile is resolved natively by kiro-cli itself — CAO not finding it in
its own store is expected and non-fatal.

This matches the documented behavior in docs/kiro-cli.md:
  If the agent is not found, CAO gracefully falls back — kiro-cli resolves
  .json profiles natively

Co-authored-by: haofeif <56006724+haofeif@users.noreply.github.com>
(cherry picked from commit 23075f3)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants