Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
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
2 changes: 2 additions & 0 deletions src/bernstein/adapters/aichat.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ def spawn(
task_scope: str = "medium",
budget_multiplier: float = 1.0,
system_addendum: str = "",
multimodal_context: Any | None = None,
) -> SpawnResult:
"""Launch an AIChat session.

Expand All @@ -68,6 +69,7 @@ def spawn(
RuntimeError: If the ``aichat`` binary is missing from PATH
or cannot be executed.
"""
self.refuse_multimodal_if_needed(multimodal_context)
log_path = workdir / ".sdd" / "runtime" / f"{session_id}.log"
log_path.parent.mkdir(parents=True, exist_ok=True)

Expand Down
2 changes: 2 additions & 0 deletions src/bernstein/adapters/aider.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,9 @@ def spawn(
task_scope: str = "medium",
budget_multiplier: float = 1.0,
system_addendum: str = "",
multimodal_context: Any | None = None,
) -> SpawnResult:
self.refuse_multimodal_if_needed(multimodal_context)
self.enforce_network_policy()
log_path = workdir / ".sdd" / "runtime" / f"{session_id}.log"
log_path.parent.mkdir(parents=True, exist_ok=True)
Expand Down
2 changes: 2 additions & 0 deletions src/bernstein/adapters/amp.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,9 @@ def spawn(
task_scope: str = "medium",
budget_multiplier: float = 1.0,
system_addendum: str = "",
multimodal_context: Any | None = None,
) -> SpawnResult:
self.refuse_multimodal_if_needed(multimodal_context)
self.enforce_network_policy()
log_path = workdir / ".sdd" / "runtime" / f"{session_id}.log"
log_path.parent.mkdir(parents=True, exist_ok=True)
Expand Down
2 changes: 2 additions & 0 deletions src/bernstein/adapters/auggie.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ def spawn(
task_scope: str = "medium",
budget_multiplier: float = 1.0,
system_addendum: str = "",
multimodal_context: Any | None = None,
) -> SpawnResult:
"""Launch an Auggie process with the given prompt.

Expand All @@ -60,6 +61,7 @@ def spawn(
RuntimeError: The ``auggie`` binary is missing from PATH or
cannot be executed due to permissions.
"""
self.refuse_multimodal_if_needed(multimodal_context)
self.enforce_network_policy()
log_path = workdir / ".sdd" / "runtime" / f"{session_id}.log"
log_path.parent.mkdir(parents=True, exist_ok=True)
Expand Down
2 changes: 2 additions & 0 deletions src/bernstein/adapters/autohand.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ def spawn(
task_scope: str = "medium",
budget_multiplier: float = 1.0,
system_addendum: str = "",
multimodal_context: Any | None = None,
) -> SpawnResult:
"""Spawn an Autohand Code session.

Expand All @@ -55,6 +56,7 @@ def spawn(
RuntimeError: If the ``autohand`` binary cannot be found or
executed.
"""
self.refuse_multimodal_if_needed(multimodal_context)
log_path = workdir / ".sdd" / "runtime" / f"{session_id}.log"
log_path.parent.mkdir(parents=True, exist_ok=True)

Expand Down
33 changes: 33 additions & 0 deletions src/bernstein/adapters/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -467,6 +467,39 @@ def enforce_network_policy(self) -> None:
for host, port in self.external_endpoints:
policy.check(host, port, source=f"adapter:{self.name()}")

def refuse_multimodal_if_needed(self, multimodal_context: Any | None) -> None:
"""Reject attachments for adapters that do not support multimodal input.

Args:
multimodal_context: Optional multimodal context from the worker
launch path.

Raises:
CapabilityRefusal: When attachments are present and this adapter is
not registered as multimodal-capable.
"""
if multimodal_context is None:
return

inputs = getattr(multimodal_context, "inputs", ()) or ()
attachments: list[str] = []
for input_item in inputs:
content_path = getattr(input_item, "content_path", None)
if content_path is not None:
attachments.append(str(content_path))
continue
description = getattr(input_item, "description", "") or "<inline attachment>"
attachments.append(str(description))
if not attachments:
return

from bernstein.core.agents.multimodal_attestation import refuse_when_incapable

refuse_when_incapable(
adapter_name=self._derive_session_namespace(),
attachments=tuple(attachments),
)

