[integration] big-agents#4791
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Important Review skippedToo many files! This PR contains 2255 files, which is 2105 over the limit of 150. To get a review, narrow the scope: Upgrade to a paid plan to raise the limit. ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: ⛔ Files ignored due to path filters (268)
📒 Files selected for processing (2255)
You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
|
There was a problem hiding this comment.
Actionable comments posted: 10
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 76c33a7d-feff-4e5f-acc0-962498f74cfc
📒 Files selected for processing (70)
sdks/python/agenta/__init__.pysdks/python/agenta/sdk/agents/__init__.pysdks/python/agenta/sdk/agents/adapters/__init__.pysdks/python/agenta/sdk/agents/adapters/_runner_config.pysdks/python/agenta/sdk/agents/adapters/agenta_builtins.pysdks/python/agenta/sdk/agents/adapters/harnesses.pysdks/python/agenta/sdk/agents/adapters/in_process.pysdks/python/agenta/sdk/agents/adapters/local.pysdks/python/agenta/sdk/agents/adapters/sandbox_agent.pysdks/python/agenta/sdk/agents/adapters/vercel/__init__.pysdks/python/agenta/sdk/agents/adapters/vercel/messages.pysdks/python/agenta/sdk/agents/adapters/vercel/routing.pysdks/python/agenta/sdk/agents/adapters/vercel/sse.pysdks/python/agenta/sdk/agents/adapters/vercel/stream.pysdks/python/agenta/sdk/agents/dtos.pysdks/python/agenta/sdk/agents/errors.pysdks/python/agenta/sdk/agents/interfaces.pysdks/python/agenta/sdk/agents/mcp/__init__.pysdks/python/agenta/sdk/agents/mcp/errors.pysdks/python/agenta/sdk/agents/mcp/interfaces.pysdks/python/agenta/sdk/agents/mcp/models.pysdks/python/agenta/sdk/agents/mcp/parsing.pysdks/python/agenta/sdk/agents/mcp/resolver.pysdks/python/agenta/sdk/agents/mcp/wire.pysdks/python/agenta/sdk/agents/streaming.pysdks/python/agenta/sdk/agents/tools/__init__.pysdks/python/agenta/sdk/agents/tools/compat.pysdks/python/agenta/sdk/agents/tools/errors.pysdks/python/agenta/sdk/agents/tools/interfaces.pysdks/python/agenta/sdk/agents/tools/models.pysdks/python/agenta/sdk/agents/tools/parsing.pysdks/python/agenta/sdk/agents/tools/resolver.pysdks/python/agenta/sdk/agents/tools/wire.pysdks/python/agenta/sdk/agents/ui_messages.pysdks/python/agenta/sdk/agents/utils/__init__.pysdks/python/agenta/sdk/agents/utils/ts_runner.pysdks/python/agenta/sdk/agents/utils/wire.pysdks/python/agenta/sdk/decorators/routing.pysdks/python/agenta/sdk/engines/running/interfaces.pysdks/python/agenta/sdk/engines/running/utils.pysdks/python/agenta/sdk/middlewares/running/normalizer.pysdks/python/agenta/sdk/models/workflows.pysdks/python/agenta/sdk/utils/types.pysdks/python/agenta/tests/agents/test_streaming.pysdks/python/oss/tests/pytest/integration/agents/__init__.pysdks/python/oss/tests/pytest/integration/agents/test_transport_roundtrip.pysdks/python/oss/tests/pytest/unit/agents/__init__.pysdks/python/oss/tests/pytest/unit/agents/conftest.pysdks/python/oss/tests/pytest/unit/agents/golden/run_request.claude.jsonsdks/python/oss/tests/pytest/unit/agents/golden/run_request.pi.jsonsdks/python/oss/tests/pytest/unit/agents/golden/run_result.error.jsonsdks/python/oss/tests/pytest/unit/agents/golden/run_result.ok.jsonsdks/python/oss/tests/pytest/unit/agents/mcp/__init__.pysdks/python/oss/tests/pytest/unit/agents/mcp/test_resolver.pysdks/python/oss/tests/pytest/unit/agents/test_dtos_agent_config.pysdks/python/oss/tests/pytest/unit/agents/test_dtos_capabilities_events.pysdks/python/oss/tests/pytest/unit/agents/test_dtos_content_blocks.pysdks/python/oss/tests/pytest/unit/agents/test_dtos_harness_configs.pysdks/python/oss/tests/pytest/unit/agents/test_environment_lifecycle.pysdks/python/oss/tests/pytest/unit/agents/test_harness_adapters.pysdks/python/oss/tests/pytest/unit/agents/test_runner_adapter_config.pysdks/python/oss/tests/pytest/unit/agents/test_ui_messages.pysdks/python/oss/tests/pytest/unit/agents/test_wire_contract.pysdks/python/oss/tests/pytest/unit/agents/tools/__init__.pysdks/python/oss/tests/pytest/unit/agents/tools/test_models.pysdks/python/oss/tests/pytest/unit/agents/tools/test_parsing.pysdks/python/oss/tests/pytest/unit/agents/tools/test_resolver.pysdks/python/oss/tests/pytest/unit/test_normalizer_passthrough.pysdks/python/oss/tests/pytest/utils/test_messages_endpoint.pysdks/python/oss/tests/pytest/utils/test_routing.py
| NOTE on packaging: the Node runner is NOT part of this Python wheel (``pip install agenta`` | ||
| stays pure Python; the wheel contains zero ``.ts``/``.js``). How a standalone Pi user obtains | ||
| the runner -- an ``npx`` npm package, a local checkout, or a Docker sidecar over HTTP -- is an | ||
| open distribution decision; see ``docs/design/agent-workflows/typescript-structure/``. Do NOT | ||
| silently bundle a JS runner into the wheel. |
There was a problem hiding this comment.
Align LocalBackend wording with the stated packaging contract.
Line 9-13 says the wheel must not bundle a JS runner, but Line 30 and the NotImplementedError messages still say “bundled JS”. This contradiction will confuse integrators.
Suggested wording fix
-class LocalBackend(Backend):
- """Run Pi (bundled JS) or Claude (``claude-agent-sdk``) on this machine."""
+class LocalBackend(Backend):
+ """Run Pi (external Node runner) or Claude (``claude-agent-sdk``) on this machine."""
...
raise NotImplementedError(
- "LocalBackend is not implemented yet (Phase 3: Pi via bundled JS, "
+ "LocalBackend is not implemented yet (Phase 3: Pi via external Node runner, "
"Phase 4: Claude via claude-agent-sdk)."
)
...
raise NotImplementedError(
- "LocalBackend is not implemented yet (Phase 3: Pi via bundled JS, "
+ "LocalBackend is not implemented yet (Phase 3: Pi via external Node runner, "
"Phase 4: Claude via claude-agent-sdk)."
)Also applies to: 30-38, 50-53
| def __init__( | ||
| self, | ||
| *, | ||
| sandbox: str = "local", | ||
| url: Optional[str] = None, | ||
| command: Optional[Sequence[str]] = None, | ||
| cwd: Optional[str] = None, | ||
| timeout: float = float(os.getenv("AGENTA_AGENT_RUNNER_TIMEOUT_SECONDS", "180")), | ||
| ) -> None: | ||
| self._sandbox = sandbox | ||
| self._url = url |
There was a problem hiding this comment.
Validate sandbox at construction time.
Line 129 currently accepts any string; invalid values get sent over the wire and fail late. Restrict this to supported values (local, daytona) and raise a configuration error early.
Suggested validation
from ..dtos import (
@@
)
+from ..errors import AgentRunnerConfigurationError
@@
def __init__(
self,
*,
sandbox: str = "local",
@@
timeout: float = float(os.getenv("AGENTA_AGENT_RUNNER_TIMEOUT_SECONDS", "180")),
) -> None:
+ allowed_sandboxes = {"local", "daytona"}
+ if sandbox not in allowed_sandboxes:
+ raise AgentRunnerConfigurationError(
+ f"Unsupported sandbox '{sandbox}'. Expected one of: {sorted(allowed_sandboxes)}."
+ )
self._sandbox = sandbox
self._url = url| from agenta.sdk.agents.tools.models import MissingSecretPolicy | ||
|
|
||
| from .errors import MissingMCPSecretError | ||
| from .interfaces import MCPSecretProvider | ||
| from .models import MCPServerConfig, ResolvedMCPServer | ||
|
|
||
|
|
||
| class MCPResolver: | ||
| def __init__( | ||
| self, | ||
| *, | ||
| secret_provider: MCPSecretProvider, | ||
| missing_secret_policy: MissingSecretPolicy = MissingSecretPolicy.ERROR, | ||
| ) -> None: |
There was a problem hiding this comment.
Breaks declared layer direction by importing tools model into MCP.
MCPResolver currently depends on agenta.sdk.agents.tools.models.MissingSecretPolicy, but this cohort declares tools as depending on MCP, not the other way around. This reverse edge can create import-order fragility and circular dependency risk as the stack evolves. Move MissingSecretPolicy to a neutral/shared module (or MCP/shared contract module) and import it from both subsystems.
Possible direction
- from agenta.sdk.agents.tools.models import MissingSecretPolicy
+ from agenta.sdk.agents.shared.missing_secret_policy import MissingSecretPolicy(then define/move the enum in that shared module and update tools imports accordingly)
| out = stdout.decode("utf-8", "replace") | ||
| err = stderr.decode("utf-8", "replace") | ||
| if not out.strip(): | ||
| raise RuntimeError( | ||
| f"Agent runner returned no output. exit={proc.returncode} stderr={err[-2000:]}" | ||
| ) | ||
| try: | ||
| return json.loads(out) | ||
| except json.JSONDecodeError as exc: |
There was a problem hiding this comment.
Treat non-zero subprocess exit as transport failure even with parseable JSON.
Line 74 returns parsed JSON without checking proc.returncode; a crashed runner can look successful if it emitted partial/legacy JSON before exiting non-zero.
Suggested fix
@@ async def deliver_subprocess(...):
out = stdout.decode("utf-8", "replace")
err = stderr.decode("utf-8", "replace")
+ if proc.returncode not in (0, None):
+ raise RuntimeError(
+ "Agent runner exited non-zero. "
+ f"exit={proc.returncode} stderr={err[-2000:]} stdout={out[:500]}"
+ )
if not out.strip():
raise RuntimeError(
f"Agent runner returned no output. exit={proc.returncode} stderr={err[-2000:]}"
)📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| out = stdout.decode("utf-8", "replace") | |
| err = stderr.decode("utf-8", "replace") | |
| if not out.strip(): | |
| raise RuntimeError( | |
| f"Agent runner returned no output. exit={proc.returncode} stderr={err[-2000:]}" | |
| ) | |
| try: | |
| return json.loads(out) | |
| except json.JSONDecodeError as exc: | |
| out = stdout.decode("utf-8", "replace") | |
| err = stderr.decode("utf-8", "replace") | |
| if proc.returncode not in (0, None): | |
| raise RuntimeError( | |
| "Agent runner exited non-zero. " | |
| f"exit={proc.returncode} stderr={err[-2000:]} stdout={out[:500]}" | |
| ) | |
| if not out.strip(): | |
| raise RuntimeError( | |
| f"Agent runner returned no output. exit={proc.returncode} stderr={err[-2000:]}" | |
| ) | |
| try: | |
| return json.loads(out) | |
| except json.JSONDecodeError as exc: |
…ation-big-agents-a9b5 # Conflicts: # docs/docs/self-host/reference/01-configuration.mdx # hosting/docker-compose/ee/env.ee.dev.example # hosting/docker-compose/ee/env.ee.gh.example # hosting/docker-compose/oss/env.oss.dev.example # hosting/docker-compose/oss/env.oss.gh.example # hosting/kubernetes/helm/templates/_helpers.tpl
…r the merged runtime_provided precondition The narrowed runner env comment's `-}}` trimmed the newline before AGENTA_API_URL, breaking env: into invalid YAML. The RUN-SEC-1 orchestration test predates 729d90a's requirement that a local runtime_provided run has CLAUDE_CONFIG_DIR set; align it with the sibling test that already does this.
…ing agent A card on the overview and quick-start pages gives a one-click prompt to hand a coding agent for a guided self-host setup. Claude-Session: https://claude.ai/code/session_01XhENr63WL9npkKrJGnzDc1
…e docker-socket note to troubleshooting The card prompt now references the docs and the skill so a bare agent can act; the docker-group permission detail moves from prerequisites to a troubleshooting entry. Claude-Session: https://claude.ai/code/session_01XhENr63WL9npkKrJGnzDc1
[fix] Align demo agent defaults
docs(self-host): copy-paste self-host prompt card
The runner's shared token was optional and default-off: unset meant the auth check was skipped entirely, and the variable was declared in no compose file, no Helm template, and no .env example. Its only authentication was therefore both disabled by default and undiscoverable — an operator had to read the sidecar's TypeScript to learn the control existed. That is not a defensible posture for this service. The /run body carries a run's plaintext provider keys, and /kill tears down sandboxes. An unauthenticated runner is not a valid deployment, so it is no longer possible to configure one. The token now behaves exactly like AGENTA_AUTH_KEY: - The runner refuses to start without it (assertRunnerToken, at the HTTP boundary). isAuthorized fails closed rather than falling open. - The Helm chart refuses to render without agenta.runnerToken, and mounts it into both the runner and Services. agentRunner.auth.tokenSecretRef still overrides the source for operators using an external vault. - Compose passes it to the runner container (:? so an unset value fails the stack loudly), and all four env examples ship AGENTA_RUNNER_TOKEN=replace-me uncommented, alongside AGENTA_AUTH_KEY. - The SDK sender raises when it is unset instead of sending an un-tokened request the runner would answer with an opaque 401. The chart's narrow-env guard is updated, not weakened: the token is a single secretKeyRef, so the runner's environment stays free of platform secrets — a local harness shares that container and can read /proc. Docs: the configuration reference and the Kubernetes deploy guide list it as a required secret and document the startup error. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ge missed
`ede25c6cda` made AGENTA_RUNNER_TOKEN required but left several surfaces
inconsistent with that. Every one of them is fixed here.
Compose: the commit added the strict `:?` declaration without removing the
pre-existing permissive `${AGENTA_RUNNER_TOKEN:-}` one, so all seven compose
files carried a duplicate mapping key and no OSS or EE stack would parse. The
old line is gone. The `services` container also now declares the token with the
same `:?` guard: it is the caller and it only ever received the value by
incidental inheritance from `env_file`, so a custom env file that omitted the
token booted fine and failed at first agent-run instead of at `up`.
Railway: `configure.sh` never set the token on any service, so every deploy
crash-looped the runner with no way to supply it. It now follows the same shape
as its sibling secrets: a default, the placeholder warning, and the value set on
both `services` and `runner`.
Helm: `assertRunnerToken` only rejects `undefined`, so it accepted the literal
`replace-me` that `values.yaml` ships. A stock `helm install` therefore deployed
a runner that booted with a publicly-known token. `validateRequiredSecrets` now
rejects the placeholder for authKey, cryptKey, and runnerToken alike, and exempts
runnerToken when `agentRunner.auth.tokenSecretRef` supplies it instead. The four
kubernetes values examples list `runnerToken` alongside the other two.
Tests: the acceptance and integration suites still encoded the default-off gate
and 401'd against the now-mandatory auth, so twelve tests failed. They are moved
onto the new contract using the pattern the commit already applied to the unit
suite; the gate itself is unchanged.
Docs: `01-configuration.mdx` contradicted itself, correctly calling the token
required and then stating a few paragraphs later that leaving it unset disables
the check. The `isAuthorized` doc-comment and the sidecar-trust design docs
described the same stale default-off behavior.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
[fix] Land the v7 audit findings that need no product decision
The published OSS/EE gh compose shipped no store, so runner mount signing returned 503 and agent file writes were silently lost. Bundles SeaweedFS (matching the dev stack) and sets working store env defaults. Claude-Session: https://claude.ai/code/session_01XhENr63WL9npkKrJGnzDc1
Move services/runner/images/service back to services/runner/docker so the runner matches the api/web/services convention (<svc>/docker/Dockerfile.gh) that platform CI builds against; the images/service rename made platform build.sh silently skip the runner and OSS preview deploys failed with no oss/agenta-runner image in ECR. Compose, Railway, and docs references updated; the Railway build script keeps images/service as a fallback for branches still carrying the renamed layout. Sandbox images stay under images/sandbox/. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
fix(hosting): bundle SeaweedFS store in gh compose
fix(hosting): bind Postgres and the dashboard to loopback by default
…ompose variants PR #5313 added the bundled store and flipped the gh env default to http://seaweedfs:8333, but only added the service to docker-compose.gh.yml. The gh.local (build-from-source) and gh.ssl variants reuse the same gh env file, so they inherited the endpoint default with no such service on the network. Add the identical seaweedfs service, api depends_on, and seaweed-data volume to oss gh.local, oss gh.ssl, and ee gh.local, plus a multi-replica JWT note in the gh env examples. Claude-Session: https://claude.ai/code/session_01XhENr63WL9npkKrJGnzDc1
fix(hosting): bundle SeaweedFS store in gh.local and gh.ssl variants
…s and store
${POSTGRES_PORT:-127.0.0.1:5432} put the loopback inside the default, so
any port override (POSTGRES_PORT=5433) silently reverted to a public
bind. Use the traefik-dashboard shape (127.0.0.1:${VAR:-port}) so the
variable carries only the port and loopback survives overrides; same fix
for the new AGENTA_STORE_PORT, whose own comment promises loopback-only.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…r path The local-run env table lumped AGENTA_RUNNER_TOKEN in with AGENTA_RUNNER_DAYTONA_API_KEY under one "when they are set" qualifier, but the runner token is mandatory (the runner refuses to start without it), so only the Daytona key is conditional. Reword accordingly. Also fix the licensing pointer in build_snapshot.py: the referenced services/runner/images/service/README.md no longer exists; the licensing section lives at services/runner/docker/README.md.
…osted deployments On a gh self-host deployment using Daytona cloud sandboxes, geesefs runs inside the sandbox and reaches the store over the internet. The bundled SeaweedFS is bound to loopback with traefik.enable=false, so the signed store endpoint is unreachable from Daytona and the runner skips the mount silently, dropping every file the agent writes. Add an opt-in traefik router on the seaweedfs service (off by default) that publishes the S3 endpoint on its own subdomain, gated by AGENTA_STORE_TRAEFIK_ENABLE and AGENTA_STORE_DOMAIN. The API's existing AGENTA_STORE_ENDPOINT_URL then carries the public endpoint into the signed mount credentials. Host-only routing keeps the request path intact, which SeaweedFS S3 SigV4 requires. Document the recipe on the Daytona self-host page and in the gh env examples. Claude-Session: https://claude.ai/code/session_01Hyn9365BLPXDmNZShrQkmH
docs(self-host): correct runner-token wording and a stale image-folder path
…d no output" Commit 42075a5 moved Pi session transcripts to <cwd>/agents/sessions/pi via PI_CODING_AGENT_SESSION_DIR, but findSwallowedPiError was still passed the Pi agent dir, which no longer holds the transcript. The helper found nothing, so every provider failure (bad key, quota, model 404) fell back to the generic "The agent produced no output." message. findSwallowedPiError now takes the run cwd and derives the transcript location from piSessionWorkspaceDir, the same shared helper configurePiSessionWorkspace uses to point Pi at it, so the reader and the writer can never disagree again. Claude-Session: https://claude.ai/code/session_01Hyn9365BLPXDmNZShrQkmH
…posure fix(hosting): expose the object store for Daytona sandboxes on self-hosted deployments
The published runner image runs as user node (uid 1000) but never created /pi-agent (the configured PI_CODING_AGENT_DIR), so installing Pi's permission-enforcing extension failed with EACCES. The install swallowed that error and returned void, so the runner continued with NO enforcement: a deny/ask policy silently ran every built-in tool. Three parts: - Image: create /pi-agent owned by node in Dockerfile.gh before USER node. - Routing: managed/no-key local Pi runs install the extension into a per-run temp dir the runtime user owns, so the install no longer depends on the configured agent dir being writable. - Fail closed: installPiExtensionLocal / uploadPiExtensionToSandbox now report success; session setup throws a named error when the policy could gate a Pi built-in and the extension did not install, surfaced as an error frame. Claude-Session: https://claude.ai/code/session_01Hyn9365BLPXDmNZShrQkmH
fix(runner): surface Pi provider errors instead of "The agent produced no output"
fix(runner): fail closed when the Pi permission extension cannot install
Context
big-agentsis the integration branch for the agent-workflows feature. Every agent PR targetsbig-agents(directly, or by stacking on one that does). The plan is to review and merge each sub-PR intobig-agents, then mergebig-agentsintomainas a single unit.This PR is a draft tracker. It stays open until all the open sub-PRs below are merged into
big-agents. The branch started from an empty commit, so the diff fills in as sub-PRs land.Integrated PRs
Each box gets checked when that PR is merged into
big-agents. Indented items stack on the item above them.SDK and service
Runner
big-agents(the relay-bug fix, the CI job, and a superset of its tests already landed via feat(agent): runner engines, HTTP server, tracing, and docker image #4778 + chore(agent): make sandbox-agent runner first-class #4786)Frontend
Hosting
Sandbox-agent deployment
Docs
Branch-only (no PR yet)
These design-doc branches are stacked on
big-agentsbut have no PR. Open one if you want them reviewed separately, otherwise they fold in with the docs.docs/agent-model-config-and-provider-authdocs/agent-skills-configdocs/agent-code-tool-sandboxdocs/agent-harness-capabilitiesNotes
big-agents(feat(agent): runner engines, HTTP server, tracing, and docker image #4778 + chore(agent): make sandbox-agent runner first-class #4786 already carry its tests, CI job, and relay-bug fix; itsversion.tswas stale["pi","rivet"]).big-agentsas chore(railway): add sandbox-agent preview deployment #4802 / chore(kubernetes): deploy sandbox-agent sidecar #4803 / ci(agent): build and test sandbox-agent images #4804.