Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
81 commits
Select commit Hold shift + click to select a range
fec63cb
fix(code): skip manual HITL for the `/offload` seeded compaction
mdrxy Jul 31, 2026
153f675
Merge branch 'main' into mdrxy/code/offload-seeded-compaction-no-hitl
mdrxy Aug 3, 2026
04b9ef7
fix(code): harden the `/offload` seeded compaction bypass
mdrxy Aug 3, 2026
07d1f9b
Merge branch 'main' into mdrxy/code/offload-seeded-compaction-no-hitl
mdrxy Aug 3, 2026
e3e2449
refactor(code): run /offload as a server operation
mdrxy Aug 3, 2026
76d8e02
Merge branch 'main' into mdrxy/code/offload-seeded-compaction-no-hitl
mdrxy Aug 3, 2026
5099442
test(code): cover the offload operation graph
mdrxy Aug 3, 2026
5f8e993
fix(code): restore /offload for local agents and repair the operation…
mdrxy Aug 3, 2026
3345e11
refactor(code): share /offload middleware via named resources and sur…
mdrxy Aug 4, 2026
19afc63
Merge remote-tracking branch 'origin/main' into mdrxy/code/offload-se…
mdrxy Aug 4, 2026
3891583
Merge remote-tracking branch 'origin/main' into mdrxy/code/offload-se…
mdrxy Aug 4, 2026
2fd189d
fix(code): fulfill server hook interrupts and restore main graph bind…
mdrxy Aug 4, 2026
b8a27bd
Merge branch 'main' into mdrxy/code/offload-seeded-compaction-no-hitl
mdrxy Aug 4, 2026
2aea101
fix(code): restrict the /offload graph's input surface and report dra…
mdrxy Aug 5, 2026
41b2939
Merge remote-tracking branch 'origin/main' into mdrxy/code/offload-se…
mdrxy Aug 5, 2026
76c5579
Merge branch 'main' into mdrxy/code/offload-seeded-compaction-no-hitl
mdrxy Aug 5, 2026
f2841e1
Merge branch 'main' into mdrxy/code/offload-seeded-compaction-no-hitl
mdrxy Aug 6, 2026
c1bd68e
fix(code): preserve offload hook interrupts
mdrxy Aug 6, 2026
6477ace
fix(code): keep the /offload hook dispatch answerable across resumes
mdrxy Aug 6, 2026
d84e654
fix(code): import `_OffloadInput` `TypedDict` from `typing_extensions`
mdrxy Aug 6, 2026
cd13f1c
Merge branch 'main' into mdrxy/code/offload-seeded-compaction-no-hitl
mdrxy Aug 6, 2026
8a5c3e3
fix(code): correct the /offload run's stream shape and replay semantics
mdrxy Aug 6, 2026
2e551cb
Merge branch 'main' into mdrxy/code/offload-seeded-compaction-no-hitl
mdrxy Aug 6, 2026
5d03307
fix(code): preserve custom graph offload fallback
mdrxy Aug 6, 2026
c1635f8
fix(code): abort `/offload` when the pre-run state refresh fails
mdrxy Aug 6, 2026
f2fa372
Merge branch 'main' into mdrxy/code/offload-seeded-compaction-no-hitl
mdrxy Aug 11, 2026
4866241
Merge branch 'main' into mdrxy/code/offload-seeded-compaction-no-hitl
mdrxy Aug 11, 2026
2723ed8
refactor(code): prototype server-owned `/offload`
mdrxy Aug 11, 2026
dc679f4
feat(code): make `/offload` server-owned
mdrxy Aug 11, 2026
8f66044
Merge branch 'main' into mdrxy/code/offload-seeded-compaction-no-hitl
mdrxy Aug 13, 2026
fd69968
fix(code): catch SDK NotFoundError in offload capability probe
mdrxy Aug 13, 2026
301557c
Merge remote-tracking branch 'origin/main' into mdrxy/code/offload-se…
mdrxy Aug 14, 2026
7ca1e8a
fix(code): hydrate persisted summaries during offload
mdrxy Aug 17, 2026
e11e70a
fix(code): harden the server-owned offload boundary
mdrxy Aug 17, 2026
0cb41c6
Merge remote-tracking branch 'origin/main' into mdrxy/code/offload-se…
mdrxy Aug 17, 2026
f31cc92
Merge branch 'main' into mdrxy/code/offload-seeded-compaction-no-hitl
mdrxy Aug 18, 2026
3e0d2fa
Merge branch 'main' into mdrxy/code/offload-seeded-compaction-no-hitl
mdrxy Aug 19, 2026
d93318a
Merge branch 'main' into mdrxy/code/offload-seeded-compaction-no-hitl
mdrxy Aug 19, 2026
5b1407f
fix(code): preserve offload archive sessions
mdrxy Aug 19, 2026
454b36f
fix(code): register the thread before a server-owned offload
mdrxy Aug 19, 2026
9c49964
fix(code): report an empty thread as nothing to offload
mdrxy Aug 19, 2026
9535b73
fix(code): restore offload token-report parity on the server path
mdrxy Aug 19, 2026
29dedef
fix(code): never lose drained cost records to a cancelled probe
mdrxy Aug 19, 2026
bdfe4f0
fix(code): contain the startup barrier inside the offload route
mdrxy Aug 19, 2026
b2f8041
test(code): cover the offload hook transport at the route
mdrxy Aug 19, 2026
e2ca9b1
test(code): assert the archive's real name in the server offload test
mdrxy Aug 19, 2026
df1ef96
docs(code): correct offload docs left over from the prototype
mdrxy Aug 19, 2026
c8c0d93
fix(code): fail closed on an unreadable offload hook decision
mdrxy Aug 19, 2026
d33c27f
test(code): cover offload archive-persistence messaging
mdrxy Aug 19, 2026
76a4285
refactor(code): tighten the offload operation's weakest invariants
mdrxy Aug 19, 2026
a024d8a
fix(code): refuse to build a reasonless offload refusal
mdrxy Aug 19, 2026
03ee0bf
Merge branch 'main' into mdrxy/code/offload-seeded-compaction-no-hitl
mdrxy Aug 19, 2026
2e2dc10
Merge branch 'main' into mdrxy/code/offload-seeded-compaction-no-hitl
mdrxy Aug 19, 2026
6930ff8
Merge branch 'main' into mdrxy/code/offload-seeded-compaction-no-hitl
mdrxy Aug 24, 2026
bb06345
Merge branch 'main' into mdrxy/code/offload-seeded-compaction-no-hitl
mdrxy Aug 24, 2026
ca0f5e6
refactor(code): remove seeded offload fallback
mdrxy Aug 24, 2026
a169879
fix(code): strip endpoint and transport keys from client-supplied off…
mdrxy Aug 24, 2026
b523ed4
Merge branch 'main' into mdrxy/code/offload-seeded-compaction-no-hitl
mdrxy Aug 24, 2026
7817762
fix(code): preserve trusted offload model transport
mdrxy Aug 24, 2026
7aff13c
fix(code): defer offload archives until checkpoint reservation
mdrxy Aug 24, 2026
add97ae
fix(code): confirm server offload cancellation
mdrxy Aug 24, 2026
83add32
fix(code): preserve custom provider offload routing
mdrxy Aug 24, 2026
6b420de
fix(code): allow offload on a thread whose last run errored
mdrxy Aug 24, 2026
4bafc64
fix(code): stop reporting a committed offload as failed
mdrxy Aug 24, 2026
ecb2d99
fix(code): enforce the offload write allowlist the type declares
mdrxy Aug 24, 2026
95a1de0
refactor(code): drop the unused offload protocol handshake
mdrxy Aug 24, 2026
0c9d4a5
fix(code): name the cause when a server lacks the offload route
mdrxy Aug 24, 2026
8dd9294
feat(code): make an abandoned cost prepare observable
mdrxy Aug 24, 2026
d353c7e
fix(code): stop logging an unobserved thread advance
mdrxy Aug 24, 2026
fae0bb0
fix(code): send the session approval mode with offload
mdrxy Aug 24, 2026
27552a2
fix(code): log dropped offload transport params
mdrxy Aug 24, 2026
bb2dd00
docs(code): correct comments left stale by server-owned offload
mdrxy Aug 24, 2026
07978b3
docs(code): correct and split THREAT_MODEL offload entries
mdrxy Aug 24, 2026
4d1190f
test(code): cover the per-thread offload lock
mdrxy Aug 24, 2026
086452d
test(code): exercise the offload routes through Starlette
mdrxy Aug 24, 2026
63a399b
fix(code): reject a bool cutoff_index in a summarization event
mdrxy Aug 24, 2026
cf8df10
test(code): pin the hook round limit and interrupt propagation
mdrxy Aug 24, 2026
3b9d92e
fix(code): pass empty json body in offload cancel request
mdrxy Aug 24, 2026
ba2c8e9
Merge branch 'main' into mdrxy/code/offload-seeded-compaction-no-hitl
mdrxy Aug 24, 2026
7e82ce1
Merge branch 'main' into mdrxy/code/offload-seeded-compaction-no-hitl
mdrxy Aug 24, 2026
d3666df
Merge branch 'main' into mdrxy/code/offload-seeded-compaction-no-hitl
mdrxy Aug 24, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 58 additions & 26 deletions libs/code/THREAT_MODEL.md

