Skip to content

fix(qodercli): keep child tools on the evaluation session - #219

Open
chiga0 wants to merge 1 commit into
alibaba:mainfrom
chiga0:feat/qoder-session-env
Open

fix(qodercli): keep child tools on the evaluation session#219
chiga0 wants to merge 1 commit into
alibaba:mainfrom
chiga0:feat/qoder-session-env

Conversation

@chiga0

@chiga0 chiga0 commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

Problem

The built-in Qoder engine starts an evaluation, parses Qoder's returned
session_id, and later uses that value for --resume. However, the session is
only learned after the Qoder process exits.

With qodercli 1.1.27, --session-id <id> selects the Qoder conversation but does
not backfill QODER_SESSION_ID into Bash/tool subprocesses. If the variable was
already present in the launcher environment, those subprocesses do inherit it.
This creates two generic failure modes for an evaluation harness:

  1. tools and nested commands cannot correlate their logs, artifacts, caches, or
    traces with the Qoder conversation that invoked them; and
  2. a stale user/configured QODER_SESSION_ID can disagree with Qoder's newly
    generated session, so the parent result and child tools identify different
    conversations.

Minimal observation:

qodercli --session-id <id>        -> result session_id=<id>, Bash child env is empty
QODER_SESSION_ID=<id> qodercli    -> result session_id=<id>, Bash child env=<id>

The CN binary has the same launcher contract through QODERCN_SESSION_ID.

Change

  • Allocate one UUID at the start of each independent Run.
  • Pin it to QODER_SESSION_ID / QODERCN_SESSION_ID after configured and runtime
    environment layers are merged, so stale values cannot override the run.
  • Require Qoder's returned session_id to agree with the launcher-assigned value.
  • Reuse the persisted session ID in both the resume argument and environment for
    RunTurn.

This makes skill-up the owner of the lifecycle it already orchestrates: one
evaluation run has one Qoder session identity, and resumed turns plus child tools
observe that same identity.

Scope and compatibility

  • No Qoder IDE hooks are installed or required.
  • No application-specific environment variables or behavior are introduced.
  • Environment variables belonging to outer agents are not modified.
  • Other engines are unchanged.
  • The only intentional observable change is that Qoder session IDs are allocated
    by the launcher instead of being learned after process exit. They remain normal
    UUID session IDs and continue to be returned in SessionResult.

Verification

  • make verify
  • make test
  • Tests cover distinct IDs for independent runs, stale/configured override
    prevention, Qoder CN mapping, returned-ID agreement, and resume continuity.
  • Real qodercli 1.1.27 run confirmed that the assigned ID is both Qoder's reported
    session_id and the value visible to its Bash subprocess.

@CLAassistant

