fix(cli): honour absolute paths in adk run - #651
Conversation
|
The red #652 pins those three actions and its The test matrix on this PR is passing on all three OSes. |
AmaadMartin
left a comment
There was a problem hiding this comment.
The fix is correct. path.resolve keeps an absolute path on POSIX and on Windows, and the new tests build their absolute path from path.sep, so run-tests (windows-latest) is a real guard here and it passes. Two nits below, both optional; neither blocks. The one red check, zizmor-output, reports unpinned actions in .github/workflows/validation.yaml, a file this PR does not touch; it is red on #649 and #650 too, and #652 fixes it.
| * `<cwd>/tmp/x.json`. Every path here comes from the command line, so an | ||
| * absolute one has to be honoured as given. | ||
| */ | ||
| function resolveFromCwd(p: string): string { |
There was a problem hiding this comment.
Nit, optional. The repo already has this helper: getAbsolutePath at dev/src/cli/cli.ts:53.
return path.isAbsolute(p) ? p : path.join(process.cwd(), p);It wraps four path arguments (cli.ts:237, 283, 442, 493), but not run. Two more sites keep the raw form: cli_create.ts:186 and :203. That gives three shapes for one operation. Please share one helper under one name.
Keep the fix inside runAgent. getAbsolutePath at cli.ts:375 breaks cli_test.ts:233 and :256, and it misses --replay.
There was a problem hiding this comment.
Done, and thanks for naming the exact sites.
getAbsolutePath now lives in dev/src/utils/file_utils.ts and is the only spelling of this operation left in the CLI:
cli.tsno longer defines its own copy; it imports the shared one, so its four call sites are unchanged in behaviour.cli_run.tsuses it for the agent path,--replay, and the save destination.cli_create.ts:186and:203no longer buildpath.join(process.cwd(), ...)by hand, and the module-leveldirnameis gone.
The fix stays inside runAgent as you asked, so cli_test.ts still sees the raw agent.ts argument and needed no changes.
One deliberate exception: the two remaining process.cwd() uses in cli.ts are commander option defaults for --agents_dir/--tests_dir. Those are already absolute and never user-supplied strings, so wrapping them would be noise.
| sessionId: session.id, | ||
| }); | ||
| await saveToFile(path.join(dirname, sessionPath), sessionToStore); | ||
| await saveToFile(resolveFromCwd(sessionPath), sessionToStore); |
There was a problem hiding this comment.
Nit, optional, and pre-existing. The save destination starts from the agent file path at line 406:
const sessionPath = path.join(
options.agentPath,
`${sessionId}.session.json`,
);For adk run agent.ts --save_session that is <cwd>/agent.ts/<id>.session.json. saveToFile runs no mkdir, and agent.ts is a file, so the write fails with ENOTDIR. join is the right call here; the base is wrong. Use path.dirname(options.agentPath). cli_run_test.ts:328 asserts only stringContaining('my-session.session.json'), so it stays green either way.
There was a problem hiding this comment.
Good catch, fixed. The base is now path.dirname(options.agentPath), so adk run agent.ts --save_session writes <cwd>/<id>.session.json next to the agent instead of attempting <cwd>/agent.ts/<id>.session.json and failing with ENOTDIR.
You were right that the existing assertion could not tell the difference. cli_run_test.ts now pins the whole resolved path rather than stringContaining('my-session.session.json'), so a regression to the old base fails the test:
expect(saveToFile).toHaveBeenCalledWith(
path.join(process.cwd(), 'agents', 'my-session.session.json'),
expect.anything(),
);Taking it in this PR rather than leaving it: it is the same path-resolution bug the PR is about, and the diff already touches that line.
|
Correction to my review body: I wrote that #652 fixes the red #648 landed the three SHA pins in My approval stands. The check stays unrelated to your diff. |
675df89 to
8dfca56
Compare
`path.join(process.cwd(), p)` strips the leading separator from an absolute path, so `adk run /abs/agent.ts` looked for `<cwd>/abs/agent.ts` and failed with a confusing "does not exists" that quotes a path the user never typed. The same applied to `--replay`. Resolve with `path.resolve` instead, which returns an absolute path unchanged and still resolves a relative one against the working directory. The existing `getAbsolutePath` from cli.ts moves to file_utils, so `run` shares one helper with `web`, `api_server` and `deploy` rather than open-coding a third shape of the same operation. `--save_session` was broken outright, for a neighbouring reason: the destination was joined onto the agent *file* path, giving `<cwd>/agent.ts/<id>.session.json`, and since saveToFile does no mkdir every save failed with ENOTDIR. Base it on the agent file's directory so the session lands beside the agent. `--resume` was already correct: it hands its path straight to loadFileData. Found while bug-bashing the graph-workflow docs samples.
8dfca56 to
854eef1
Compare
|
Rebased onto latest main (8611219). Thanks for the review — both nits taken, and the second one was a real bug. Shared helper —
Not just the wrong location — the feature could never have worked, since the base was always a file. Fixed with Note the Dev suite: 265 tests, one pre-existing |
The last two raw `path.join(process.cwd(), ...)` sites in the CLI, so one operation is spelled one way across cli, cli_run and cli_create.
* fix(cli): honour absolute paths in adk run `path.join(process.cwd(), p)` strips the leading separator from an absolute path, so `adk run /abs/agent.ts` looked for `<cwd>/abs/agent.ts` and failed with a confusing "does not exists" that quotes a path the user never typed. The same applied to `--replay`. Resolve with `path.resolve` instead, which returns an absolute path unchanged and still resolves a relative one against the working directory. The existing `getAbsolutePath` from cli.ts moves to file_utils, so `run` shares one helper with `web`, `api_server` and `deploy` rather than open-coding a third shape of the same operation. `--save_session` was broken outright, for a neighbouring reason: the destination was joined onto the agent *file* path, giving `<cwd>/agent.ts/<id>.session.json`, and since saveToFile does no mkdir every save failed with ENOTDIR. Base it on the agent file's directory so the session lands beside the agent. `--resume` was already correct: it hands its path straight to loadFileData. Found while bug-bashing the graph-workflow docs samples. * fix(cli): route agent-dir creation through the shared path helper The last two raw `path.join(process.cwd(), ...)` sites in the CLI, so one operation is spelled one way across cli, cli_run and cli_create.
* fix(cli): honour absolute paths in adk run `path.join(process.cwd(), p)` strips the leading separator from an absolute path, so `adk run /abs/agent.ts` looked for `<cwd>/abs/agent.ts` and failed with a confusing "does not exists" that quotes a path the user never typed. The same applied to `--replay`. Resolve with `path.resolve` instead, which returns an absolute path unchanged and still resolves a relative one against the working directory. The existing `getAbsolutePath` from cli.ts moves to file_utils, so `run` shares one helper with `web`, `api_server` and `deploy` rather than open-coding a third shape of the same operation. `--save_session` was broken outright, for a neighbouring reason: the destination was joined onto the agent *file* path, giving `<cwd>/agent.ts/<id>.session.json`, and since saveToFile does no mkdir every save failed with ENOTDIR. Base it on the agent file's directory so the session lands beside the agent. `--resume` was already correct: it hands its path straight to loadFileData. Found while bug-bashing the graph-workflow docs samples. * fix(cli): route agent-dir creation through the shared path helper The last two raw `path.join(process.cwd(), ...)` sites in the CLI, so one operation is spelled one way across cli, cli_run and cli_create.
Link to Issue or Description of Change
2. Or, if no issue exists, describe the change:
Problem:
adk runrebases absolute paths onto the working directory, becausepath.joinstrips the leading separator:So an absolute agent path fails with an error quoting a path the user never
typed:
and an absolute
--replaypath fails the same way:Both messages point at a path that is neither what was passed nor anywhere the
user can act on, which makes this disproportionately confusing to debug. It
also affects the
--save_sessiondestination.Solution:
Resolve command-line paths with
path.resolveinstead ofpath.join, via asmall named helper in
cli_run.tsso the reason is documented in one place.path.resolvereturns an absolute path unchanged and still resolves a relativeone against the working directory, so relative paths behave exactly as before.
--resumewas already correct and is untouched: it hands its path straight toloadFileData.Testing Plan
Unit Tests:
Three tests in
dev/test/cli/cli_run_test.ts: an absolute--replaypath, anabsolute agent path, and a relative path that must keep resolving against cwd.
Confirmed the two absolute-path tests fail without the source change:
Full dev project:
The single failure is
cli_create_test.ts > should handle Vertex AI selection with gcloud defaults, which reads local gcloud config and fails identically onclean
mainat5742875. Unrelated to this change.Manual End-to-End (E2E) Tests:
Relative paths continue to work unchanged.
Checklist
Additional context
Found while bug-bashing the graph-workflow docs samples: the human-in-the-loop
samples need
--replayto script their two turns, and an absolute path to thereplay file silently failed.
A companion PR fixes two graph-workflow diagnostics found in the same session.
Generated with CloudCode, session
ses_00c664b88ffeuSsmLI4zfs0a3q.