Skip to content

feat(agent): agent-provider class — drive Claude over ACP on your own subscription (#813)#866

Open
softmarshmallow wants to merge 3 commits into
mainfrom
feat/agent-provider-acp-consumer
Open

feat(agent): agent-provider class — drive Claude over ACP on your own subscription (#813)#866
softmarshmallow wants to merge 3 commits into
mainfrom
feat/agent-provider-acp-consumer

Conversation

@softmarshmallow

@softmarshmallow softmarshmallow commented Jun 18, 2026

Copy link
Copy Markdown
Member

What

Adds the agent-provider class (#813): a second provider class where an external agent owns the loop. Grida acts as an ACP consumer, spawns the ACP-team bridge (@agentclientprotocol/claude-agent-acp), and drives Claude on the user's own Pro/Max subscription — zero API key, zero signup.

It is deliberately distinct from the model-provider kinds (BYOK / endpoint): no ModelFactory is ever called. The runtime branches before provider resolution and streams the external agent's output (ProviderChunk → AI-SDK chunks).

Why

BYOK already covers "bring your own key." This reaches the subscription crowd that BYOK can't — the lowest-friction on-ramp. It is a spike to inform a keep/drop decision, not a settled feature.

What's in it

Works + verified:

  • Keyless run on the user's own Claude subscription
  • Native streaming (ACP agent_message_chunk deltas → text-delta)
  • Multi-turn continuity (session/resume), with fallback to a fresh session when a stale id can't be resumed
  • Model picker (Opus 4.8 1M / Sonnet 4.6 / Haiku 4.5), grouped by provider
  • Thinking content, tool-call UI, persistence
  • Cancel (abort → ACP session/cancel) and stop-reason → finish-reason mapping

Test infrastructure: a deterministic in-memory fake ACP agent (testing/fake-acp-agent.ts) + a JTBD suite (agent-provider/jtbd.test.ts) that asserts user-visible outcomes with no real Claude and no npx; the gated run.live.test.ts proves the real bridge.

Docs: decision/RFD docs/wg/ai/agent/acp-provider.md, a README section, and a SECURITY.md (GRIDA-SEC-004) amendment.

Reviewer notes

  • ⚠️ This is a SPIKE — the keep/drop decision is OPEN. Two gates sit above the code: (1) Anthropic ToS — driving a subscription-logged-in agent from a third party is not formally blessed (Codex is the blessed analogue); (2) the permanent per-feature fork tax — every host feature needs an agent-provider branch alongside the model-provider one. See acp-provider.md.
  • Packaged-desktop sandbox is UNVERIFIED. The npx bridge running under the packaged srt/Seatbelt + proxy wrap has not been reproduced (only dev). This is the technical go/no-go.
  • Signed-out default caveat: DEFAULT_MODEL_ID points at Claude Code, so a signed-out user's first new chat hits auth_required until the zero-config auto-detect lands. Intentional per the product ask — flag if you'd rather gate it on login detection now.
  • Layering: the agent-provider is a clean parallel provider class (branches once before resolution), not special-cased through the runtime; ProviderChunk is the neutral seam and runtime/agent-provider-run.ts is the adapter.
  • GRIDA-SEC-004 reviewed: sandbox/policy.ts adds the Anthropic egress allowlist; claude.ts strips ANTHROPIC_API_KEY (subscription billing only).
  • Deferred (tracked): queue-drain (needs runtime-level test harness or a live run to verify), mode/approval UX routing, usage stamping, @-file mentions, slash commands, Grida-as-MCP-server (canvas tools), multimodal, Codex.

Tests

pnpm --filter @grida/agent test530 passed, 16 skipped (gated live), 3 todo. Typecheck clean, oxlint clean.

Summary by CodeRabbit

  • New Features
    • Added Claude Code as a selectable desktop model option, with external-agent execution and persisted session continuity across turns.
    • Improved the model picker by grouping options by provider (plus Claude Code synthetic options) and updating the default selection.
  • Documentation
    • Updated security guidance for bounded external-agent egress.
    • Added/expanded ACP “agent-provider class” decision docs and related experimental README content.
  • Security / Bug Fixes
    • Expanded the sandbox network allowlist for required vendor endpoints using an explicit allowlist (no wildcard expansion).
  • Tests
    • Added contract, integration (LIVE gated), and fake-agent coverage for external-agent streaming, cancellation, and session resume.

…e user's own subscription (#813)

A second provider class where an EXTERNAL agent owns the loop: Grida acts as an ACP consumer, spawns the ACP-team bridge (@agentclientprotocol/claude-agent-acp), and drives Claude on the user's own Pro/Max subscription — zero API key. Distinct from the model-provider kinds (BYOK/endpoint): no ModelFactory is called; the runtime branches before resolution and streams from the external agent (ProviderChunk -> AI-SDK chunks).

Working + verified via deterministic + gated-live tests: keyless run, native streaming, multi-turn continuity (session/resume), model picker (Opus 1M / Sonnet / Haiku, Claude-default), thinking content, tool-call UI, persistence, cancel, resume-fallback on stale id, stop-reason mapping. Adds a deterministic in-memory fake ACP agent (testing/fake-acp-agent.ts) + JTBD suite (agent-provider/jtbd.test.ts) so the user-outcome contract is testable without a real Claude; gated run.live.test.ts proves the real bridge.

Spike: the keep/drop decision (Anthropic ToS + the permanent per-feature fork tax) is OPEN — see docs/wg/ai/agent/acp-provider.md. GRIDA-SEC-004 reviewed (sandbox/policy.ts allowlist, SECURITY.md).
@vercel

vercel Bot commented Jun 18, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
grida Ready Ready Preview, Comment Jun 19, 2026 7:07am
6 Skipped Deployments
Project Deployment Actions Updated (UTC)
code Ignored Ignored Jun 19, 2026 7:07am
docs Ignored Ignored Preview Jun 19, 2026 7:07am
legacy Ignored Ignored Jun 19, 2026 7:07am
backgrounds Skipped Skipped Jun 19, 2026 7:07am
blog Skipped Skipped Jun 19, 2026 7:07am
viewer Skipped Skipped Jun 19, 2026 7:07am

Request Review

@coderabbitai

coderabbitai Bot commented Jun 18, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c683ee80-5b25-4e66-adaa-52b03545b9ae

📥 Commits

Reviewing files that changed from the base of the PR and between bda5e8f and 66cc64d.

📒 Files selected for processing (9)
  • packages/grida-ai-agent/src/agent-provider/claude.ts
  • packages/grida-ai-agent/src/agent-provider/config.ts
  • packages/grida-ai-agent/src/agent-provider/jtbd.test.ts
  • packages/grida-ai-agent/src/agent/index.ts
  • packages/grida-ai-agent/src/agent/prompts.ts
  • packages/grida-ai-agent/src/prompts.ts
  • packages/grida-ai-agent/src/session/compactor.ts
  • packages/grida-ai-agent/src/session/titler.ts
  • packages/grida-ai-agent/src/testing/fake-acp-agent.ts
✅ Files skipped from review due to trivial changes (1)
  • packages/grida-ai-agent/src/agent-provider/config.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/grida-ai-agent/src/agent-provider/jtbd.test.ts
  • packages/grida-ai-agent/src/testing/fake-acp-agent.ts
  • packages/grida-ai-agent/src/agent-provider/claude.ts

Walkthrough

Adds an "agent-provider" execution class to grida-ai-agent, enabling external ACP agents (Claude Code) to own the inference loop. Implements the Claude stdio bridge, a turn runner that translates ACP events into AI-SDK chunks, AgentRuntime integration, sandbox egress allowlisting, model picker UI updates, a centralized prompt registry refactoring, and a comprehensive test suite plus RFD documentation.

Changes

Agent-provider class (Claude Code ACP)

Layer / File(s) Summary
Agent-provider public contracts and provider wiring
packages/grida-ai-agent/src/agent-provider/types.ts, packages/grida-ai-agent/src/providers/index.ts
Defines AgentProviderId, ProviderChunk union, AgentProviderSession, AGENT_PROVIDER_MODELS catalog with synthetic ids, isAgentProviderModel/agentProviderModel helpers, and OpenProviderOptions. Extends ResolvedProvider.kind to include "agent-provider" and adds makeAgentProvider constructor with model_factory guard.
Centralized prompt registry and agent refactoring
packages/grida-ai-agent/src/prompts.ts, packages/grida-ai-agent/src/agent/prompts.ts, packages/grida-ai-agent/src/agent/index.ts, packages/grida-ai-agent/src/session/compactor.ts, packages/grida-ai-agent/src/session/titler.ts
Creates prompts.ts registry exporting agent_core, agent_svg_skill, command_capability, acp_system, titler_system, and compactor_system templates. Refactors agent/prompts.ts, agent/index.ts, and session modules to import from the registry, eliminating inline prompt duplication.
Claude ACP bridge and configuration
packages/grida-ai-agent/src/agent-provider/claude.ts, packages/grida-ai-agent/src/agent-provider/config.ts, packages/grida-ai-agent/src/agent-provider/index.ts
Spawns claude-agent-acp stdio bridge, filters stdout to JSON-RPC lines, translates ACP session/update into ProviderChunks, manages initialize/resume/new lifecycle with fallback, and exposes BridgeTransport/BridgeConnect for injection. Defines static acp_config with client capabilities, MCP servers, and system-prompt append mode. Dispatches openProvider by provider id.
Turn runner and session persistence
packages/grida-ai-agent/src/runtime/agent-provider-run.ts, packages/grida-ai-agent/src/session/store.ts, packages/grida-ai-agent/src/runtime/run-input.ts
runAgentProviderTurn wires AbortSignal to cancel, lowers ProviderChunks into AgentUIMessageChunks with lazy text/reasoning streams and tool lifecycle. SessionsStore.setAgentProviderSessionId persists external session ids. parseRunBody accepts synthetic agent-provider model ids; extractLastUserText added.
AgentRuntime agent-provider path
packages/grida-ai-agent/src/runtime/index.ts
Detects agent-provider models via isAgentProviderModel, builds provider with makeAgentProvider, skips session titling, derives agent_prompt from extractLastUserText, and adds early-exit pump branch that resumes external sessions, calls runAgentProviderTurn, persists providerSessionId, and bypasses the compaction/model-factory pipeline.
Sandbox network policy expansion and security documentation
packages/grida-ai-agent/src/sandbox/policy.ts, SECURITY.md, packages/grida-ai-agent/src/__public-api__.test.ts
Adds AGENT_PROVIDER_NETWORK_HOSTS covering Anthropic/Claude domains into ALWAYS_ALLOWED_HOSTS; documents explicit vendor domain enumeration under GRIDA-SEC-004; adds contract assertion for api.anthropic.com.
Model picker UI: Claude Code groups and default model
editor/scaffolds/desktop/shared/model-picker.tsx
Changes DEFAULT_MODEL_ID to claude-code/opus-4.8-1m, renders three grouped sections (Claude Code synthetic options, provider-grouped hosted catalog, endpoint models), and extends isKnownId to accept Claude Code synthetic ids.
Fake ACP agent, test helpers, and tests
packages/grida-ai-agent/src/testing/fake-acp-agent.ts, packages/grida-ai-agent/src/testing/sse.ts, packages/grida-ai-agent/src/agent-provider/jtbd.test.ts, packages/grida-ai-agent/src/agent-provider/run.live.test.ts, packages/grida-ai-agent/src/agent-provider/consume.bin.ts
createFakeBridge provides deterministic in-memory ACP agent with call observation. assistantTextFromSse extracted as shared helper. JTBD tests cover streaming, continuity, stale-resume fallback, cancel, and stop-reason mapping. LIVE tests cover keyless run, session continuity, and model selection. consume.bin.ts CLI harness streams prompts with timing.
ACP provider decision documentation and README
docs/wg/ai/agent/acp-provider.md, docs/wg/ai/agent/acp-provider-codex.md, docs/wg/ai/agent/index.md, packages/grida-ai-agent/README.md
Adds acp-provider.md RFD covering loop-inversion decision, forever-layer costs, reversible path, and open questions. Updates Codex profile with cross-link; adds index entry; extends README with agent-provider class documentation.

Sequence Diagram(s)

sequenceDiagram
  participant Client as Client (POST /agent/run)
  participant AgentRuntime
  participant runAgentProviderTurn
  participant openClaudeSession
  participant ClaudeBridge as Claude ACP Bridge (stdio)
  participant SSE as SSE Response

  Client->>AgentRuntime: run({ model_id: "claude-code/opus-4.8-1m", messages })
  AgentRuntime->>AgentRuntime: isAgentProviderModel → makeAgentProvider
  AgentRuntime->>AgentRuntime: extractLastUserText(messages)
  AgentRuntime->>runAgentProviderTurn: prompt, cwd, resume_session_id, model, signal, emit
  runAgentProviderTurn->>openClaudeSession: openProvider("claude", opts)
  openClaudeSession->>ClaudeBridge: spawn npx claude-agent-acp
  openClaudeSession->>ClaudeBridge: initialize + newSession/resumeSession
  openClaudeSession-->>runAgentProviderTurn: AgentProviderSession
  runAgentProviderTurn->>ClaudeBridge: session.prompt(text, chunkSink)
  runAgentProviderTurn->>Client: emit start, start-step (SSE)
  loop streaming ProviderChunks
    ClaudeBridge-->>runAgentProviderTurn: ProviderChunk (text/reasoning/tool/error)
    runAgentProviderTurn->>Client: emit text-delta, reasoning-delta, tool events (SSE)
  end
  ClaudeBridge-->>runAgentProviderTurn: TurnResult { stopReason, providerSessionId }
  runAgentProviderTurn->>Client: emit finish-step, finish (SSE)
  runAgentProviderTurn-->>AgentRuntime: TurnResult
  AgentRuntime->>AgentRuntime: setAgentProviderSessionId (persist external session id)
  AgentRuntime->>Client: close SSE
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related issues

Possibly related PRs

  • gridaco/grida#800: Both PRs modify the agent sandbox network allowlist in packages/grida-ai-agent/src/sandbox/policy.ts, expanding ALWAYS_ALLOWED_HOSTS and allowed_domains under GRIDA-SEC-004 for network-policy enforcement.
  • gridaco/grida#811: This PR updates docs/wg/ai/agent/acp-provider-codex.md with a lead-in cross-link to the new ACP provider decision page, directly building on the Codex ACP provider profile introduced in PR #811.

Suggested labels

enhancement, ai, documentation

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 51.61% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title clearly and specifically describes the main change: introducing an agent-provider class that enables users to drive Claude over ACP using their own subscription, with explicit issue reference (#813).
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/agent-provider-acp-consumer

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 and usage tips.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6ffead327e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +622 to +626
if (isAgentProviderModel(req.model_id)) {
// Agent-provider class (issue #813): an external agent owns its own
// loop. No BYOK/endpoint resolution, no model factory — the runtime
// streams from the agent-provider consumer in startTurn.
provider = makeAgentProvider(AGENT_PROVIDER_MODELS[req.model_id].id);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Handle queued Claude Code sends

When the selected model is Claude Code, this special-case only runs for direct /agent/run calls. If the user submits while a Claude Code turn is busy, the desktop queue posts /sessions/:id/queue; the scheduler later calls drainTurn, which still resolves the persisted provider_id ("claude") through resolveProvider instead of recreating an agent-provider, so the drain throws after the queued row has already been dequeued and no turn starts. Mirror the agent-provider resolution in the drain path and pass the dequeued user text as the provider prompt.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Acknowledged, and intentionally deferred in this spike PR. The fix is clear, but its prompt-derivation half is behaviorally verifiable only via the gated live test (the deterministic fake injects at runAgentProviderTurn, not the runtime/host level). Tracked in docs/wg/ai/agent/acp-provider.plan.md (Queue drain), to land with a runtime-level test harness or a live run.

Comment on lines +203 to +208
const allow =
req.options.find((o) => o.kind === "allow_always") ??
req.options.find((o) => o.kind === "allow_once") ??
req.options[0];
if (!allow) return { outcome: { outcome: "cancelled" } };
return { outcome: { outcome: "selected", optionId: allow.optionId } };

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Do not auto-approve external agent tools

For any ACP permission request from Claude Code, this handler selects allow_always/allow_once without consulting the session mode or the supervised approval flow. In the default accept-edits posture, a prompt-injected external agent can therefore run write/shell/file tools without the user approval that Grida's built-in agent requires; route these requests through the host approval UI or fail closed instead of automatically granting them.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Acknowledged — this is the deferred mode/approval-UX item (tracked in acp-provider.plan.md). Auto-approve is the documented PoC posture; the real fix routes ACP session/request_permission to the host supervised Allow/Deny gate and maps the Auto / Accept-edits picker to setSessionMode. Fail-closed would make the spike non-functional, so the PoC behavior stays pending that design.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 9

🧹 Nitpick comments (1)
packages/grida-ai-agent/src/__public-api__.test.ts (1)

236-238: ⚡ Quick win

Broaden the public contract assertion for external-agent egress hosts.

Line [238] only pins one domain, so regressions on other required hosts can pass tests and fail runtime egress.

Suggested test hardening
-      expect(policy.network.allowed_domains).toContain("api.anthropic.com");
+      expect(policy.network.allowed_domains).toEqual(
+        expect.arrayContaining([
+          "api.anthropic.com",
+          "anthropic.com",
+          "*.anthropic.com",
+          "claude.ai",
+          "*.claude.ai",
+        ])
+      );
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/grida-ai-agent/src/__public-api__.test.ts` around lines 236 - 238,
The test assertion for the external agent egress policy only validates a single
domain (api.anthropic.com) in policy.network.allowed_domains, which is
insufficient to catch regressions. Expand this test to verify that ALL required
external agent egress hosts are present in the allowed_domains list, not just
one. Identify all necessary vendor backend hosts that the external agent needs
to reach and add assertions to ensure each one is included in the policy, so
that missing domains are caught at test time rather than failing at runtime.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@editor/scaffolds/desktop/shared/model-picker.tsx`:
- Around line 46-56: The DEFAULT_MODEL_ID constant is currently set to
"claude-code/opus-4.8-1m" which requires external Claude authentication, causing
first-run to fail for signed-out users. Change the DEFAULT_MODEL_ID value to use
TIER_MODEL_IDS.pro instead, which references the hosted Sonnet 4.6 model that
does not require external authentication and allows new chat to succeed without
auth.
- Around line 67-76: The AGENT_PROVIDER_IDS set only includes the current model
ids from AGENT_PROVIDER_OPTIONS but excludes legacy claude-code model ids that
the runtime still supports for backward compatibility. Modify the
AGENT_PROVIDER_IDS set creation to also include legacy id variants, or create a
normalization function that can map legacy claude-code ids to their current
equivalents. This will ensure that sessions stored with legacy ids can be
properly validated and reseeded in the model picker state path.

In `@packages/grida-ai-agent/src/agent-provider/claude.ts`:
- Line 17: The CI spell-check pipeline is failing because the variable name
`ndJsonStream` at lines 17 and 63 is being flagged as a misspelling. Add an
allowlist or ignore entry for the token `ndJsonStream` in your spell-check
configuration file (typically a file like .spellcheckrc, .spelling,
pyproject.toml, or similar spell-checker config) to mark this as an intentional
term that should not trigger spelling errors and allow the CI job to pass.
- Around line 198-209: The requestPermission method in the claude.ts file is
currently auto-approving all tool execution requests by selecting the first
available permission option, which bypasses the authorization gate. To implement
fail-closed permission handling, refactor the requestPermission method to deny
permission by default and require explicit user or host approval before allowing
any tool to execute. Instead of automatically selecting from the provided
options, return an outcome with "cancelled" status or implement a mechanism that
routes permission requests to the host's permission UX for explicit consent,
ensuring that tools cannot be executed without explicit authorization.
- Around line 189-248: The transport spawned by spawnBridge at the beginning of
the function is not disposed if initialize, newSession, resumeSession, or
startFresh throw an error. Wrap all the initialization logic starting from the
ClientSideConnection instantiation through the sessionId assignment (including
the canResume check, the conditional session resume/start logic, and startFresh
invocation) in a try-catch block that ensures the transport is disposed before
re-throwing the error, so the bridge process is not left running if any of these
operations fail.

In `@packages/grida-ai-agent/src/agent-provider/consume.bin.ts`:
- Around line 41-56: The session.dispose() call is currently only executed on
the success path after session.prompt() completes. If session.prompt() throws an
error, the session resource will not be cleaned up before the process exits.
Wrap the block containing the session.prompt() call and the subsequent logging
and metrics calculation within a try-finally block, moving the session.dispose()
call into the finally block to ensure it always executes regardless of whether
session.prompt() succeeds or throws an error.

In `@packages/grida-ai-agent/src/agent-provider/run.live.test.ts`:
- Around line 77-89: The beforeEach hook deletes process.env.ANTHROPIC_API_KEY
but the afterEach hook does not restore it, causing process-wide state pollution
that affects subsequent tests. Store the original value of
process.env.ANTHROPIC_API_KEY before deleting it in the beforeEach hook, then
restore the original value in the afterEach hook after the cleanup operations to
prevent test interference.

In `@packages/grida-ai-agent/src/agent-provider/types.ts`:
- Around line 93-97: The isAgentProviderModel function uses the `in` operator to
check if modelId exists in AGENT_PROVIDER_MODELS, which checks the entire
prototype chain including inherited properties like __proto__ and toString. This
allows invalid model IDs to pass validation and later cause runtime errors when
indexing the object. Replace the `in` check with
Object.prototype.hasOwnProperty.call(AGENT_PROVIDER_MODELS, modelId) or
Object.hasOwn(AGENT_PROVIDER_MODELS, modelId) to only validate against own
properties of the allowlist object.

In `@packages/grida-ai-agent/src/runtime/run-input.ts`:
- Around line 107-108: The isAgentProviderModel function in
packages/grida-ai-agent/src/agent-provider/types.ts uses the `in` operator to
check for model IDs, which checks both own and inherited properties and allows
inherited properties like "toString" to bypass the guard. Replace the `in`
operator check with an own-property check using hasOwnProperty or
Object.prototype.hasOwnProperty.call to ensure only explicitly defined model IDs
pass the guard and prevent invalid provider access.

---

Nitpick comments:
In `@packages/grida-ai-agent/src/__public-api__.test.ts`:
- Around line 236-238: The test assertion for the external agent egress policy
only validates a single domain (api.anthropic.com) in
policy.network.allowed_domains, which is insufficient to catch regressions.
Expand this test to verify that ALL required external agent egress hosts are
present in the allowed_domains list, not just one. Identify all necessary vendor
backend hosts that the external agent needs to reach and add assertions to
ensure each one is included in the policy, so that missing domains are caught at
test time rather than failing at runtime.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: a9ac459d-bd1b-4e4a-a07f-85b8ff5061b4

📥 Commits

Reviewing files that changed from the base of the PR and between d389f0c and 6ffead3.

📒 Files selected for processing (23)
  • SECURITY.md
  • docs/wg/ai/agent/acp-provider-codex.md
  • docs/wg/ai/agent/acp-provider.md
  • docs/wg/ai/agent/index.md
  • editor/scaffolds/desktop/shared/model-picker.tsx
  • packages/grida-ai-agent/README.md
  • packages/grida-ai-agent/src/__public-api__.test.ts
  • packages/grida-ai-agent/src/agent-provider/claude.ts
  • packages/grida-ai-agent/src/agent-provider/consume.bin.ts
  • packages/grida-ai-agent/src/agent-provider/index.ts
  • packages/grida-ai-agent/src/agent-provider/jtbd.test.ts
  • packages/grida-ai-agent/src/agent-provider/run.live.test.ts
  • packages/grida-ai-agent/src/agent-provider/types.ts
  • packages/grida-ai-agent/src/providers/endpoints.live.test.ts
  • packages/grida-ai-agent/src/providers/index.ts
  • packages/grida-ai-agent/src/runtime/agent-provider-run.ts
  • packages/grida-ai-agent/src/runtime/index.ts
  • packages/grida-ai-agent/src/runtime/run-input.ts
  • packages/grida-ai-agent/src/runtime/runtime.live.test.ts
  • packages/grida-ai-agent/src/sandbox/policy.ts
  • packages/grida-ai-agent/src/session/store.ts
  • packages/grida-ai-agent/src/testing/fake-acp-agent.ts
  • packages/grida-ai-agent/src/testing/sse.ts

Comment thread editor/scaffolds/desktop/shared/model-picker.tsx
Comment thread editor/scaffolds/desktop/shared/model-picker.tsx Outdated
Comment thread packages/grida-ai-agent/src/agent-provider/claude.ts
Comment thread packages/grida-ai-agent/src/agent-provider/claude.ts
Comment thread packages/grida-ai-agent/src/agent-provider/claude.ts
Comment thread packages/grida-ai-agent/src/agent-provider/consume.bin.ts
Comment thread packages/grida-ai-agent/src/agent-provider/run.live.test.ts
Comment thread packages/grida-ai-agent/src/agent-provider/types.ts
Comment thread packages/grida-ai-agent/src/runtime/run-input.ts
…port cleanup, test hygiene

- typos: allowlist the `ndJsonStream` identifier (CI typos check was failing on it)
- isAgentProviderModel: use Object.hasOwn instead of `in` so prototype keys (toString/__proto__) can't pass the guard and reach AGENT_PROVIDER_MODELS[id]
- claude.ts: close the bridge transport if the ACP handshake throws (otherwise the spawned npx process leaks — dispose() is unreachable pre-return)
- consume.bin.ts: dispose the session in a finally block
- run.live.test.ts: save/restore ANTHROPIC_API_KEY so the env mutation can't bleed into other suites
- __public-api__.test.ts: assert the full agent-provider egress host set, not just api.anthropic.com
- model-picker: keep the legacy bare `claude-code` id recognized so older sessions re-seed instead of being clobbered
…tem prompt (#813)

Prompt registry: add src/prompts.ts as the single home for every authored prompt across the package's agent systems — model-provider core/svg/command-hint, agent-provider/ACP system, and the session titler/compactor subagents (moved out of agent/prompts.ts, agent/index.ts, session/*, agent-provider/config.ts). Tool-name-dependent prompts are dependency-free builders that take the tool-name bag as a parameter, so importing a prompt never drags in the tool modules; tool descriptions and the skill-index block stay own-contracted with their tool/mechanism.

ACP config dial-board: add agent-provider/config.ts — one place to change how Grida configures the external agent (bridge package, client capabilities, MCP servers, thinking, system-prompt mode). claude.ts reads from it.

System prompt: the agent-provider path now appends a managed system prompt (registry prompts.acp_system) onto Claude Code's preset via _meta.systemPrompt; locked by a JTBD test (the fake captures the session _meta). Verified: 531 unit tests, typecheck, oxlint clean; composeSystemPrompt output byte-identical after the move.
@softmarshmallow

Copy link
Copy Markdown
Member Author

Followup tracked in #871productionize the transport: drop the runtime npx (vendor + self-spawn the bridge with the app's own Node), resolve the user's claude via CLAUDE_CODE_EXECUTABLE (ship no Anthropic binary), and verify the packaged srt/Seatbelt sandbox. Contained to the spawnBridge/BridgeConnect seam — the ACP consumer here doesn't change. Deferred behind the agent-provider keep/drop decision.

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