Skip to content

fix(apodex): preflight search credentials from the profile's tools - #35

Open
Samurai007AK wants to merge 3 commits into
ApodexAI:mainfrom
Samurai007AK:fix/34-web-tool-preflight
Open

fix(apodex): preflight search credentials from the profile's tools#35
Samurai007AK wants to merge 3 commits into
ApodexAI:mainfrom
Samurai007AK:fix/34-web-tool-preflight

Conversation

@Samurai007AK

Copy link
Copy Markdown
Contributor

inspect_runtime_config() only checked SERPER_API_KEY and JINA_API_KEY when the
active mode was research, and the terminal cannot select that mode:
_TERMINAL_WORKFLOW_MODES caps the list at react and agent_team, and cli.py
rejects anything else before the preflight runs. Both selectable profiles bind
web_search and web_fetch, so the check never fired for the profiles that need
it. A blank key first surfaced as [ERROR]: SERPER_API_KEY environment variable not set. handed to the model as a tool result, which reads as a failed call and
gets improvised around rather than reported.

Gate the credentials on the tools the profile declares instead of the mode name,
and split them so each key is checked against the tool that needs it. Whether
web_search is bound is the actual dependency; the mode name was only ever a
proxy for it, and a wrong one.

The names come from a new AgentProfile.tool_names rather than from
profile.tools(). That field is a factory which imports apodex.agent_tools,
builds the whole registry, and raises KeyError on an unrecognised name — more
machinery and more failure modes than a local, secret-free preflight should
carry. tool_names is populated from the same YAML list the factory closes over.

missing_serper_api_key drops to a warning. It was blocking, but it never ran, so
nothing depended on that: making it fire as a blocker would newly refuse startup
(cli.py turns a blocking issue into exit 2) and break switch_session for anyone
running these profiles as a coding agent without a search key. web_search is one
of the seven tools these profiles bind, and the README describes the key as
optional — which stays true this way. missing_jina_api_key already warned.

One limitation worth flagging: cli.py prints warnings to stderr just before the
TUI takes the alternate screen buffer, so under the full TUI they may not remain
visible. Line mode (--no-tui) shows them normally. Surfacing them inside the TUI
means touching the renderer and seemed like your call rather than mine.

Closes #34

The SERPER_API_KEY / JINA_API_KEY check was keyed on the research mode, which the terminal cannot select, so it never fired for react or agent_team, both of which bind web_search and web_fetch. A blank key first surfaced as an error string inside a tool result.

Gate on the tools the profile declares, and drop the Serper issue to a warning so a coding session with no search key still starts.

Closes ApodexAI#34
@zhanghanduo

Copy link
Copy Markdown
Collaborator

Thanks for the fix — the tool-based direction makes sense, but I see two remaining issues:

  1. Missing-key findings are now warnings printed to stderr immediately before Textual enters its alternate screen. In the default TUI flow they do not remain visible during the session, so web_search preflight is keyed to a mode the CLI cannot select, so a missing SERPER_API_KEY never surfaces #34 is still effectively unsurfaced for most users. Could we pass these warnings into the TUI and render them after mount?

  2. AgentProfile.tool_names comes from the top-level profile YAML, but react and agent_team run native workflows whose effective tools come from their workflow profiles (agent_tools / main_agent_tools / sub_agent_tools). These duplicated lists can drift or differ in user overrides, causing false positives or false negatives. The preflight should inspect the effective workflow tool configuration, or use a single source of truth.

… in the TUI

Two review findings on the tool-based preflight.

Warnings were printed to stderr moments before Textual takes the alternate
screen, so under the default TUI they were gone before the session started.
cli.py now prints them only in line mode and hands them to FrontierAgentApp,
which renders them in the transcript after mount.

AgentProfile.tool_names read the top-level `tools:` of the apodex YAML, but
react and agent_team dispatch to a native workflow and never bind that list.
It is now a property resolving agent_tools / main_agent_tools /
sub_agent_tools from the workflow profile, through that workflow's own loader
so aliases and ${VAR} resolve as they do at dispatch. The duplicated `tools:`
lists are deleted rather than worked around: nothing read them, and a dead
copy is what drifts. agent_team's coordinator binds no web_search while its
sub-agents do, which the old list could not express either way.

The loaders log their own config diagnostics, and dispatch loads the same
profile again and logs them where the renderer routes them, so the preflight
read is muted to avoid printing each one twice.
@Samurai007AK

Copy link
Copy Markdown
Contributor Author

@zhanghanduo Thanks for the follow-up. I addressed both points in the latest commit.

  1. The preflight warnings are now passed into the TUI and rendered in the transcript after mount, so they remain visible in the default Textual flow. Line mode still prints them normally.

  2. AgentProfile.tool_names no longer treats the top-level profile tools: list as the source of truth for native workflows. For react and agent_team, it resolves the effective tools from the workflow profile (agent_tools / main_agent_tools / sub_agent_tools) using the workflow's own loader, so aliases and ${VAR} resolution match dispatch behavior.

I also removed the duplicated tools: lists from react.yaml and agent_team.yaml. This is intentionally behavior-visible rather than just a refactor: anyone reading those profiles now has to follow the workflow reference/comment to see the tools actually bound by the mode. That avoids maintaining a second list that can silently drift from the workflow configuration. In particular, agent_team has a coordinator/sub-agent tool distinction that the old top-level list could not represent correctly.

The relevant tests were updated to cover the tool-based preflight and TUI warning visibility.

@dq-ai-dev

dq-ai-dev commented Sep 8, 2026

Copy link
Copy Markdown
Collaborator

One minor remaining issue: the new preflight tool resolution does not account for closed-book filtering. With REACT_NO_WEB=1 or SWARM_NO_WEB=1, runtime removes web_search and web_fetch, but _workflow_tool_names() still includes them, so preflight reports missing Serper/Jina credentials for tools that will not run.

Could you apply the same closed-book filtering before checking credentials and add coverage for both modes?

@Samurai007AK

Copy link
Copy Markdown
Contributor Author

@dq-ai-dev Addressed - thanks for catching it .

Applied the same closed-book filtering before checking credentials:

  • REACT_NO_WEB=1 drops web_search/web_fetch/download_file for react (stateful-react-agent), SWARM_NO_WEB=1 does the same for agent_team, matching workflows/*/nodes/main_agent.py.
  • Filtering is applied in both inspect_runtime_config() (via its environ mapping) and AgentProfile.tool_names (via live os.environ), so no more missing Serper/Jina warnings for tools that won't run.
  • Flags are workflow-specific; unknown modes like coding still warn.

Added coverage for both modes: unit cases for each flag + wrong-flag isolation, and end-to-end over the real react/agent_team profiles.

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.

web_search preflight is keyed to a mode the CLI cannot select, so a missing SERPER_API_KEY never surfaces

3 participants