mirror of
https://github.com/harivansh-afk/sandbox-agent.git
synced 2026-04-15 06:04:43 +00:00
Merge branch 'main' into fix-this-bug-https-github-com-rivet-dev-sandbox-ag
This commit is contained in:
commit
357fbaea5b
14 changed files with 53 additions and 70 deletions
|
|
@ -40,7 +40,7 @@ Universal schema guidance:
|
|||
- Never use synthetic data or mocked responses in tests.
|
||||
- Never manually write agent types; always use generated types in `resources/agent-schemas/`. If types are broken, fix the generated types.
|
||||
- The universal schema must provide consistent behavior across providers; avoid requiring frontend/client logic to special-case agents.
|
||||
- The UI must reflect every field in AgentCapabilities; keep it in sync with `docs/session-transcript-schema.mdx` and `agent_capabilities_for`.
|
||||
- The UI must reflect every field in AgentCapabilities (feature coverage); keep it in sync with `docs/session-transcript-schema.mdx` and `agent_capabilities_for`.
|
||||
- When parsing agent data, if something is unexpected or does not match the schema, bail out and surface the error rather than trying to continue with partial parsing.
|
||||
- When defining the universal schema, choose the option most compatible with native agent APIs, and add synthetics to fill gaps for other agents.
|
||||
- Use `docs/session-transcript-schema.mdx` as the source of truth for schema terminology and keep it updated alongside schema changes.
|
||||
|
|
|
|||
12
README.md
12
README.md
|
|
@ -216,18 +216,6 @@ sandbox-agent credentials extract-env --export
|
|||
|
||||
This prints environment variables for your OpenAI/Anthropic/etc API keys to test with Sandbox Agent SDK.
|
||||
|
||||
## Integrations
|
||||
|
||||
Works with your stack:
|
||||
|
||||
| Sandbox Providers | AI Platforms | Infrastructure | Storage |
|
||||
|---|---|---|---|
|
||||
| [Daytona](https://sandboxagent.dev/docs/deploy/daytona) | Anthropic | Docker | Postgres |
|
||||
| [E2B](https://sandboxagent.dev/docs/deploy/e2b) | OpenAI | Fly.io | ClickHouse |
|
||||
| [Vercel Sandboxes](https://sandboxagent.dev/docs/deploy) | [AI SDK](https://ai-sdk.dev) | AWS Nitro | [Rivet](https://rivet.dev) |
|
||||
|
||||
Want support for another agent or sandbox provider? [Open an issue](https://github.com/rivet-dev/sandbox-agent/issues/new) to request it.
|
||||
|
||||
## FAQ
|
||||
|
||||
<details>
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ icon: "comments"
|
|||
```ts
|
||||
const { agents } = await client.listAgents();
|
||||
|
||||
// Each agent has capabilities that determine what UI to show
|
||||
// Each agent exposes feature coverage via `capabilities` to determine what UI to show
|
||||
const claude = agents.find((a) => a.id === "claude");
|
||||
if (claude?.capabilities.permissions) {
|
||||
// Show permission approval UI
|
||||
|
|
|
|||
|
|
@ -1,10 +1 @@
|
|||
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="32" height="32" rx="6" fill="url(#bg_gradient)"/>
|
||||
<text x="16" y="22" text-anchor="middle" font-family="system-ui, -apple-system, sans-serif" font-size="16" font-weight="700" fill="white">SA</text>
|
||||
<defs>
|
||||
<linearGradient id="bg_gradient" x1="0" y1="0" x2="32" y2="32" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#16A34A"/>
|
||||
<stop offset="1" stop-color="#15803D"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
<svg width="128" height="128" fill="none" xmlns="http://www.w3.org/2000/svg"><rect x="1" y="1" width="126" height="126" rx="44" fill="#0F0F0F"/><rect x="18.25" y="18.25" width="91.5" height="91.5" rx="25.75" stroke="#F0F0F0" stroke-width="8.5"/><path fill-rule="evenodd" clip-rule="evenodd" d="M57.694 43.098c0-.622-.505-1.126-1.127-1.126h-8.444a5.114 5.114 0 0 0-5.112 5.111v33.824a5.114 5.114 0 0 0 5.112 5.112h8.444c.622 0 1.127-.505 1.127-1.127V43.098Zm24.424 27.869c-1.238-2.222-4.047-4.026-6.27-4.026H62.923c-.684 0-.93.555-.549 1.239l7.703 13.822c1.239 2.223 4.048 4.026 6.27 4.026h12.927c.683 0 .93-.555.548-1.239l-7.703-13.822Zm.538-18.718c0-5.672-4.605-10.277-10.277-10.277H63.31a1.21 1.21 0 0 0-1.209 1.209v18.137c0 .667.542 1.209 1.21 1.209h9.068c5.672 0 10.277-4.605 10.277-10.278Z" fill="#F0F0F0"/></svg>
|
||||
|
Before Width: | Height: | Size: 539 B After Width: | Height: | Size: 818 B |
|
|
@ -62,7 +62,7 @@ await client.createSession("demo-session", {
|
|||
await client.postMessage("demo-session", { message: "Hello" });
|
||||
```
|
||||
|
||||
List agents and pick a compatible one:
|
||||
List agents and inspect feature coverage (available on `capabilities`):
|
||||
|
||||
```ts
|
||||
const agents = await client.listAgents();
|
||||
|
|
@ -153,7 +153,7 @@ Parameters:
|
|||
|
||||
## Types
|
||||
|
||||
The SDK exports OpenAPI-derived types for events, items, and capabilities:
|
||||
The SDK exports OpenAPI-derived types for events, items, and feature coverage:
|
||||
|
||||
```ts
|
||||
import type { UniversalEvent, UniversalItem, AgentCapabilities } from "sandbox-agent";
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ The schema is defined in [OpenAPI format](https://github.com/rivet-dev/sandbox-a
|
|||
|
||||
## Coverage Matrix
|
||||
|
||||
This table shows which agent capabilities appear in the universal event stream. All agents retain their full native capabilities—this only reflects what's normalized into the schema.
|
||||
This table shows which agent feature coverage appears in the universal event stream. All agents retain their full native feature coverage—this only reflects what's normalized into the schema.
|
||||
|
||||
| Feature | Claude | Codex | OpenCode | Amp |
|
||||
|--------------------|:------:|:-----:|:------------:|:------------:|
|
||||
|
|
|
|||
|
|
@ -1676,14 +1676,14 @@
|
|||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* Capability Badges */
|
||||
.capability-badges {
|
||||
/* Feature Coverage Badges */
|
||||
.feature-coverage-badges {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.capability-badge {
|
||||
.feature-coverage-badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
|
|
@ -1693,17 +1693,17 @@
|
|||
font-weight: 500;
|
||||
}
|
||||
|
||||
.capability-badge.enabled {
|
||||
.feature-coverage-badge.enabled {
|
||||
background: rgba(48, 209, 88, 0.12);
|
||||
color: var(--success);
|
||||
}
|
||||
|
||||
.capability-badge.disabled {
|
||||
.feature-coverage-badge.disabled {
|
||||
background: rgba(255, 255, 255, 0.04);
|
||||
color: var(--muted-2);
|
||||
}
|
||||
|
||||
.capability-badge svg {
|
||||
.feature-coverage-badge svg {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ import {
|
|||
Terminal,
|
||||
Wrench
|
||||
} from "lucide-react";
|
||||
import type { AgentCapabilitiesView } from "../../types/agents";
|
||||
import type { FeatureCoverageView } from "../../types/agents";
|
||||
|
||||
const badges = [
|
||||
{ key: "planMode", label: "Plan", icon: GitBranch },
|
||||
|
|
@ -42,14 +42,14 @@ const badges = [
|
|||
|
||||
type BadgeItem = (typeof badges)[number];
|
||||
|
||||
const getEnabled = (capabilities: AgentCapabilitiesView, key: BadgeItem["key"]) =>
|
||||
Boolean((capabilities as Record<string, boolean | undefined>)[key]);
|
||||
const getEnabled = (featureCoverage: FeatureCoverageView, key: BadgeItem["key"]) =>
|
||||
Boolean((featureCoverage as Record<string, boolean | undefined>)[key]);
|
||||
|
||||
const CapabilityBadges = ({ capabilities }: { capabilities: AgentCapabilitiesView }) => {
|
||||
const FeatureCoverageBadges = ({ featureCoverage }: { featureCoverage: FeatureCoverageView }) => {
|
||||
return (
|
||||
<div className="capability-badges">
|
||||
<div className="feature-coverage-badges">
|
||||
{badges.map(({ key, label, icon: Icon }) => (
|
||||
<span key={key} className={`capability-badge ${getEnabled(capabilities, key) ? "enabled" : "disabled"}`}>
|
||||
<span key={key} className={`feature-coverage-badge ${getEnabled(featureCoverage, key) ? "enabled" : "disabled"}`}>
|
||||
<Icon size={12} />
|
||||
<span>{label}</span>
|
||||
</span>
|
||||
|
|
@ -58,4 +58,4 @@ const CapabilityBadges = ({ capabilities }: { capabilities: AgentCapabilitiesVie
|
|||
);
|
||||
};
|
||||
|
||||
export default CapabilityBadges;
|
||||
export default FeatureCoverageBadges;
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
import { Download, RefreshCw } from "lucide-react";
|
||||
import type { AgentInfo, AgentModeInfo } from "sandbox-agent";
|
||||
import CapabilityBadges from "../agents/CapabilityBadges";
|
||||
import { emptyCapabilities } from "../../types/agents";
|
||||
import FeatureCoverageBadges from "../agents/FeatureCoverageBadges";
|
||||
import { emptyFeatureCoverage } from "../../types/agents";
|
||||
|
||||
const AgentsTab = ({
|
||||
agents,
|
||||
|
|
@ -41,7 +41,7 @@ const AgentsTab = ({
|
|||
installed: false,
|
||||
version: undefined,
|
||||
path: undefined,
|
||||
capabilities: emptyCapabilities
|
||||
capabilities: emptyFeatureCoverage
|
||||
}))).map((agent) => (
|
||||
<div key={agent.id} className="card">
|
||||
<div className="card-header">
|
||||
|
|
@ -54,8 +54,11 @@ const AgentsTab = ({
|
|||
{agent.version ? `v${agent.version}` : "Version unknown"}
|
||||
{agent.path && <span className="mono muted" style={{ marginLeft: 8 }}>{agent.path}</span>}
|
||||
</div>
|
||||
<div className="card-meta" style={{ marginTop: 8 }}>
|
||||
Feature coverage
|
||||
</div>
|
||||
<div style={{ marginTop: 8 }}>
|
||||
<CapabilityBadges capabilities={agent.capabilities ?? emptyCapabilities} />
|
||||
<FeatureCoverageBadges featureCoverage={agent.capabilities ?? emptyFeatureCoverage} />
|
||||
</div>
|
||||
{modesByAgent[agent.id] && modesByAgent[agent.id].length > 0 && (
|
||||
<div className="card-meta" style={{ marginTop: 8 }}>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import type { AgentCapabilities } from "sandbox-agent";
|
||||
|
||||
export type AgentCapabilitiesView = AgentCapabilities & {
|
||||
export type FeatureCoverageView = AgentCapabilities & {
|
||||
toolResults?: boolean;
|
||||
textMessages?: boolean;
|
||||
images?: boolean;
|
||||
|
|
@ -16,7 +16,7 @@ export type AgentCapabilitiesView = AgentCapabilities & {
|
|||
itemStarted?: boolean;
|
||||
};
|
||||
|
||||
export const emptyCapabilities: AgentCapabilitiesView = {
|
||||
export const emptyFeatureCoverage: FeatureCoverageView = {
|
||||
planMode: false,
|
||||
permissions: false,
|
||||
questions: false,
|
||||
|
|
|
|||
|
|
@ -44,6 +44,9 @@ function UniversalAPIDiagram() {
|
|||
<feGaussianBlur stdDeviation="3" result="blur" />
|
||||
<feComposite in="SourceGraphic" in2="blur" operator="over" />
|
||||
</filter>
|
||||
<filter id="invert-white" colorInterpolationFilters="sRGB">
|
||||
<feColorMatrix type="matrix" values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0" />
|
||||
</filter>
|
||||
</defs>
|
||||
|
||||
{/* YOUR APP NODE */}
|
||||
|
|
@ -99,22 +102,20 @@ function UniversalAPIDiagram() {
|
|||
stroke={isActive ? p.color : '#333'}
|
||||
strokeWidth={isActive ? 2 : 1.5}
|
||||
/>
|
||||
<foreignObject x="0" y="8" width="110" height="28">
|
||||
<div className="flex justify-center" style={{ opacity: isActive ? 1 : 0.4 }}>
|
||||
{p.logo === 'openai' ? (
|
||||
<svg className="h-6 w-6" viewBox="0 0 24 24" fill="none">
|
||||
<path d="M22.2819 9.8211a5.9847 5.9847 0 0 0-.5157-4.9108 6.0462 6.0462 0 0 0-6.5098-2.9A6.0651 6.0651 0 0 0 4.9807 4.1818a5.9847 5.9847 0 0 0-3.9977 2.9 6.0462 6.0462 0 0 0 .7427 7.0966 5.98 5.98 0 0 0 .511 4.9107 6.051 6.051 0 0 0 6.5146 2.9001A5.9847 5.9847 0 0 0 13.2599 24a6.0557 6.0557 0 0 0 5.7718-4.2058 5.9894 5.9894 0 0 0 3.9977-2.9001 6.0557 6.0557 0 0 0-.7475-7.0729zm-9.022 12.6081a4.4755 4.4755 0 0 1-2.8764-1.0408l.1419-.0804 4.7783-2.7582a.7948.7948 0 0 0 .3927-.6813v-6.7369l2.02 1.1686a.071.071 0 0 1 .038.052v5.5826a4.504 4.504 0 0 1-4.4945 4.4944zm-9.6607-4.1254a4.4708 4.4708 0 0 1-.5346-3.0137l.142.0852 4.783 2.7582a.7712.7712 0 0 0 .7806 0l5.8428-3.3685v2.3324a.0804.0804 0 0 1-.0332.0615L9.74 19.9502a4.4992 4.4992 0 0 1-6.1408-1.6464zM2.3408 7.8956a4.485 4.485 0 0 1 2.3655-1.9728V11.6a.7664.7664 0 0 0 .3879.6765l5.8144 3.3543-2.0201 1.1685a.0757.0757 0 0 1-.071 0l-4.8303-2.7865A4.504 4.504 0 0 1 2.3408 7.872zm16.5963 3.8558L13.1038 8.364 15.1192 7.2a.0757.0757 0 0 1 .071 0l4.8303 2.7913a4.4944 4.4944 0 0 1-.6765 8.1042v-5.6772a.79.79 0 0 0-.407-.667zm2.0107-3.0231l-.142-.0852-4.7735-2.7818a.7759.7759 0 0 0-.7854 0L9.409 9.2297V6.8974a.0662.0662 0 0 1 .0284-.0615l4.8303-2.7866a4.4992 4.4992 0 0 1 6.6802 4.66zM8.3065 12.863l-2.02-1.1638a.0804.0804 0 0 1-.038-.0567V6.0742a4.4992 4.4992 0 0 1 7.3757-3.4537l-.142.0805L8.704 5.459a.7948.7948 0 0 0-.3927.6813zm1.0976-2.3654l2.602-1.4998 2.6069 1.4998v2.9994l-2.5974 1.4997-2.6067-1.4997Z" fill="#ffffff" />
|
||||
</svg>
|
||||
) : p.logo === 'opencode' ? (
|
||||
<svg className="h-6 w-auto" viewBox="0 0 32 40" fill="none">
|
||||
<path d="M24 32H8V16H24V32Z" fill="#4B4646"/>
|
||||
<path d="M24 8H8V32H24V8ZM32 40H0V0H32V40Z" fill="#F1ECEC"/>
|
||||
</svg>
|
||||
) : (
|
||||
<img src={p.logo} alt={p.label} className="h-6 w-6" style={{ filter: 'brightness(0) invert(1)' }} />
|
||||
)}
|
||||
</div>
|
||||
</foreignObject>
|
||||
<g opacity={isActive ? 1 : 0.4}>
|
||||
{p.logo === 'openai' ? (
|
||||
<svg x="43" y="10" width="24" height="24" viewBox="0 0 24 24" fill="none">
|
||||
<path d="M22.2819 9.8211a5.9847 5.9847 0 0 0-.5157-4.9108 6.0462 6.0462 0 0 0-6.5098-2.9A6.0651 6.0651 0 0 0 4.9807 4.1818a5.9847 5.9847 0 0 0-3.9977 2.9 6.0462 6.0462 0 0 0 .7427 7.0966 5.98 5.98 0 0 0 .511 4.9107 6.051 6.051 0 0 0 6.5146 2.9001A5.9847 5.9847 0 0 0 13.2599 24a6.0557 6.0557 0 0 0 5.7718-4.2058 5.9894 5.9894 0 0 0 3.9977-2.9001 6.0557 6.0557 0 0 0-.7475-7.0729zm-9.022 12.6081a4.4755 4.4755 0 0 1-2.8764-1.0408l.1419-.0804 4.7783-2.7582a.7948.7948 0 0 0 .3927-.6813v-6.7369l2.02 1.1686a.071.071 0 0 1 .038.052v5.5826a4.504 4.504 0 0 1-4.4945 4.4944zm-9.6607-4.1254a4.4708 4.4708 0 0 1-.5346-3.0137l.142.0852 4.783 2.7582a.7712.7712 0 0 0 .7806 0l5.8428-3.3685v2.3324a.0804.0804 0 0 1-.0332.0615L9.74 19.9502a4.4992 4.4992 0 0 1-6.1408-1.6464zM2.3408 7.8956a4.485 4.485 0 0 1 2.3655-1.9728V11.6a.7664.7664 0 0 0 .3879.6765l5.8144 3.3543-2.0201 1.1685a.0757.0757 0 0 1-.071 0l-4.8303-2.7865A4.504 4.504 0 0 1 2.3408 7.872zm16.5963 3.8558L13.1038 8.364 15.1192 7.2a.0757.0757 0 0 1 .071 0l4.8303 2.7913a4.4944 4.4944 0 0 1-.6765 8.1042v-5.6772a.79.79 0 0 0-.407-.667zm2.0107-3.0231l-.142-.0852-4.7735-2.7818a.7759.7759 0 0 0-.7854 0L9.409 9.2297V6.8974a.0662.0662 0 0 1 .0284-.0615l4.8303-2.7866a4.4992 4.4992 0 0 1 6.6802 4.66zM8.3065 12.863l-2.02-1.1638a.0804.0804 0 0 1-.038-.0567V6.0742a4.4992 4.4992 0 0 1 7.3757-3.4537l-.142.0805L8.704 5.459a.7948.7948 0 0 0-.3927.6813zm1.0976-2.3654l2.602-1.4998 2.6069 1.4998v2.9994l-2.5974 1.4997-2.6067-1.4997Z" fill="#ffffff" />
|
||||
</svg>
|
||||
) : p.logo === 'opencode' ? (
|
||||
<svg x="43" y="10" width="19" height="24" viewBox="0 0 32 40" fill="none">
|
||||
<path d="M24 32H8V16H24V32Z" fill="#4B4646"/>
|
||||
<path d="M24 8H8V32H24V8ZM32 40H0V0H32V40Z" fill="#F1ECEC"/>
|
||||
</svg>
|
||||
) : (
|
||||
<image href={p.logo} x="43" y="10" width="24" height="24" filter="url(#invert-white)" />
|
||||
)}
|
||||
</g>
|
||||
<text
|
||||
x="55"
|
||||
y="52"
|
||||
|
|
|
|||
|
|
@ -140,7 +140,7 @@ const permissions: PermissionRule[] = [
|
|||
|
||||
No documented agent mode concept. Behavior controlled via:
|
||||
- `--toolbox` flag for different tool configurations
|
||||
- Permission rules for capability restrictions
|
||||
- Permission rules for feature coverage restrictions
|
||||
|
||||
### Bypass All Permissions
|
||||
|
||||
|
|
|
|||
|
|
@ -567,7 +567,7 @@ console.log(`Running on: ${provider.provider} (${provider.confidence} confidence
|
|||
Several open-source projects implement cloud detection patterns:
|
||||
|
||||
- **cloud-detect** (Python, `pip install cloud-detect`): Detects AWS, GCP, Azure, Alibaba, DigitalOcean, Oracle via filesystem + metadata
|
||||
- **cloud-detect-js** (Node, `npm install cloud-detect-js` or `bun add cloud-detect-js`): JavaScript port with similar capabilities
|
||||
- **cloud-detect-js** (Node, `npm install cloud-detect-js`): JavaScript port with similar feature coverage
|
||||
- **banzaicloud/satellite** (Go): Uses two-tier detection with sysfs first, then metadata fallback
|
||||
- **OpenTelemetry Resource Detectors**: Production-grade detectors across Node.js, Python, Go — use `@opentelemetry/resource-detector-aws`, `@opentelemetry/resource-detector-gcp`, etc.
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ Place all new tests under `server/packages/**/tests/` (or a package-specific `te
|
|||
- Agent management coverage in `agent-management/`
|
||||
- Shared server manager coverage in `server-manager/`
|
||||
- HTTP endpoint snapshots in `http/` (snapshots in `http/snapshots/`)
|
||||
- Session capability snapshots in `sessions/` (one file per capability, e.g. `session_lifecycle.rs`, `permissions.rs`, `questions.rs`, `reasoning.rs`, `status.rs`; snapshots in `sessions/snapshots/`)
|
||||
- Session feature coverage snapshots in `sessions/` (one file per feature, e.g. `session_lifecycle.rs`, `permissions.rs`, `questions.rs`, `reasoning.rs`, `status.rs`; snapshots in `sessions/snapshots/`)
|
||||
- UI coverage in `ui/`
|
||||
- Shared helpers in `common/`
|
||||
- Extracted agent schema roundtrip tests live under `server/packages/extracted-agent-schemas/tests/`
|
||||
|
|
@ -30,7 +30,7 @@ Session snapshot entrypoint:
|
|||
|
||||
Snapshots are written to:
|
||||
- `server/packages/sandbox-agent/tests/http/snapshots/` (HTTP endpoint snapshots)
|
||||
- `server/packages/sandbox-agent/tests/sessions/snapshots/` (session/capability snapshots)
|
||||
- `server/packages/sandbox-agent/tests/sessions/snapshots/` (session/feature coverage snapshots)
|
||||
|
||||
## Agent selection
|
||||
|
||||
|
|
@ -80,7 +80,7 @@ To keep snapshots deterministic:
|
|||
- IDs, timestamps, native IDs
|
||||
- text content, tool inputs/outputs, provider-specific metadata
|
||||
- `source` and `synthetic` flags (these are implementation details)
|
||||
- Scrub `reasoning` and `status` content from session-baseline snapshots to keep the core event skeleton consistent across agents; validate those content types separately in their capability-specific tests.
|
||||
- Scrub `reasoning` and `status` content from session-baseline snapshots to keep the core event skeleton consistent across agents; validate those content types separately in their feature-coverage-specific tests.
|
||||
- The sandbox-agent is responsible for emitting **synthetic events** so that real agents match the mock sequence exactly.
|
||||
- Event streams are truncated after the first assistant or error event.
|
||||
- Permission flow snapshots are truncated after the permission request (or first assistant) event.
|
||||
|
|
@ -110,9 +110,9 @@ cargo test -p sandbox-agent --test http_endpoints
|
|||
|
||||
When modifying agent conversion code in `server/packages/universal-agent-schema/src/agents/` or adding/changing properties on the universal schema, update the feature matrix in `README.md` to reflect which agents support which features.
|
||||
|
||||
## Capabilities sync
|
||||
## Feature coverage sync
|
||||
|
||||
When updating agent capabilities (flags or values), keep them in sync across:
|
||||
When updating agent feature coverage (flags or values), keep them in sync across:
|
||||
- `README.md` (feature matrix / documented support)
|
||||
- server Rust implementation (`AgentCapabilities` + `agent_capabilities_for`)
|
||||
- frontend capability views/badges (Inspector UI)
|
||||
- frontend feature coverage views/badges (Inspector UI)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue