Skip to content

[feat] Extend sessions#5363

Draft
jp-agenta wants to merge 39 commits into
big-agents-add-sessionsfrom
feat/sessions-extensions
Draft

[feat] Extend sessions#5363
jp-agenta wants to merge 39 commits into
big-agents-add-sessionsfrom
feat/sessions-extensions

Conversation

@jp-agenta

Copy link
Copy Markdown
Member

No description provided.

jp-agenta and others added 30 commits July 17, 2026 13:29
MountDBA had a bare nullable session_id but no agent_id, so agent mounts
were only findable by slug pattern-matching (asymmetric with session
mounts). Add a nullable agent_id String column + partial index mirroring
session_id, and backfill existing agent-mount rows by parsing the id out
of their `__ag__agent__<id>__<name>` slug (deterministic — the agent
segment is the raw canonical artifact id, unlike the session segment
which is a uuid5 hash). Mounts are core DB, so this backfill is allowed
(unlike the tracing DB). Session-mount rows stay agent_id-null.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Populate agent_id in get_or_create_agent_mount (the caller already holds
artifact_id) via a new mint_agent_id helper shared with mint_agent_slug,
so the slug's id segment and the column derive byte-identically from the
same artifact id. Add agent_id to the mount query DTO/DAO filter and the
/mounts/query request/router, mirroring the existing session_id filter.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…arsing

Unit tests: a new agent mount's agent_id matches its slug's id segment;
session mounts stay agent_id-null; query_mounts filters by agent_id
(extends the in-memory DAO test double to support it); and the
migration's SQL backfill parser is pinned in Python against
mint_agent_slug/mint_agent_id so any slug-format drift is caught without
a live DB (the SQL itself was verified against a real Postgres instance
during implementation).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Promote session/user/agent identity from JSONB attributes to nullable
root-level columns on the spans table (tracing_oss migration
oss000000003, chained off oss000000002_add_records — the live OSS
tracing tree, post-park). Wire the columns through SpanDBA/SpanDBE, the
OTelFlatSpan DTO, and the DAO mappings/filtering so they're queryable
via the existing Condition/Filtering API. Add a (project_id, session_id)
index. No data migration — old spans stay null (tracing-DB forward-fill
only rule). Leaves a deferred note on the JSONB list_sessions query that
could become an indexed scan once this lands.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add promote_identity_by_trace, grouped by trace_id alongside the
existing trace-type inference and metrics propagation in
ingest_span_dtos. Lifts ag.session.id/ag.user.id/ag.agent.id from each
trace's root span (parent_id is None) onto the new DTO fields; child
spans are left untouched. Root-only because ingestion is span-by-span /
partial-batch — a trace's root and children can arrive in different
requests, so there is no cheap way to propagate to children safely.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add Tracing.store_agent (mirrors store_session/store_user) stamping
ag.agent.id on the current span. Resolve the agent id in
NormalizerMiddleware.__call__ from RunningContext.revision.artifact_id
(falling back to the workflow_id alias) — workflow, application, and
evaluator invocations all resolve through the same WorkflowRevision
shape, so one seam covers all three. Called once per invocation
alongside store_session, before the handler runs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add gen_ai.agent.id -> ag.agent.id to the GenAI semconv table shared by
the Logfire adapter (OpenInference and Vercel AI have no agent-identity
telemetry field to map from). Wiring this through required more than
the adapter's own mapping table: SpanFeatures had no `agent` bucket,
NAMESPACE_PREFIX_FEATURE_MAPPING had no ag.agent. prefix entry, and
span_data_builders.py never flushed a features.agent bucket back onto
attributes — session/user only. All three needed the same treatment
already given to session/user for agent id to actually reach the span.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
New core-DB table, one row per turn (1:many by session_id), absorbing the
per-turn resume fold currently folded into session_states.data. Composite pk
(project_id, id), FK to session_streams (project_id, id) ON DELETE NO ACTION
(no cascade — delete is an explicit session-scoped fan-out), GIN
jsonb_path_ops index on references (eval_runs pattern), indexes on
(project_id, session_id) and (project_id, session_id, turn_index).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
core/sessions/turns/: SessionTurn DTOs, Harness(str, Enum) enumerated from the
runner's services/runner/src/version.ts HARNESSES (pi_core default, pi_agenta,
claude), SessionTurnsDAOInterface, SessionTurnsService.