Large diffs are not rendered by default.

9 changes: 0 additions & 9 deletions libs/code/deepagents_code/_cli_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,6 @@ class CLIContextSchema:

turn_id: str | None = None

offload_tool_call_id: str | None = None

hooks_snapshot_id: str | None = None

hooks_server_events: list[str] = field(default_factory=list)
Expand Down Expand Up @@ -139,13 +137,6 @@ class CLIContext(TypedDict, total=False):
turn_id: str | None
"""Current user-turn ID for binding trusted interactive responses."""

offload_tool_call_id: str | None
"""The sole tool-call ID authorized during a server-driven `/offload` run.

This is set by the client, not graph state, so model-generated calls cannot
grant themselves permission to execute during the hidden compaction turn.
"""

hooks_snapshot_id: str | None
"""Canonical Hooks v2 configuration hash for this session.

Expand Down
58 changes: 57 additions & 1 deletion libs/code/deepagents_code/_testing_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,17 @@
from langchain_core.callbacks import CallbackManagerForLLMRun


DCA_TEST_OFFLOAD_GATE_ENV = "DCA_TEST_OFFLOAD_GATE_DIR"
"""Env var pointing at a directory used to gate summary generation.

When set, a summary request writes `<dir>/entered` and then polls for
`<dir>/release` before replying. File-based so the test process can hold the
server's compaction model call open without sharing Python state across the
server subprocess boundary. Only summary prompts are gated; ordinary turns pass
through, which is what lets a test launch a concurrent run *while* `/offload`
is blocked here.
"""

# Prompt markers that drive `ToolCallingIntegrationChatModel`. Each marker is the
# full token (including the trailing `=`); the file path follows on the same line,
# e.g. `DCA_TEST_WRITE_FILE=/tmp/out.txt`. These are the single source of truth
Expand Down Expand Up @@ -94,6 +105,7 @@ def _generate(
if (text := self._stringify_message(message)).strip()
)
if self._looks_like_summary_request(prompt):
self._wait_at_summary_gate()
content = "integration summary"
else:
excerpt = " ".join(prompt.split()[-18:])
Expand All @@ -103,14 +115,58 @@ def _generate(
content = "integration reply"

return ChatResult(
generations=[ChatGeneration(message=AIMessage(content=content))]
generations=[
ChatGeneration(
message=AIMessage(
content=content,
usage_metadata={
"input_tokens": 100,
"output_tokens": 20,
"total_tokens": 120,
},
)
)
]
)

@property
def _llm_type(self) -> str:
"""LangChain model type identifier."""
return "deterministic-integration"

@staticmethod
def _wait_at_summary_gate() -> None:
"""Hold the summary call open until the test releases it.

