Skip to content

feat(modal): per-session custom image + honeycomb-compat Railway deploy hand-off#213

Draft
listar2000 wants to merge 4 commits into
rllm-org:mainfrom
listar2000:honeycomb-compat
Draft

feat(modal): per-session custom image + honeycomb-compat Railway deploy hand-off#213
listar2000 wants to merge 4 commits into
rllm-org:mainfrom
listar2000:honeycomb-compat

Conversation

@listar2000

@listar2000 listar2000 commented Jul 1, 2026

Copy link
Copy Markdown
Collaborator

What & why

A hand-off branch for standing up a standalone agent-sdk server on Railway dedicated to honeycomb
seed/task generation (isolated from the shared staging/production servers, which serve other clients).
Branched off current main (774ade1).

1. feat(modal): per-session custom image (ec3b65d)

Boot a non-default image on the modal supervisor path via a per-session image on the session-create
recipe: Recipe.image_sessions_create_eagerModalSandboxSession._create_kwargs
_get_image(image, dockerfile), resolving an im-... filesystem-snapshot id (Image.from_id), a
docker registry ref (Image.from_registry), or a materialized dockerfile (Image.from_dockerfile),
never memoizing the per-session image into the shared module global. Adds the matching image= kwarg
to the Agent client and to _CLONABLE_FIELDS.

Only the modal provider honors it; the daytona/default path is unaffected (image defaults to
None). This was previously carried as an uncommitted local patch on the box running honeycomb's
generation server — it powers honeycomb's --profile aws LocalStack generation (a combined
LocalStack + agent-sdk-runtime image). Committing it upstream so the deploy branch is self-contained.
The image field 3-way auto-merged cleanly alongside main's new no_reap recipe field.

