feat: add session-name input for message reuse#3
Conversation
Change the `timeout` input from a hard session timeout (minutes) to an inactivity timeout (seconds). The session now runs as long as needed and auto-stops after the specified duration of inactivity. - `timeout` now maps to `inactivityTimeout` in the API body (was `timeout`) - Value is passed in seconds with no conversion (was minutes * 60) - Default is `0` (no auto-stop) for backward compatibility - Recommended value for orchestrator sessions: `60` (1 min idle → stop) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When session-name is provided, the action sends the prompt as a message to that existing session via the AG-UI /agui/run endpoint instead of creating a new session. - New input: session-name (optional) - New function: send_message() posts to /agui/run - Supports --wait to poll after sending - Falls back to create mode when session-name is empty Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (1)
WalkthroughAdds optional Changes
Sequence DiagramsequenceDiagram
participant Action as GitHub Action
participant Script as create_session.py
participant AGUI as AG-UI API
Action->>Script: Run with prompt (+ optional --session-name, --wait, --poll-timeout)
alt --session-name provided
Script->>AGUI: GET /sessions/{name} (read phase)
AGUI-->>Script: phase or 404
alt phase != "Running"
Script->>AGUI: POST /sessions/{name}/start
AGUI-->>Script: start response
Script->>AGUI: poll GET /sessions/{name} (up to --poll-timeout)
AGUI-->>Script: phase updates
end
Script->>AGUI: POST /agui/run (send user message with runId + message id)
AGUI-->>Script: send response (success/failure)
alt --wait set
Script->>AGUI: poll GET /sessions/{name} until final or timeout (--poll-timeout)
AGUI-->>Script: final status
end
else no --session-name
Script->>AGUI: POST /sessions (create with inactivityTimeout from --timeout)
AGUI-->>Script: create response (session name)
Script->>AGUI: poll GET /sessions/{new} (up to --poll-timeout)
AGUI-->>Script: phase updates
end
Script->>Action: emit outputs (`session_phase`, `session_name`, exit code)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes 🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@action.yml`:
- Line 105: The composite action currently hard-codes the create_session.py
polling timeout because action.yml only forwards session-name
(INPUT_SESSION_NAME); add a new input named poll-timeout in action.yml and
expose it (e.g., INPUT_POLL_TIMEOUT) and then forward that value into the step
that invokes create_session.py (either as an environment variable or by
appending --poll-timeout ${{ inputs.poll-timeout }} to the command that runs
create_session.py in the composite action), and update the other input
mappings/steps referenced near the same block (the places around
INPUT_SESSION_NAME and the later occurrences) so the poll-timeout is passed
consistently into the wait flow.
In `@create_session.py`:
- Around line 38-42: The URL is built with raw project and session_name which
can contain reserved characters; update the code that constructs the url
variable to percent-encode path segments (project and session_name) before
interpolation (e.g., use urllib.parse.quote on project and session_name) so
reserved characters like '/', '?', '#', and spaces are encoded; ensure you
encode only the path segments (not the whole URL or query string) and then use
the encoded values when assigning url =
f"{api_url.rstrip('/')}/projects/{encoded_project}/agentic-sessions/{encoded_session_name}/agui/run".
- Around line 253-265: The --wait path currently calls poll_session() which only
checks overall session phase and can return a stale terminal state; modify the
flow around send_message and poll_session so that the newly-created run is
tracked and waited-for specifically: capture the session phase immediately
before calling send_message (use the same variable sent by send_message that
contains runId), extract the generated runId returned by send_message, and then
when args.wait is set either (a) subscribe to SSE RUN_FINISHED events and wait
for an event whose runId matches the returned runId, or (b) poll the specific
run status (not poll_session()) until that runId reports terminal state; update
the code paths referencing send_message, runId, and poll_session to perform
run-level waiting rather than relying solely on session-level phase.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: d999e8c8-2956-472a-8476-88518bfa77fb
📒 Files selected for processing (2)
action.ymlcreate_session.py
| url = f"{api_url.rstrip('/')}/projects/{project}/agentic-sessions/{session_name}/agui/run" | ||
|
|
||
| body = { | ||
| "threadId": session_name, | ||
| "runId": str(uuid.uuid4()), |
There was a problem hiding this comment.
URL path parameters must be percent-encoded before request construction.
Line 38 builds the endpoint using raw project and session_name. If either contains reserved characters (/, ?, #, spaces), requests can target the wrong route or fail unpredictably.
🔧 Proposed fix
+from urllib.parse import quote
...
- url = f"{api_url.rstrip('/')}/projects/{project}/agentic-sessions/{session_name}/agui/run"
+ encoded_project = quote(project, safe="")
+ encoded_session_name = quote(session_name, safe="")
+ url = (
+ f"{api_url.rstrip('/')}/projects/{encoded_project}"
+ f"/agentic-sessions/{encoded_session_name}/agui/run"
+ )🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@create_session.py` around lines 38 - 42, The URL is built with raw project
and session_name which can contain reserved characters; update the code that
constructs the url variable to percent-encode path segments (project and
session_name) before interpolation (e.g., use urllib.parse.quote on project and
session_name) so reserved characters like '/', '?', '#', and spaces are encoded;
ensure you encode only the path segments (not the whole URL or query string) and
then use the encoded values when assigning url =
f"{api_url.rstrip('/')}/projects/{encoded_project}/agentic-sessions/{encoded_session_name}/agui/run".
| if args.wait: | ||
| poll_result = poll_session( | ||
| api_url=args.api_url, | ||
| api_token=args.api_token, | ||
| project=args.project, | ||
| session_name=args.session_name, | ||
| poll_interval=args.poll_interval, | ||
| timeout_minutes=args.poll_timeout, | ||
| verify_ssl=verify_ssl, | ||
| ) | ||
| output["session_phase"] = poll_result.get("phase", "") | ||
| output["session_result"] = poll_result.get("result", "") | ||
|
|
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
Ambient Code AG-UI API: after POST /agui/run with runId, what endpoint and field should be polled to determine completion of that specific runId (not just session phase)?
💡 Result:
No specific endpoint found for polling individual runId completion in Ambient Code AG-UI API. Standard AG-UI protocol uses streaming SSE from POST /agui (or /agui/run) where completion is indicated by RUN_FINISHED or run_finished event containing the runId. For polling a specific runId (not session), no dedicated endpoint identified in available sources. Ambient Code Platform uses Kubernetes CRDs for agentic sessions with public API via public-api gateway for status/metrics, but no explicit /agui/run poll endpoint documented. Likely poll GET /sessions/{runId} or similar via their public API, but unconfirmed. Use SSE streaming for real-time completion detection matching runId in events.
Citations:
- 1: https://docs.praison.ai/docs/deploy/api/agui-api
- 2: https://docs.agno.com/applications/ag-ui/introduction
- 3: https://github.com/ambient-code/platform
- 4: https://github.com/ambient-code/mcp
- 5: https://github.com/ambient-code/platform/blob/main/CLAUDE.md
🏁 Script executed:
# First, find the create_session.py file
fd "create_session.py" -type fRepository: ambient-code/ambient-action
Length of output: 241
🏁 Script executed:
fd "create_session.py"Repository: ambient-code/ambient-action
Length of output: 88
🏁 Script executed:
wc -l create_session.pyRepository: ambient-code/ambient-action
Length of output: 92
🏁 Script executed:
cat -n create_session.pyRepository: ambient-code/ambient-action
Length of output: 12821
--wait after send_message cannot confirm the submitted runId completed; it returns stale session phase.
The generated runId (line 42) is never tracked or correlated with polling. When --wait is set (line 253), poll_session() checks only the session's overall phase; if the session was already terminal before the message was sent, polling immediately returns that old completion state, not the result of the just-submitted run.
The web search indicates AG-UI uses SSE streaming with RUN_FINISHED events for reliable run completion detection (matching the runId in events). If polling is preferred, either switch to SSE streaming or add pre-send phase capture and post-send phase-transition confirmation before accepting terminal completion.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@create_session.py` around lines 253 - 265, The --wait path currently calls
poll_session() which only checks overall session phase and can return a stale
terminal state; modify the flow around send_message and poll_session so that the
newly-created run is tracked and waited-for specifically: capture the session
phase immediately before calling send_message (use the same variable sent by
send_message that contains runId), extract the generated runId returned by
send_message, and then when args.wait is set either (a) subscribe to SSE
RUN_FINISHED events and wait for an event whose runId matches the returned
runId, or (b) poll the specific run status (not poll_session()) until that runId
reports terminal state; update the code paths referencing send_message, runId,
and poll_session to perform run-level waiting rather than relying solely on
session-level phase.
When session-name targets a stopped session, the action now:
1. Checks session phase via GET /agentic-sessions/{name}
2. If stopped, calls POST /agentic-sessions/{name}/start
3. Waits up to 60s for Running phase
4. Then sends the message
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (2)
create_session.py (2)
37-44:⚠️ Potential issue | 🟠 MajorPercent-encode
projectandsession_namebefore building request URLs.These values are still interpolated raw here. If either contains
/,?,#, or spaces, the request can hit the wrong route or fail outright. The same bug is repeated in the new/startand/agui/runhelpers, so please encode the path segments once and reuse them everywhere.🔧 Proposed fix
+from urllib.parse import quote ... - url = f"{api_url.rstrip('/')}/projects/{project}/agentic-sessions/{session_name}" + encoded_project = quote(project, safe="") + encoded_session_name = quote(session_name, safe="") + url = ( + f"{api_url.rstrip('/')}/projects/{encoded_project}" + f"/agentic-sessions/{encoded_session_name}" + )🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@create_session.py` around lines 37 - 44, The code builds request URLs by interpolating raw path segments (project, session_name) into url (in create_session.py where url = f"{api_url.rstrip('/')}/projects/{project}/agentic-sessions/{session_name}" and in the /start and /agui/run helpers), which breaks when segments contain '/', '?', '#', or spaces; fix by percent-encoding those path segments once (e.g., using urllib.parse.quote) before composing URLs, centralize this encoding into a helper (e.g., encode_path_segment or similar) and use that helper everywhere the project or session_name is inserted into path strings so all requests use encoded path segments consistently.
121-160:⚠️ Potential issue | 🟠 Major
--waitis still waiting on session state, not on the message run you just submitted.
send_message()creates a freshrunIdbut returns onlyTrue/False, and the wait path then polls onlysession.status.phase. If the session was alreadyCompletedfrom an earlier run,--waitcan return that stale terminal state immediately even though the new message run has not finished. Return the submittedrunIdfromsend_message()and wait on run-specific completion instead of session-level phase.Ambient Code official AG-UI documentation: after POST /projects/{project}/agentic-sessions/{session}/agui/run with a runId, what documented mechanism or endpoint should a client use to detect completion of that specific runId?Also applies to: 348-359
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@create_session.py`:
- Line 303: The new parser.add_argument("--poll-timeout", ...) is never reached
from the composite action because action.yml still exposes/forwards only the old
timeout/poll-interval inputs, so args.poll_timeout always falls back to the 60
default; fix either by updating action.yml to add a poll-timeout input and
forward it into the script (match the naming used by parser.add_argument) or
make create_session.py backward-compatible by changing the wait branches to use
args.poll_timeout if set else fall back to args.timeout (check args.poll_timeout
presence before using it), ensuring variables args.poll_timeout and args.timeout
are referenced where polling timeout is read so existing users still get the
intended behavior.
- Around line 96-118: The current logic returns True for any non-terminal phase,
allowing callers to proceed before the session is Running; change the tail of
the function (the branch that currently does logger.info(f"Session
{session_name} is in phase {phase}, waiting...") followed by return True) to
poll with the same deadline logic used after start_session: repeatedly call
get_session_phase(api_url, api_token, project, session_name, verify_ssl)
(sleeping ~3s between tries) until phase == "Running" (then return True), or
phase becomes None or the timeout expires (log an error and return False); reuse
the existing max_wait/deadline pattern and keep the logging messages consistent
with the start branch and functions start_session and get_session_phase.
---
Duplicate comments:
In `@create_session.py`:
- Around line 37-44: The code builds request URLs by interpolating raw path
segments (project, session_name) into url (in create_session.py where url =
f"{api_url.rstrip('/')}/projects/{project}/agentic-sessions/{session_name}" and
in the /start and /agui/run helpers), which breaks when segments contain '/',
'?', '#', or spaces; fix by percent-encoding those path segments once (e.g.,
using urllib.parse.quote) before composing URLs, centralize this encoding into a
helper (e.g., encode_path_segment or similar) and use that helper everywhere the
project or session_name is inserted into path strings so all requests use
encoded path segments consistently.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 9588844a-5bd4-459c-a012-f3c7e01fa3d5
📒 Files selected for processing (1)
create_session.py
- Expose poll-timeout input in action.yml and wire through to script - Fix ensure_session_running to always poll until Running phase, not fall through for Pending/Starting phases Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (2)
create_session.py (2)
29-37:⚠️ Potential issue | 🟠 MajorPercent-encode these path segments before building the request URL.
Line 37 and the similar URL builders on Lines 62, 130, and 230 still interpolate raw
project/session_name. Names containing/, space,?, or#can hit the wrong route or 404, which makes the new reuse flow fail for valid identifiers. Encode each path segment once before interpolation and reuse the encoded values in all four helpers.🔧 Proposed fix
+from urllib.parse import quote ... - url = f"{api_url.rstrip('/')}/projects/{project}/agentic-sessions/{session_name}" + encoded_project = quote(project, safe="") + encoded_session_name = quote(session_name, safe="") + url = ( + f"{api_url.rstrip('/')}/projects/{encoded_project}" + f"/agentic-sessions/{encoded_session_name}" + )Also applies to: 54-63, 130-130, 220-230
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@create_session.py` around lines 29 - 37, Percent-encode the path segments before building the request URL so project and session_name don’t break routes; in get_session_phase (and the other helpers that build URLs around the same inputs at the other occurrences) call a single percent-encoding step for project and session_name (reuse the encoded values) and interpolate those encoded variables into url = f"{api_url.rstrip('/')}/projects/{encoded_project}/agentic-sessions/{encoded_session_name}" instead of inserting raw project/session_name; ensure you use a standard percent-encoding routine that encodes reserved characters (e.g., via urllib.parse.quote) and apply the same change to the other functions that construct URLs with project/session_name.
118-157:⚠️ Potential issue | 🟠 Major
--waitcannot tell whether the message submitted here is the one that finished.Line 134 creates a unique
runId, butsend_message()returns onlyTrue/False. The later wait path can therefore poll only session-level state, which is ambiguous once multiple messages can target the same session. Return therunIdhere and wait on that specific run instead of whole-session phase.🔧 Minimal root-cause change
def send_message( @@ -) -> bool: +) -> str | None: @@ - body = { + run_id = str(uuid.uuid4()) + body = { "threadId": session_name, - "runId": str(uuid.uuid4()), + "runId": run_id, @@ - return True + return run_id @@ - return False + return None🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@create_session.py` around lines 118 - 157, send_message currently generates a unique runId but only returns True/False, making later --wait polling ambiguous; change send_message(api_url, api_token, project, session_name, message, verify_ssl=True) to return the generated runId (string) on success and None/False on failure so callers can poll that specific run; specifically, extract runId into a variable (e.g., run_id = str(uuid.uuid4())), use run_id in the body["runId"], and replace the boolean return with return run_id after a successful resp.raise_for_status(); ensure callers that used the boolean now expect and handle a run id (or None) to wait on the precise run.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@create_session.py`:
- Around line 323-332: The send_message() call in the reused-session path
ignores the caller's startup wait budget (it inherits
ensure_session_running(..., max_wait=60)), so add a startup timeout parameter
and thread the caller's poll timeout through it: update send_message(...) to
accept startup_timeout (or a dedicated startup_timeout flag), pass that value
from main() (e.g., startup_timeout=args.poll_timeout or a new CLI arg), and
ensure send_message uses startup_timeout when calling
ensure_session_running(..., max_wait=startup_timeout); update any other callers
of send_message accordingly.
---
Duplicate comments:
In `@create_session.py`:
- Around line 29-37: Percent-encode the path segments before building the
request URL so project and session_name don’t break routes; in get_session_phase
(and the other helpers that build URLs around the same inputs at the other
occurrences) call a single percent-encoding step for project and session_name
(reuse the encoded values) and interpolate those encoded variables into url =
f"{api_url.rstrip('/')}/projects/{encoded_project}/agentic-sessions/{encoded_session_name}"
instead of inserting raw project/session_name; ensure you use a standard
percent-encoding routine that encodes reserved characters (e.g., via
urllib.parse.quote) and apply the same change to the other functions that
construct URLs with project/session_name.
- Around line 118-157: send_message currently generates a unique runId but only
returns True/False, making later --wait polling ambiguous; change
send_message(api_url, api_token, project, session_name, message,
verify_ssl=True) to return the generated runId (string) on success and
None/False on failure so callers can poll that specific run; specifically,
extract runId into a variable (e.g., run_id = str(uuid.uuid4())), use run_id in
the body["runId"], and replace the boolean return with return run_id after a
successful resp.raise_for_status(); ensure callers that used the boolean now
expect and handle a run id (or None) to wait on the precise run.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 806ffb2e-cf97-4f3f-a598-e03403d3f2fa
📒 Files selected for processing (2)
action.ymlcreate_session.py
send_message now accepts startup_timeout parameter instead of hardcoding 60s. main() passes poll_timeout (converted to seconds) so callers can control how long to wait for a stopped session to restart. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Summary
session-nameinput — when provided, sends the prompt as a message to an existing session instead of creating a new one/agui/runendpoint to deliver messages--waitto poll after sendingTest plan
session-name— works as beforesession-name— verify message delivered to existing sessionsession-namewithwait: true— verify polling works🤖 Generated with Claude Code