dbs/postgres/sessions/turns/: SessionTurnDBE (no data/flags/tags/meta — every
field first-class/queryable), mappings, and SessionTurnsDAO with:
- append / fetch_turn / query_turns (apply_windowing + references .contains(),
  the eval_runs GIN jsonb_path_ops pattern, not the git temporary adapter)
- latest_turn / latest_turn_per_harness — the resume-read the runner needs
  (WP3): ORDER BY turn_index DESC LIMIT 1, so a late lower-index write can
  never win
- delete_by_session_id — hard delete (WP5's session-delete fan-out)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
SessionTurnsRouter (apis/fastapi/sessions/router.py) exposes:
  POST /sessions/turns/       append_turn   (RUN_SESSIONS)
  POST /sessions/turns/query  query_turns   (VIEW_SESSIONS)
  GET  /sessions/turns/{id}   fetch_turn    (VIEW_SESSIONS)

append_turn reads user_id from the caller's credential and threads it through
service -> dao -> created_by_id, mirroring the streams/interactions pattern.

Composed into SessionsRouter as `.turns`; entrypoints/routers.py instantiates
SessionTurnsDAO/SessionTurnsService next to the streams wiring and mounts the
router under /sessions/turns.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Against a real Postgres (core_oss migration chain applied): append round-trips
every field and sets created_by_id from the caller; query_turns filters by
references via the GIN .contains() pattern; windowed query lists newest first;
latest_turn / latest_turn_per_harness resolve correctly even when a
lower-turn_index row is appended last; delete_by_session_id hard-deletes and
leaves no rows.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds two nullable, plain (no-FK) columns to the tracing DB's records
table: turn_id (str) groups records by the turn that produced them;
span_id (uuid) bridges to the observability span. Both are forward-fill
only per the tracing-DB rule (never backfill/data-migrate that DB) --
new records carry them, existing rows stay null since they carry no
turn key to reconstruct one from.

Migration oss000000003 chains from this worktree's real tracing_oss
head (oss000000002_add_records). Threads the columns through
RecordDBA/RecordDBE, SessionRecord/SessionRecordEvent DTOs,
SessionRecordIngestRequest, the ingest router handler, and the
DAO's upsert (both insert and on-conflict paths), plus an optional
(project_id, session_id, turn_id) index for grouping.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
buildPersistingEmitter and postEvent (services/runner/src/sessions/persist.ts)
now accept optional turnId/spanId and stamp them onto every record's ingest
body, so the API's new session_records.turn_id/span_id columns get populated
at the source. server.ts's session-owned call site passes the turn id already
minted at resolveTurnId (turnId, in scope since line ~859) and the request's
propagated span (request.runContext?.trace?.span_id) when tracing supplied one.

Both params are optional and appended at the end of existing signatures, so
this stays additive for WP3's later edit to the same file.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add name/description (HeaderDBA) to session_streams and point the
/sessions/states/ header surface at the merged row: GET reads the header,
PUT/POST is a full-PUT {name, description} rename edit gated EDIT_SESSIONS,
off the runner's write path. The flag-mirror/heartbeat paths use a separate
SessionStreamEdit path that never carries name/description, so heartbeats
can't churn the header. session_states stays present-but-unused; the DROP
is deferred to WPI after WP3's runner cutover.

Migration oss000000015 chains from WP1's oss000000014 head.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Unit tests (test_stream_header_merge.py): the header edit round-trips
through the DBE mapping and DAO, a heartbeat/detach/kill flag-mirror write
never clobbers a prior rename, flags still mirror the Redis nest, and the
rename creates the row on a session's first touch (with a race fallback
to update when a concurrent heartbeat wins the create).

Rewrites the two acceptance suites under session_states/ that asserted the
old data-blob/sandbox_id RMW semantics (retired by the merge) to instead
exercise the new {name, description} rename contract.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The runner already POSTs /sessions/streams/heartbeat every turn and discarded
the response; it carries stream.id (the session_streams row uuid) at zero
extra cost. Await the watchdog's first heartbeat (only) so stream_id is ready
before the turn starts, and thread it onto AgentRunRequest.streamId for the
turn-append write site to consume.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace syncHarnessSessionDurable's GET-then-PUT of the whole session_states
.data blob with appendSessionTurn, a plain POST /sessions/turns/ insert per
completed turn (session_id, stream_id, harness, agent_session_id, sandbox_id,
turn_index, references, trace_id) — no read, no merge, no race.