No-op unless `DCA_TEST_OFFLOAD_GATE_DIR` names a directory. When set,
write `<dir>/entered` (the test's signal that the offload operation is
mid-summary) and then poll for `<dir>/release`. Every summary request
rewrites the marker, so the test reads it as "a summary is in flight"
rather than "the first summary started". Bounded so a crashed test
cannot wedge the server subprocess indefinitely.

Raises:
TimeoutError: If the gate is not released within 120 seconds.
"""
import os
import time
from pathlib import Path

gate_dir = os.environ.get(DCA_TEST_OFFLOAD_GATE_ENV)
if not gate_dir:
return
gate = Path(gate_dir)
(gate / "entered").write_text("1")
deadline = time.monotonic() + 120
while not (gate / "release").exists():
if time.monotonic() > deadline:
msg = (
"Offload test gate was never released; refusing to block "
"the server summary call forever."
)
raise TimeoutError(msg)
time.sleep(0.05)

@staticmethod
def _stringify_message(message: BaseMessage) -> str:
"""Flatten message content into plain text for deterministic responses.
Expand Down
20 changes: 17 additions & 3 deletions libs/code/deepagents_code/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,11 @@
_artifacts_root,
_offload_fallback_root,
)
from deepagents_code.offload_middleware import _create_cli_compaction_middleware
from deepagents_code.offload_middleware import (
OffloadOperation,
_create_cli_compaction_middleware,
attach_offload_operation,
)
from deepagents_code.plugins.adapters.skills_middleware import PluginSkillsMiddleware
from deepagents_code.project_utils import ProjectContext, get_server_project_context
from deepagents_code.reliable_rubric import ReliableRubricMiddleware
Expand All @@ -116,6 +120,7 @@