2. Deploy hand-off docs (c3d1b66)

  • HANDOFF.md — Railway deploy runbook: required/forbidden env, the per-Daytona-org snapshot decision,
    post-deploy verification, the known long-turn stream-drop caveat (Railway edge cap / RAM) + its
    client-side durable fix, a no-app-auth security note, and the client→server contract to preserve.
  • .env.example — env template (DATABASE_URL + DAYTONA_API_KEY required; model creds must NOT be
    set — they're stripped server-side and forwarded per-session by the client).

3. fix(usage): codex cached/thought tokens on the done frame (bdaf04c)

Codex reports token usage on its terminal PromptResponse (camelCase cachedReadTokens/thoughtTokens),
not via a usage_update event, so UsageStats silently dropped a codex run's cache-read and reasoning
tokens. Accumulate both additively (claude snake_case variants tolerated), and add
_meta.quota.token_count to the SSE done-usage probe paths so the client can reconstruct token counts
even on subscription auth (where total_cost_usd stays 0). The client-side field additions are
back-compat (default 0); the SSE probe change is server-side and takes effect on the next server build.

Notes

  • Daytona generation needs none of the modal code (it's dormant there); the branch is deployable
    as-is for the daytona path.
  • .runtime-snapshot-tag is unchanged (agent-sdk-46606ca) — no snapshot rebuild implied.
  • No railway.toml / Dockerfile changes (single-worker session-affinity pin kept intentionally).

🤖 Generated with Claude Code

https://claude.ai/code/session_01EzkMPi5tAr3e4T5HBQ14Dt

listar2000 and others added 2 commits July 1, 2026 00:55
…ockerfile)

Boot a non-default image on the modal supervisor path via a per-session
`image` on the session-create recipe: `Recipe.image` → server reads it in
`_sessions_create_eager` → `ModalSandboxSession._create_kwargs` threads
`recipe.image`/`recipe.dockerfile` → `_get_image(image, dockerfile)` resolves
an `im-...` filesystem-snapshot id (`Image.from_id`), a docker registry ref
(`Image.from_registry`), or a materialized dockerfile (`Image.from_dockerfile`),
never memoizing the per-session image into the shared module global. Adds the
matching `image=` kwarg to the `Agent` client and to `_CLONABLE_FIELDS`.

Only the modal provider honors it; the daytona/default path is unaffected
(`image` defaults to None). Enables honeycomb's `--profile aws` LocalStack
generation (a combined LocalStack + agent-sdk-runtime image); dormant on the
Daytona seed/task-generation path this deployment targets.

Previously carried as an uncommitted local patch on the box that ran the
generation server; committed here so the honeycomb-compat deploy branch is
self-contained.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EzkMPi5tAr3e4T5HBQ14Dt
HANDOFF.md: deploy steps, required/forbidden env, the per-org Daytona snapshot
decision, post-deploy verification, the known long-turn stream-drop blocker
(Railway edge cap / RAM) and its client-side durable fix, a no-app-auth security
note, and the client->server contract to preserve.

.env.example: DATABASE_URL + DAYTONA_API_KEY required; model credentials must
NOT be set (stripped server-side, forwarded per-session by the client); optional
daytona snapshot/image/pool knobs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EzkMPi5tAr3e4T5HBQ14Dt
@Chanbinski2

Copy link
Copy Markdown
Collaborator

Thanks for the PR @listar2000, two things:

  1. Since we want to create a separate server of agent-sdk for honeycomb, can you create this PR to point to another branch, like 'honeycomb' for example?
  2. If your changes regarding modal is just for honeycomb, I think the commits here can just move to the 'honeycomb' branch?

Let me know.

@Chanbinski2

Copy link
Copy Markdown
Collaborator

Also if this is all you need for honeycomb, I can just create a new branch and then set up the credentials on railway. + I'm not sure if railway has a path for codex oauth, so we might need to add that. Let me know what works best for you.

@listar2000

Copy link
Copy Markdown
Collaborator Author

@Chanbinski2 Thanks for the help. I will work locally to get two more features in before getting this to a standalone branch (the current merge to main is just a marker).

  • Daytona support for running oracle AWS task image
  • Codex OAuth support for running evaluations

… boot

Two integration features for honeycomb task generation on this compat branch.

Codex harness — GPT-5.x via `@agentclientprotocol/codex-acp@^1.0.2` (bundles
@openai/codex) as an alternative ACP runtime alongside claude:
- _shared.py: codex npm spec in _ACP_NPM_SPECS; CODEX_ACCESS_TOKEN / CODEX_API_KEY
  in AUTH_KEYS (auto-forwarded from the child env, short-circuits authRequired).
- acp_client.py: one-shot api-key auth fallback on -32000 for codex; _BYPASS_MODE
  (codex -> agent-full-access); set_thought_level routes configId "reasoning_effort"
  for codex vs "thinking" otherwise; codex has no vendor options namespace.
- sandbox/session.py: set_thought_level wrapper + recovery replay bind agent_type.
- client.py: thought_level ctor param (rides config_data via _CLONABLE_FIELDS);
  auto-forward CODEX_ACCESS_TOKEN / CODEX_API_KEY into _secrets_payload for codex.
- sse.py: extract token usage from the done/PromptResponse frame (codex emits no
  usage_update); client astream accumulates self.usage from it.
- supervisor/package.json: enable codex-acp (out of _disabledDependencies; retire
  the stale zed pin) + lockfile.

Daytona per-session image/snapshot — the daytona analog of the modal per-session
image, so a Recipe.image naming a registered snapshot (e.g. honeycomb-aws-combined-v2)
boots the fast snapshot path while a registry ref pulls:
- daytona/__init__.py: provision/create_sandbox accept `image`; boot-source
  precedence image > dockerfile > default snapshot/image; _snapshot_registered
  lookup with positive-only cache; snapshot path drops per-session resources.
- daytona/session.py: pass recipe.image through.
- sandbox/state.py, server.py: doc the daytona image path (Recipe.image already existed).

Tests: test_codex_harness_unit.py, test_daytona_per_session_image_unit.py (14 passing).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EzkMPi5tAr3e4T5HBQ14Dt
@listar2000
listar2000 marked this pull request as draft July 2, 2026 22:04
Codex reports token usage on its terminal PromptResponse (camelCase
cachedReadTokens/thoughtTokens), not via a usage_update event, so
UsageStats silently dropped a codex run's cache-read and reasoning
tokens. Accumulate both additively (claude snake_case variants
tolerated), and add `_meta.quota.token_count` to the SSE done-usage
probe paths so the client can reconstruct token counts even on
subscription auth (where total_cost_usd stays 0).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EzkMPi5tAr3e4T5HBQ14Dt
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.

2 participants