Skip to content

feat: opper launch URL-sessions for usage attribution#11

Merged
joch merged 9 commits intomainfrom
url-sessions
May 7, 2026
Merged

feat: opper launch URL-sessions for usage attribution#11
joch merged 9 commits intomainfrom
url-sessions

Conversation

@joch
Copy link
Copy Markdown
Member

@joch joch commented May 7, 2026

Summary

Mint a sess_<uuid> per opper launch, accept repeatable --tag k=v flags, and embed both into the agent's base URL as /v3/session/<sid>[/k:v]* so every spawned-agent LLM call carries the session id + tags. The post-launch summary now queries /v2/analytics/usage?session_id=<sid>, fixing the wall-clock conflation when launches overlap.

All six launchable adapters (Claude Code, Hermes, Codex, OpenCode, OpenClaw, Pi) now consume routing.baseUrl so URL-sessions work uniformly. Server-side support ships in opper-ai/opper#2270.

Validation matches the server byte-for-byte:

  • Key regex ^[a-zA-Z][a-zA-Z0-9_.-]{0,63}$, opper.* reserved (case-insensitive).
  • Max 8 pairs, max 256 UTF-8 bytes per value.
  • Comma-separated --tag a=1,b=2 rejected; duplicate keys rejected.

Test plan

  • npm test — 296/296 pass, including: URL builder + tag validator (10 tests), collectTagPairs (8 tests), launch session prefix + flag handling (5 new tests), summary query shape (2 new tests), per-adapter session URL forwarding (Claude Code, Codex, OpenClaw, Pi each assert the session URL lands in their config / env).
  • npm run build clean.
  • Manual smoke: opper launch claude --tag customer=acme → tags land in BillableEvent.tags; opper usage list --group-by=customer buckets correctly.

Notes

  • Direct invocation of codex / pi / openclaw / opencode (without opper launch) inherits the previous session's URL because we rewrite-on-spawn rather than snapshot/restore. Known limitation; tracked as a follow-up.
  • Version bumped 0.1.140.1.16 (branch was a stale rebase on 0.1.14; main is at 0.1.15).

joch added 8 commits May 7, 2026 14:35
Previously only claude-code and hermes consumed routing.baseUrl. The
other four launchable adapters (codex, openclaw, pi, opencode) hard-coded
OPPER_COMPAT_URL, silently dropping the per-session URL minted by
opper launch. Each adapter now writes routing.baseUrl into its own
config on every spawn:

- codex: rewrites the managed sentinel block in ~/.codex/config.toml
  with the session URL as base_url. configure() (menu/agents flow)
  keeps the default compat URL. isConfigured() no longer pins the URL
  value, since spawn rewrites it per-session.
- openclaw / pi: setOpperProvider gains a baseUrl parameter; spawn
  passes routing.baseUrl, configure passes OPPER_COMPAT_URL.
- opencode: a new setSessionBaseUrl helper rewrites
  provider.opper.options.baseURL on every launch (the bundled
  template still ships the default compat URL).

Tests added for openclaw and pi (none existed); codex and opencode
tests now use a realistic session URL and assert it lands in the
config on disk.

A consequence: if the user later runs the agent directly without
opper launch, it inherits the last session's URL. Documented as a
known follow-up; this PR doesn't introduce snapshot/restore.
Copy link
Copy Markdown

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

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: a6be79a3ee

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/cli/agents.ts Outdated
The previous check rejected any comma in the value, which blocked
legitimate inputs like \`customer=Acme, Inc\`. Narrow the check to the
multi-pair shorthand (a=1,b=2) — only reject when a comma is followed
by another \`key=\` token.

Codex review feedback on PR #11.
@joch
Copy link
Copy Markdown
Member Author

joch commented May 7, 2026

@codex review — addressed P2 on collectTagPairs in cd19c90: comma in value is now only rejected when it's followed by another key= (the multi-pair shorthand). Plain commas in values (customer=Acme, Inc) round-trip cleanly. Test added.

@chatgpt-codex-connector
Copy link
Copy Markdown

Codex Review: Didn't find any major issues. More of your lovely PRs please.

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@joch joch merged commit 57980f8 into main May 7, 2026
4 checks passed
@joch joch deleted the url-sessions branch May 7, 2026 13:27
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.

1 participant