def set_resource_limits(self, limits: ResourceLimits | None) -> None:
"""Configure OS-level resource limits applied to spawned child processes.

Expand Down
4 changes: 3 additions & 1 deletion src/bernstein/adapters/caching_adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ def spawn(
task_scope: str = "medium",
budget_multiplier: float = 1.0,
system_addendum: str = "",
multimodal_context: Any | None = None,
) -> SpawnResult:
"""Spawn agent with caching: process prompt, check response cache, then delegate.

Expand Down Expand Up @@ -165,7 +166,7 @@ def spawn(
)
cached_entry, similarity = self._response_cache.lookup_entry(key)

if cached_entry and cached_entry.verified:
if multimodal_context is None and cached_entry and cached_entry.verified:
logger.info(
"Response cache hit (similarity=%.3f) for session %s -- skipping spawn",
similarity,
Expand Down Expand Up @@ -193,6 +194,7 @@ def spawn(
task_scope=task_scope,
budget_multiplier=budget_multiplier,
system_addendum=system_addendum,
multimodal_context=multimodal_context,
)

def name(self) -> str:
Expand Down
2 changes: 2 additions & 0 deletions src/bernstein/adapters/charm.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ def spawn(
task_scope: str = "medium",
budget_multiplier: float = 1.0,
system_addendum: str = "",
multimodal_context: Any | None = None,
) -> SpawnResult:
"""Spawn a Crush session.

Expand All @@ -55,6 +56,7 @@ def spawn(
RuntimeError: If the ``crush`` binary cannot be found or
executed.
"""
self.refuse_multimodal_if_needed(multimodal_context)
log_path = workdir / ".sdd" / "runtime" / f"{session_id}.log"
log_path.parent.mkdir(parents=True, exist_ok=True)

Expand Down
2 changes: 2 additions & 0 deletions src/bernstein/adapters/cline.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ def spawn(
task_scope: str = "medium",
budget_multiplier: float = 1.0,
system_addendum: str = "",
multimodal_context: Any | None = None,
) -> SpawnResult:
"""Spawn a Cline CLI session.

Expand All @@ -57,6 +58,7 @@ def spawn(
Raises:
RuntimeError: If ``cline`` is not installed or is not executable.
"""
self.refuse_multimodal_if_needed(multimodal_context)
log_path = workdir / ".sdd" / "runtime" / f"{session_id}.log"
log_path.parent.mkdir(parents=True, exist_ok=True)

Expand Down
2 changes: 2 additions & 0 deletions src/bernstein/adapters/clm.py
Original file line number Diff line number Diff line change
Expand Up @@ -379,7 +379,9 @@ def spawn(
task_scope: str = "medium",
budget_multiplier: float = 1.0,
system_addendum: str = "",
multimodal_context: Any | None = None,
) -> SpawnResult:
self.refuse_multimodal_if_needed(multimodal_context)
log_path = workdir / ".sdd" / "runtime" / f"{session_id}.log"
log_path.parent.mkdir(parents=True, exist_ok=True)

Expand Down
2 changes: 2 additions & 0 deletions src/bernstein/adapters/cloudflare_agents.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ def spawn(
task_scope: str = "medium",
budget_multiplier: float = 1.0,
system_addendum: str = "",
multimodal_context: Any | None = None,
) -> SpawnResult:
"""Launch a Cloudflare Agents worker via ``npx wrangler dev``.

Expand All @@ -76,6 +77,7 @@ def spawn(
RuntimeError: If ``npx`` is not found or permission is denied.
NetworkPolicyDenied: When the active --allow-network policy denies api.cloudflare.com.
"""
self.refuse_multimodal_if_needed(multimodal_context)
self.enforce_network_policy()
log_path = workdir / ".sdd" / "runtime" / f"{session_id}.log"
log_path.parent.mkdir(parents=True, exist_ok=True)
Expand Down
2 changes: 2 additions & 0 deletions src/bernstein/adapters/codebuff.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ def spawn(
task_scope: str = "medium",
budget_multiplier: float = 1.0,
system_addendum: str = "",
multimodal_context: Any | None = None,
) -> SpawnResult:
"""Launch a Codebuff session.

Expand All @@ -57,6 +58,7 @@ def spawn(
RuntimeError: If the ``codebuff`` binary is missing or not
executable.
"""
self.refuse_multimodal_if_needed(multimodal_context)
log_path = workdir / ".sdd" / "runtime" / f"{session_id}.log"
log_path.parent.mkdir(parents=True, exist_ok=True)

Expand Down
2 changes: 2 additions & 0 deletions src/bernstein/adapters/codex.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,9 @@ def spawn(
task_scope: str = "medium",
budget_multiplier: float = 1.0,
system_addendum: str = "",
multimodal_context: Any | None = None,
) -> SpawnResult:
self.refuse_multimodal_if_needed(multimodal_context)
self.enforce_network_policy()
log_path = workdir / ".sdd" / "runtime" / f"{session_id}.log"
log_path.parent.mkdir(parents=True, exist_ok=True)
Expand Down
2 changes: 2 additions & 0 deletions src/bernstein/adapters/cody.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ def spawn(
task_scope: str = "medium",
budget_multiplier: float = 1.0,
system_addendum: str = "",
multimodal_context: Any | None = None,
) -> SpawnResult:
"""Launch a Cody agent process.

Expand All @@ -79,6 +80,7 @@ def spawn(
Raises:
RuntimeError: If ``cody`` is not found in PATH.
"""
self.refuse_multimodal_if_needed(multimodal_context)
self.enforce_network_policy()
log_path = workdir / ".sdd" / "runtime" / f"{session_id}.log"
log_path.parent.mkdir(parents=True, exist_ok=True)
Expand Down
2 changes: 2 additions & 0 deletions src/bernstein/adapters/composio.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ def spawn(
task_scope: str = "medium",
budget_multiplier: float = 1.0,
system_addendum: str = "",
multimodal_context: Any | None = None,
) -> SpawnResult:
"""Launch a Composio Agent Orchestrator session.

Expand All @@ -68,6 +69,7 @@ def spawn(
RuntimeError: If the ``ao`` binary is missing from PATH or
cannot be executed.
"""
self.refuse_multimodal_if_needed(multimodal_context)
log_path = workdir / ".sdd" / "runtime" / f"{session_id}.log"
log_path.parent.mkdir(parents=True, exist_ok=True)

Expand Down
2 changes: 2 additions & 0 deletions src/bernstein/adapters/conformance.py
Original file line number Diff line number Diff line change
Expand Up @@ -575,6 +575,7 @@ def spawn(
mcp_config: dict[str, Any] | None = None,
timeout_seconds: int = 1800,
task_scope: str = "medium",
multimodal_context: Any | None = None,
) -> SpawnResult:
"""Launch {cli_name} with the given prompt.

Expand All @@ -589,6 +590,7 @@ def spawn(
Returns:
SpawnResult with PID and log path.
"""
self.refuse_multimodal_if_needed(multimodal_context)
log_path = workdir / f"{adapter_id}-{{session_id}}.log"
cmd = ["{cli_command}", "--prompt", prompt]
proc = subprocess.Popen(
Expand Down
2 changes: 2 additions & 0 deletions src/bernstein/adapters/continue_dev.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ def spawn(
task_scope: str = "medium",
budget_multiplier: float = 1.0,
system_addendum: str = "",
multimodal_context: Any | None = None,
) -> SpawnResult:
"""Launch a Continue.dev agent process.

Expand All @@ -70,6 +71,7 @@ def spawn(
Raises:
RuntimeError: If the ``cn`` binary is not found in PATH.
"""
self.refuse_multimodal_if_needed(multimodal_context)
self.enforce_network_policy()
log_path = workdir / ".sdd" / "runtime" / f"{session_id}.log"
log_path.parent.mkdir(parents=True, exist_ok=True)
Expand Down
2 changes: 2 additions & 0 deletions src/bernstein/adapters/copilot.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ def spawn(
task_scope: str = "medium",
budget_multiplier: float = 1.0,
system_addendum: str = "",
multimodal_context: Any | None = None,
) -> SpawnResult:
"""Launch a GitHub Copilot CLI session.

Expand All @@ -62,6 +63,7 @@ def spawn(
RuntimeError: If the ``copilot`` binary is missing from PATH
or cannot be executed.
"""
self.refuse_multimodal_if_needed(multimodal_context)
log_path = workdir / ".sdd" / "runtime" / f"{session_id}.log"
log_path.parent.mkdir(parents=True, exist_ok=True)

Expand Down
2 changes: 2 additions & 0 deletions src/bernstein/adapters/cursor.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,9 @@ def spawn(
task_scope: str = "medium",
budget_multiplier: float = 1.0,
system_addendum: str = "",
multimodal_context: Any | None = None,
) -> SpawnResult:
self.refuse_multimodal_if_needed(multimodal_context)
self.enforce_network_policy()
log_path = workdir / ".sdd" / "runtime" / f"{session_id}.log"
log_path.parent.mkdir(parents=True, exist_ok=True)
Expand Down
2 changes: 2 additions & 0 deletions src/bernstein/adapters/devin_terminal.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ def spawn(
task_scope: str = "medium",
budget_multiplier: float = 1.0,
system_addendum: str = "",
multimodal_context: Any | None = None,
) -> SpawnResult:
"""Launch a one-shot Devin for Terminal session.

Expand Down Expand Up @@ -116,6 +117,7 @@ def spawn(
RuntimeError: The ``devin`` binary is missing from PATH or
the OS denies execution.
"""
self.refuse_multimodal_if_needed(multimodal_context)
self.enforce_network_policy()
log_path = workdir / ".sdd" / "runtime" / f"{session_id}.log"
log_path.parent.mkdir(parents=True, exist_ok=True)
Expand Down
2 changes: 2 additions & 0 deletions src/bernstein/adapters/droid.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ def spawn(
task_scope: str = "medium",
budget_multiplier: float = 1.0,
system_addendum: str = "",
multimodal_context: Any | None = None,
) -> SpawnResult:
"""Launch a Droid CLI session.

Expand All @@ -57,6 +58,7 @@ def spawn(
RuntimeError: If the Droid CLI is not installed or not
executable on the configured PATH.
"""
self.refuse_multimodal_if_needed(multimodal_context)
log_path = workdir / ".sdd" / "runtime" / f"{session_id}.log"
log_path.parent.mkdir(parents=True, exist_ok=True)

Expand Down
2 changes: 2 additions & 0 deletions src/bernstein/adapters/forge.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ def spawn(
task_scope: str = "medium",
budget_multiplier: float = 1.0,
system_addendum: str = "",
multimodal_context: Any | None = None,
) -> SpawnResult:
"""Launch a Forge CLI process for the given prompt.

Expand All @@ -56,6 +57,7 @@ def spawn(
RuntimeError: The ``forge`` binary is missing from PATH or the
current user lacks permission to execute it.
"""
self.refuse_multimodal_if_needed(multimodal_context)
log_path = workdir / ".sdd" / "runtime" / f"{session_id}.log"
log_path.parent.mkdir(parents=True, exist_ok=True)

Expand Down
2 changes: 2 additions & 0 deletions src/bernstein/adapters/generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,9 @@ def spawn(
task_scope: str = "medium",
budget_multiplier: float = 1.0,
system_addendum: str = "",
multimodal_context: Any | None = None,
) -> SpawnResult:
self.refuse_multimodal_if_needed(multimodal_context)
log_path = workdir / ".sdd" / "runtime" / f"{session_id}.log"
log_path.parent.mkdir(parents=True, exist_ok=True)

Expand Down
2 changes: 2 additions & 0 deletions src/bernstein/adapters/goose.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ def spawn(
task_scope: str = "medium",
budget_multiplier: float = 1.0,
system_addendum: str = "",
multimodal_context: Any | None = None,
) -> SpawnResult:
"""Launch a Goose agent process.

Expand All @@ -80,6 +81,7 @@ def spawn(
Raises:
RuntimeError: If the Goose binary is not found.
"""
self.refuse_multimodal_if_needed(multimodal_context)
self.enforce_network_policy()
log_path = workdir / ".sdd" / "runtime" / f"{session_id}.log"
log_path.parent.mkdir(parents=True, exist_ok=True)
Expand Down
2 changes: 2 additions & 0 deletions src/bernstein/adapters/gptme.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ def spawn(
task_scope: str = "medium",
budget_multiplier: float = 1.0,
system_addendum: str = "",
multimodal_context: Any | None = None,
) -> SpawnResult:
"""Launch a gptme CLI session.

Expand All @@ -76,6 +77,7 @@ def spawn(
RuntimeError: If the ``gptme`` binary is missing from PATH or
cannot be executed.
"""
self.refuse_multimodal_if_needed(multimodal_context)
log_path = workdir / ".sdd" / "runtime" / f"{session_id}.log"
log_path.parent.mkdir(parents=True, exist_ok=True)

Expand Down
Loading
Loading