Resume/eligibility reads (hydrateHarnessSessionFromDurable) and the sandbox
reconnect pointer (readStoredSandboxPointer) now query the latest turn
(POST /sessions/turns/query, windowed limit=1 order=descending on the uuid7
id, equivalent to turn_index DESC for an append-only table) instead of the
1:1 states row. The old atomic sandbox_turn_index staleness guard dissolves:
a late lower-index turn can never win the ordered read, so the separate
writeSandboxPointer/clearSandboxPointer PUTs and the terminal-reconnect clear
are retired — the live sandbox id rides forward as a field on the next
completed turn's row instead.

W3.0 verify-first finding: the per-turn resume write at the one write site
(sandbox_agent.ts runTurn, ~2295) is agent_session_id-shaped only (harness,
agentSessionId, turnIndex) — no richer separate SDK blob is round-tripped.
This confirms the session_states drop (WPI, after this cutover) is safe.

References populate from request.runContext.workflow.{artifact,variant,
revision} (buildWorkflowReferences, flattened to a bare list per the eval_runs
convention — the dict key is dropped, only {id,slug,version} survive) and
trace_id from run.traceId(), both already in scope at the write site.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
New DAO methods for the session-level delete/archive fan-out, all previously
soft-delete-only: SessionInteractionsDAO.delete_by_session_id (hard delete,
was soft-only via cancel_session_pending's status flip),
SessionStreamsDAO.hard_delete_by_session_id (hard delete, kill only
soft-deletes) + unarchive_by_session_id/get_by_session_id_including_archived
(the archive round-trip's reverse + confirmation read), and
MountsDAO.delete_by_session_id (hard delete of session-bound mount rows,
returning the deleted rows for object-store teardown). Streams query() also
gains optional windowing + session_ids filtering for the root query_sessions
endpoint. MountsService grows delete_session_mounts (rows + ObjectStore
prefix teardown) and archive/unarchive_session_mounts (soft, reversible).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
New root-level session operations orchestrating across the streams/turns/
interactions/mounts facets, anchored on session_id (never stream_id):

- POST /sessions/query (query_sessions): lists/filters the merged stream
  rows, newest->oldest, windowed. A references filter joins the turns'
  references (WP1's GIN .contains()) to resolve matching session_ids first,
  then filters the stream query to that set — no denormalization onto the
  stream row (B3).
- DELETE /sessions/?session_id=: hard-delete fan-out (turns, interactions,
  mounts + their object-store prefixes, then the stream row). Records are
  never touched — cross-DB, left to tracing retention.
- POST /sessions/archive / /sessions/unarchive: the same fan-out but soft
  (deleted_at), including the bound mounts (reversible); folders untouched.

RBAC: VIEW_SESSIONS for query, EDIT_SESSIONS for the three mutations. Wired
as SessionsRouter.root in apis/fastapi/sessions/router.py and mounted
unprefixed in api/entrypoints/routers.py alongside the other session
sub-routers.

peek (S12/E1) is deliberately NOT built as a server-side aggregate: the
individual reads (query_sessions here, GET /sessions/streams/?session_id=,
turns/records query-or-fetch) are the whole read surface, documented in the
router module docstring as what the front-end composes.

Renamed the deprecated OTel-side /tracing/sessions/query operation_id to
query_sessions_tracing (was query_sessions) to resolve the FastAPI
duplicate-operation-id collision with the new endpoint, following the
existing delete_trace_tracing disambiguation precedent in the same router.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- test_sessions_root_service.py: SessionsService orchestration (fakes each
  sub-service) — delete fan-out order/keys, archive/unarchive round-trip,
  reference-join query with windowing pass-through and no-match short-circuit.
- test_wp5_root_router.py: SessionsRootRouter RBAC gating + service
  delegation (mirrors test_record_ingest_endpoint.py's mock-Request pattern).
- test_wp5_dao_fanout.py: integration tests against a real Postgres for the
  new hard-delete/unarchive DAO methods (interactions, streams, mounts),
  including the soft-vs-hard-delete distinction and session-scoping.
- test_wp5_mount_teardown.py: MountsService delete/archive/unarchive_session_
  mounts — object-store delete_prefix call shape, and that archive/unarchive
  never touch the store.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… (W7.1/E6)

send/steer/cancel/attach in SessionStreamsService.command() are now keyed on
data.inputs (a WorkflowServiceRequestData, matching WorkflowInvokeRequest.data.inputs)
present-or-not x force, replacing the bespoke prompt string. Also fixes heartbeat()'s
acquire-then-refresh fallback, which previously masked a cancel/steer/kill that raced
a heartbeat by silently re-acquiring the alive/running lock under the SAME turn_id;
SessionHeartbeatResult now carries is_current_turn so the runner's watchdog can tell
a genuine interruption from this turn's own first-touch establishment.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
SessionStreamsService.kill() previously only force-cleared the Redis nest and
soft-deleted the stream row -- nothing called the runner's POST /kill
(services/runner/src/server.ts), so a live sandbox kept running until its own
idle-TTL eviction. kill_runner_sandbox (core/sessions/streams/runner_client.py)
adds that direct API -> runner hop, scoped to (project_id, session_id), reusing
the same AGENTA_RUNNER_INTERNAL_URL/AGENTA_RUNNER_TOKEN the Python agent service
already uses. Best-effort: kill's Redis/row edit remains authoritative and must
not depend on the runner being reachable.

Wires the two env vars into the API container/deployment across all compose
files and the Helm chart (previously only the services/agent-service container
had them), and updates the self-host configuration reference doc.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…uption (W7.4)

For a session-owned run, server.ts's AbortController was never fed by anything --
a client disconnect only flipped clientDisconnected (a park-vs-destroy signal),
and losing the alive lock to a cancel/steer/kill was invisible to the runner
process (the heartbeat loop only logged non-OK responses and never inspected the
body). startAliveWatchdog now takes an onInterrupted callback, fired at most once
when a beat's is_current_turn:false; server.ts wires it to controller.abort(),
which already feeds the sandbox-agent engine's existing signal-based teardown
(runSandboxAgent's startOptions.signal) -- the same mechanism a client disconnect
used for non-session runs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ns 014, header 015)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…r span-identity 003)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Resolves alive.ts + server.ts conflicts with WP7 (both restructured the heartbeat
path for orthogonal reasons): sendHeartbeat returns { streamId, interrupted } (both
signals from the one response body); startAliveWatchdog is async (WP3, awaits first
beat for stream_id) AND takes onInterrupted (WP7, control-signal -> controller.abort).
WP7's interrupt test updated to await the now-async watchdog.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ates

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented Jul 17, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
agenta-documentation Ready Ready Preview, Comment Jul 17, 2026 6:34pm

Request Review

@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: e2d2f263-8622-4d46-a2cb-1b76a589bf6c

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/sessions-extensions

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

…runner tests

Picks the 3-file dependency bump from vibes/runner-daytona-otel-bump so the installed
2.x OTel deps match the otel.ts API (resourceFromAttributes/spanProcessors/
parentSpanContext). Resolves 39 pre-existing 'Resource is not a constructor' failures.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
mmabrouk added a commit that referenced this pull request Jul 18, 2026
Rebases the runner third of JP's feat/sessions-extensions (PR #5363) onto
current main, ported into the post-decomposition module layout (PR #5369).

JP wrote these against the old monolithic sandbox_agent.ts; they are re-homed
by region into the decomposed modules:
- The SandboxAgentDeps interface change (syncHarnessSessionDurable renamed to
  appendSessionTurn; the write/clear sandbox-pointer deps dropped) goes into
  runtime-contracts.ts.
- The two acquireEnvironment branches (the reconnect-failure path and the
  post-hydrate pointer write, both now append-only with no pre-turn pointer PUT)
  go into environment.ts.
- The turn-completion sync (syncHarnessSessionDurable replaced by appendSessionTurn
  with the streamId gate, workflow references, sandbox id, and trace id) goes into
  run-turn.ts.
The sandbox-reconnect.ts and session-continuity-durable.ts rewrites apply as-is.
protocol.ts, sessions/alive.ts, sessions/persist.ts, version.ts, and the tests
are JP's versions verbatim.

Ported from feat/sessions-extensions@1532ec7fe5 (JP).

Reconciliations with the release main:
- server.ts: kept main's session-identity / session-pool import split from the
  decomposition and applied JP's watchdog changes (startAliveWatchdog is now
  awaited and takes an onInterrupted callback that aborts the controller,
  request.streamId is threaded from the heartbeat, and buildPersistingEmitter
  gets turnId and span_id).
- tracing/otel.ts, package.json, pnpm-lock.yaml: kept main's. The OTel 2.x bump
  JP carried is already in main, and main additionally has the #5364
  trace-id-on-done feature that JP's branch predates.

Verified: pnpm run typecheck clean, pnpm test 1202/1202 pass, build:extension ok.

Claude-Session: https://claude.ai/code/session_01DnWRxU3dCJ11hgDidm26vW
mmabrouk added a commit that referenced this pull request Jul 18, 2026
Rebases the backend two-thirds of JP's feat/sessions-extensions (PR #5363)
onto current main (v0.105.5). Covers api, SDK, Fern python client, and the
web generated client: the append-only session_turns domain replacing
session_states, the stream command discriminator rename (prompt -> inputs/data),
the root /sessions router and SessionsService, /kill teardown wiring, span
identity columns plus ag.agent.id, and mounts agent_id.

Ported from feat/sessions-extensions@1532ec7fe5 (JP).

Reconciliations with the release main:
- Kept main's pi-openai model_ref threading (PiHarness/AgentaHarness) and the
  EndpointResolutionError export alongside JP's HarnessType -> HarnessKind rename.
- Kept main's 0.105.5 version in api/pyproject.toml while re-adding JP's
  greenlet dependency; api/uv.lock updated for greenlet only.
- Kept main's sdks/python and services uv.lock (JP's were stale transitive bumps).

Claude-Session: https://claude.ai/code/session_01DnWRxU3dCJ11hgDidm26vW
mmabrouk added a commit that referenced this pull request Jul 18, 2026
Rebases the runner third of JP's feat/sessions-extensions (PR #5363) onto
current main, ported into the post-decomposition module layout (PR #5369).

JP wrote these against the old monolithic sandbox_agent.ts; they are re-homed
by region into the decomposed modules:
- The SandboxAgentDeps interface change (syncHarnessSessionDurable renamed to
  appendSessionTurn; the write/clear sandbox-pointer deps dropped) goes into
  runtime-contracts.ts.
- The two acquireEnvironment branches (the reconnect-failure path and the
  post-hydrate pointer write, both now append-only with no pre-turn pointer PUT)
  go into environment.ts.
- The turn-completion sync (syncHarnessSessionDurable replaced by appendSessionTurn
  with the streamId gate, workflow references, sandbox id, and trace id) goes into
  run-turn.ts.
The sandbox-reconnect.ts and session-continuity-durable.ts rewrites apply as-is.
protocol.ts, sessions/alive.ts, sessions/persist.ts, version.ts, and the tests
are JP's versions verbatim.

Ported from feat/sessions-extensions@1532ec7fe5 (JP).

Reconciliations with the release main:
- server.ts: kept main's session-identity / session-pool import split from the
  decomposition and applied JP's watchdog changes (startAliveWatchdog is now
  awaited and takes an onInterrupted callback that aborts the controller,
  request.streamId is threaded from the heartbeat, and buildPersistingEmitter
  gets turnId and span_id).
- tracing/otel.ts, package.json, pnpm-lock.yaml: kept main's. The OTel 2.x bump
  JP carried is already in main, and main additionally has the #5364
  trace-id-on-done feature that JP's branch predates.

Verified: pnpm run typecheck clean, pnpm test 1202/1202 pass, build:extension ok.

Claude-Session: https://claude.ai/code/session_01DnWRxU3dCJ11hgDidm26vW
mmabrouk added a commit that referenced this pull request Jul 18, 2026
Rebases the backend two-thirds of JP's feat/sessions-extensions (PR #5363)
onto current main (v0.105.5). Covers api, SDK, Fern python client, and the
web generated client: the append-only session_turns domain replacing
session_states, the stream command discriminator rename (prompt -> inputs/data),
the root /sessions router and SessionsService, /kill teardown wiring, span
identity columns plus ag.agent.id, and mounts agent_id.

Ported from feat/sessions-extensions@1532ec7fe5 (JP).

Reconciliations with the release main:
- Kept main's pi-openai model_ref threading (PiHarness/AgentaHarness) and the
  EndpointResolutionError export alongside JP's HarnessType -> HarnessKind rename.
- Kept main's 0.105.5 version in api/pyproject.toml while re-adding JP's
  greenlet dependency; api/uv.lock updated for greenlet only.
- Kept main's sdks/python and services uv.lock (JP's were stale transitive bumps).

Claude-Session: https://claude.ai/code/session_01DnWRxU3dCJ11hgDidm26vW
mmabrouk added a commit that referenced this pull request Jul 18, 2026
Rebases the runner third of JP's feat/sessions-extensions (PR #5363) onto
current main, ported into the post-decomposition module layout (PR #5369).

JP wrote these against the old monolithic sandbox_agent.ts; they are re-homed
by region into the decomposed modules:
- The SandboxAgentDeps interface change (syncHarnessSessionDurable renamed to
  appendSessionTurn; the write/clear sandbox-pointer deps dropped) goes into
  runtime-contracts.ts.
- The two acquireEnvironment branches (the reconnect-failure path and the
  post-hydrate pointer write, both now append-only with no pre-turn pointer PUT)
  go into environment.ts.
- The turn-completion sync (syncHarnessSessionDurable replaced by appendSessionTurn
  with the streamId gate, workflow references, sandbox id, and trace id) goes into
  run-turn.ts.
The sandbox-reconnect.ts and session-continuity-durable.ts rewrites apply as-is.
protocol.ts, sessions/alive.ts, sessions/persist.ts, version.ts, and the tests
are JP's versions verbatim.

Ported from feat/sessions-extensions@1532ec7fe5 (JP).

Reconciliations with the release main:
- server.ts: kept main's session-identity / session-pool import split from the
  decomposition and applied JP's watchdog changes (startAliveWatchdog is now
  awaited and takes an onInterrupted callback that aborts the controller,
  request.streamId is threaded from the heartbeat, and buildPersistingEmitter
  gets turnId and span_id).
- tracing/otel.ts, package.json, pnpm-lock.yaml: kept main's. The OTel 2.x bump
  JP carried is already in main, and main additionally has the #5364
  trace-id-on-done feature that JP's branch predates.

Verified: pnpm run typecheck clean, pnpm test 1202/1202 pass, build:extension ok.

Claude-Session: https://claude.ai/code/session_01DnWRxU3dCJ11hgDidm26vW
mmabrouk added a commit that referenced this pull request Jul 19, 2026
Rebases the runner third of JP's feat/sessions-extensions (PR #5363) onto
current main, ported into the post-decomposition module layout (PR #5369).

JP wrote these against the old monolithic sandbox_agent.ts; they are re-homed
by region into the decomposed modules:
- The SandboxAgentDeps interface change (syncHarnessSessionDurable renamed to
  appendSessionTurn; the write/clear sandbox-pointer deps dropped) goes into
  runtime-contracts.ts.
- The two acquireEnvironment branches (the reconnect-failure path and the
  post-hydrate pointer write, both now append-only with no pre-turn pointer PUT)
  go into environment.ts.
- The turn-completion sync (syncHarnessSessionDurable replaced by appendSessionTurn
  with the streamId gate, workflow references, sandbox id, and trace id) goes into
  run-turn.ts.
The sandbox-reconnect.ts and session-continuity-durable.ts rewrites apply as-is.
protocol.ts, sessions/alive.ts, sessions/persist.ts, version.ts, and the tests
are JP's versions verbatim.

Ported from feat/sessions-extensions@1532ec7fe5 (JP).

Reconciliations with the release main:
- server.ts: kept main's session-identity / session-pool import split from the
  decomposition and applied JP's watchdog changes (startAliveWatchdog is now
  awaited and takes an onInterrupted callback that aborts the controller,
  request.streamId is threaded from the heartbeat, and buildPersistingEmitter
  gets turnId and span_id).
- tracing/otel.ts, package.json, pnpm-lock.yaml: kept main's. The OTel 2.x bump
  JP carried is already in main, and main additionally has the #5364
  trace-id-on-done feature that JP's branch predates.

Verified: pnpm run typecheck clean, pnpm test 1202/1202 pass, build:extension ok.

Claude-Session: https://claude.ai/code/session_01DnWRxU3dCJ11hgDidm26vW
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