logger = logging.getLogger(__name__)


_MEMORY_READONLY_SYSTEM_PROMPT = (
"<agent_memory>\n"
"{agent_memory}\n\n"
Expand Down Expand Up @@ -2943,7 +2948,7 @@ def _subagent_cli_middleware(
trusted_root, narrow_allow_list = auto_mode_config
# An explicit argument wins; otherwise the env var / `config.toml`
# preference is read here, where agent construction already runs off the
# blockbuster-guarded server loop (see `server_graph._make_graph`).
# blockbuster-guarded server loop (see `server_graph._make_graphs`).
classifier_model = (
auto_classifier_model
if auto_classifier_model is not None
Expand Down Expand Up @@ -2973,7 +2978,16 @@ def _subagent_cli_middleware(
from deepagents_code.hooks.server_middleware import ServerHooksMiddleware

hooks_cwd = Path(effective_cwd) if effective_cwd is not None else Path.cwd()
agent_middleware.append(ServerHooksMiddleware(cwd=hooks_cwd, mcp_tools=mcp_tools))
server_hooks_middleware = ServerHooksMiddleware(cwd=hooks_cwd, mcp_tools=mcp_tools)
agent_middleware.append(server_hooks_middleware)

# Publish the server operation on the backend shared with `server_graph`.
# The custom HTTP route owns checkpoint access and persistence, while this
# object retains the exact compaction and hook instances used by the agent.
attach_offload_operation(
composite_backend,
OffloadOperation(compaction_middleware, server_hooks_middleware),
)

if fs_tools is not None:
# `fs_tools` is an explicit allowlist here (`--allow-fs-tools all` and an
Expand Down
Loading