CLAassistant commented Aug 25, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7d0effe58f

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread internal/agent/qodercli.go Outdated
Comment on lines +234 to +238
for _, key := range []string{
"CODEX_THREAD_ID",
"CLAUDE_CODE_SESSION_ID",
"QODERWORK_SOURCE_CHAT_ID",
} {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Clear the inactive Qoder edition's session variable

When skill-up is launched beneath the opposite Qoder edition—for example, a CN evaluation started from global qodercli—the inherited QODER_SESSION_ID remains set while this code adds QODERCN_SESSION_ID (and vice versa). NoneRuntime begins with os.Environ() and overlays these entries, so both exact identities reach Qoder and its Bash subprocesses, recreating the host-identity conflict this change is intended to prevent. Clear the inactive profile's session variable alongside the other inherited host identities.

Useful? React with 👍 / 👎.

Comment thread internal/agent/qodercli.go Outdated
Comment on lines +377 to +379
envVars := a.qoderRunEnvVars(sessionID)
opts = a.mergeExecOptionsEnv(ctx, opts, envVars, a.buildAgentObservabilityAttrs(nil))
a.pinQoderSessionEnv(&opts, sessionID)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reject a different ID on resumed turns

When a resumed -r invocation reports a different session_id—for example, if Qoder starts a replacement session because the requested one is unavailable—buildSessionResult captures that ID, but the following assignment silently overwrites it with the requested ID. The evaluator then sends later turns to the old session while grading artifacts from the replacement session. Apply the same mismatch validation used by Run before retaining the resumed ID.

Useful? React with 👍 / 👎.

@chiga0
chiga0 force-pushed the feat/qoder-session-env branch from 7d0effe to f30cdf9 Compare August 25, 2026 08:23
@chiga0 chiga0 changed the title fix(qodercli): propagate native session identity fix(qodercli): keep child tools on the evaluation session Aug 25, 2026

@JHWang-1997 JHWang-1997 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The initial-session change is sound, but the resumed-turn path introduces a deterministic Qoder CLI argument conflict.

RunTurn builds qodercli -r <sessionID> and then calls qoderRunEnvVars(sessionID) / pinQoderSessionEnv, which also exports QODER_SESSION_ID=<sessionID> (or QODERCN_SESSION_ID for CN). Qoder maps that environment variable to its --session-id option, so the effective invocation combines --resume and --session-id without --fork-session.

Qoder CLI rejects that combination before authentication or model execution. Reproduction with the official 1.1.27 package:

QODER_SESSION_ID=11111111-1111-4111-8111-111111111111 \
  qodercli \
  --resume 11111111-1111-4111-8111-111111111111 \
  --print --output-format json test

Output:

--session-id can only be used with --continue or --resume when --fork-session is also specified.

The process exits with code 42. I reproduced the same behavior with Qoder CLI 1.1.29. Consequently, the first turn can succeed, but every subsequent RunTurn fails at argument validation. The current fake runtime accepts the combination, so TestQoderCLIRunTurn_ResumeUsesCorrectFlag does not expose the incompatibility.

Please avoid exporting the Qoder session environment variable on the resume path and use only -r <sessionID>, unless Qoder adds a separate child-process propagation mechanism that does not participate in CLI session selection. A parser-level or integration contract test for this combination would also prevent regression.

@chiga0

chiga0 commented Aug 26, 2026

Copy link
Copy Markdown
Contributor Author

Addressed the resume-path conflict in the latest revision:

  • first launch still assigns a fresh native Qoder session ID so child tools inherit exact identity
  • resumed turns clear both QODER_SESSION_ID and QODERCN_SESSION_ID before launching Qoder, and select the existing session only with -r
  • added regression coverage for stale configured/runtime session env on resumed turns

Validation: make verify, targeted Qoder tests, and go test -race ./internal/agent ./internal/runtime with host credential variables removed.

@chiga0
chiga0 force-pushed the feat/qoder-session-env branch from f30cdf9 to 7ffddb8 Compare August 26, 2026 07:40
@JHWang-1997

Copy link
Copy Markdown
Collaborator

Thanks for addressing the resume-path conflict. I checked the latest revision, and clearing both session environment variables before invoking Qoder with -r does resolve the --resume / --session-id incompatibility.

There is just one behavior I would like to clarify before resolving the review. The PR description currently says that resumed turns and their child tools observe the same session identity, while the updated resume path intentionally removes the session variables from Qoder's inherited environment.

If Qoder re-populates the restored session ID for child processes after handling -r, could we add a resumed-turn child-tool test to document that contract? If it does not, the current implementation still looks correct for session resumption, but it may be worth narrowing the PR description to state that launcher-level child-tool propagation is guaranteed only for the initial turn.

To be clear, I am not suggesting restoring QODER_SESSION_ID or QODERCN_SESSION_ID on the resume path, since that would reintroduce the original argument conflict. This is only a request to verify or clarify the remaining child-process behavior.

@chiga0
chiga0 force-pushed the feat/qoder-session-env branch from 7ffddb8 to 6d314db Compare August 26, 2026 08:59
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.

3 participants