mirror of
https://github.com/coder/coder.git
synced 2026-09-22 13:10:21 +08:00
Replaces the v2.10 `PushContextState` stub with a real coderd write path. Phase 1 of the chat-side persistence story; nothing reads these rows yet. Follows [#25983](https://github.com/coder/coder/pull/25983) and unblocks [CODAGT-569](https://linear.app/codercom/issue/CODAGT-569/enable-agent-api-v210-pushcontextstate-bump-currentminor-wire-coderd). ## What ships ### Schema (`000517_workspace_agent_context.{up,down}.sql`) Two new tables plus `api_key_scope` enum extensions: - `workspace_agent_context_snapshots` (PK `workspace_agent_id` to `workspace_agents(id) ON DELETE CASCADE`): one row per agent, overwritten per push. Holds `version`, `schema_version`, `aggregate_hash`, `snapshot_error`, `received_at`. - `workspace_agent_context_resources` (PK `(workspace_agent_id, source)`): per-resource state. `body_kind` and `status` are `TEXT` + `CHECK` so adding new wire kinds (the RFC's reserved PLUGIN/HOOK/SUBAGENT/COMMAND) is a one-line CHECK update plus a Go switch case. ### SQLC queries (`coderd/database/queries/workspaceagentcontext.sql`) - `UpsertWorkspaceAgentContextSnapshot` - `UpsertWorkspaceAgentContextResource` - `DeleteStaleWorkspaceAgentContextResources` (delete-where-source-not-in) - `GetLatestWorkspaceAgentContextSnapshot` - `ListWorkspaceAgentContextResources` ### Handler (`coderd/agentapi/context.go`) `ContextAPI` is a new sub-API. `PushContextState`: 1. Rejects `schema_version > 1` with a non-`Unimplemented` error so a forward-incompatible agent fails loudly during rollout instead of slipping into the permanent fallback path the `Unimplemented` translation reserves for old coderd deployments. 2. Validates resources: no empty/duplicate sources, every variant maps to a known body kind, every status maps to a known enum value, the `Body` oneof is set (even when status is non-OK, mirroring the wire guarantee so coderd can attribute failures to a known kind). 3. Inside `Database.InTx`, reads the existing snapshot. If the push is not `initial` and `version` is not strictly greater, returns `accepted = false` and leaves stored state untouched. Otherwise upserts the snapshot row, upserts each resource, then runs the stale-source prune so the snapshot and resource rows always agree. 4. Returns `accepted = true` on success. Resource bodies are stored as `protojson(body oneof variant)` in `body JSONB` with `body_kind` as the discriminator. Adding a new field to an existing variant is zero work since `protojson` tolerates new fields; adding a new variant is a CHECK + switch case. ### RBAC + dbauthz - New `ResourceWorkspaceAgentContext` (Create/Read/Update/Delete). - New `SubjectTypeAgentContext` plus `subjectAgentContext` system role and `dbauthz.AsAgentContext` helper. The push handler elevates to this subject; the agent's own role does not get direct write access to the table. - New `workspace_agent_context:*` API key scopes registered in the enum migration; internal-only (not added to `externalLowLevel`). ### Audit These rows are agent-pushed state, not user-authored. They are intentionally not added to `AuditActionMap` and not enumerated in `enterprise/audit/table.go`, matching `boundary_logs`, `workspace_agent_memory_resource_monitor`, etc. `enterprise/audit` tests pass unchanged. ## Tests - `coderd/agentapi/context_test.go`: 12 subtests covering accepts/rejects (schema version, empty/duplicate source, unknown status, missing body), version semantics (stale dropped, same-version replay dropped, `initial=true` overwrites lower version), variant coverage, non-OK status persistence, and the empty-active-set prune case. - `coderd/database/dbauthz/dbauthz_test.go`: 5 `MethodTestSuite` cases covering the new queries. - `coderd/rbac/roles_test.go`: `WorkspaceAgentContext` permission row asserting no human role currently has access. - `coderd/database/migrations/testdata/fixtures/000517_workspace_agent_context.up.sql`: one snapshot + one resource per known body kind plus a non-OK status, so the migration test suite never lands with these tables empty. ## Out of scope (later phases) - Chat hydration (`chats.context_aggregate_hash`, `last_injected_context`). - Dirty-bit fan-out and `PUT /chats/{id}/context`. - Agent-side `POST /api/v0/context/resync` barrier and the `coder exp chat context` CLI. - `codersdk` chat-context wire types and the dashboard Sources drawer. - Removal of the chatd per-turn pull fallback. ## Compat property This is a pure write path. If anything here returns errors the agent's `RunPush` loop backs off, no chat behavior changes, and the workspace keeps behaving exactly like it did before v2.10. <details> <summary>Implementation plan and decision log</summary> Key design calls: 1. **Concurrency**: Accept iff `req.Initial || req.Version > existing.Version`. The strict RFC reading ("version comparison is authoritative") locks restarted agents out because their per-process counter resets to 1; honoring `initial=true` reflects the real reboot reality while still rejecting steady-state replays/out-of-order pushes. 2. **Body encoding**: `protojson` over the oneof variant body proto, stored in JSONB with `body_kind` discriminator. Structured at the API/Go layer, schema-tolerant at the storage layer, and Phase 2 readers round-trip back via `protojson.Unmarshal`. 3. **Schema version rejection**: returns a normal error, not `Unimplemented`. The agent's `RunPush` loop only short-circuits on `Unimplemented`; that escape hatch is reserved for old coderd deployments. A forward-incompatible agent should retry-and-back-off, not flip the connection into permanent fallback. 4. **Validation strictness**: empty sources, duplicate sources, `STATUS_UNSPECIFIED`, and missing `Body` oneof variants are rejected before any write so a misbehaving agent cannot poison the snapshot table. Phase 2 readers can trust every row maps to a known proto variant. </details> _This PR was authored by Coder Agents on Kyle Carberry's behalf._
681 lines
17 KiB
Protocol Buffer
681 lines
17 KiB
Protocol Buffer
syntax = "proto3";
|
|
option go_package = "github.com/coder/coder/v2/agent/proto";
|
|
|
|
package coder.agent.v2;
|
|
|
|
import "tailnet/proto/tailnet.proto";
|
|
import "google/protobuf/timestamp.proto";
|
|
import "google/protobuf/duration.proto";
|
|
import "google/protobuf/empty.proto";
|
|
import "google/protobuf/struct.proto";
|
|
|
|
message WorkspaceApp {
|
|
bytes id = 1;
|
|
string url = 2;
|
|
bool external = 3;
|
|
string slug = 4;
|
|
string display_name = 5;
|
|
string command = 6;
|
|
string icon = 7;
|
|
bool subdomain = 8;
|
|
string subdomain_name = 9;
|
|
|
|
enum SharingLevel {
|
|
SHARING_LEVEL_UNSPECIFIED = 0;
|
|
OWNER = 1;
|
|
AUTHENTICATED = 2;
|
|
PUBLIC = 3;
|
|
ORGANIZATION = 4;
|
|
}
|
|
SharingLevel sharing_level = 10;
|
|
|
|
message Healthcheck {
|
|
string url = 1;
|
|
google.protobuf.Duration interval = 2;
|
|
int32 threshold = 3;
|
|
}
|
|
Healthcheck healthcheck = 11;
|
|
|
|
enum Health {
|
|
HEALTH_UNSPECIFIED = 0;
|
|
DISABLED = 1;
|
|
INITIALIZING = 2;
|
|
HEALTHY = 3;
|
|
UNHEALTHY = 4;
|
|
}
|
|
Health health = 12;
|
|
bool hidden = 13;
|
|
}
|
|
|
|
message WorkspaceAgentScript {
|
|
bytes log_source_id = 1;
|
|
string log_path = 2;
|
|
string script = 3;
|
|
string cron = 4;
|
|
bool run_on_start = 5;
|
|
bool run_on_stop = 6;
|
|
bool start_blocks_login = 7;
|
|
google.protobuf.Duration timeout = 8;
|
|
string display_name = 9;
|
|
bytes id = 10;
|
|
}
|
|
|
|
message WorkspaceAgentMetadata {
|
|
message Result {
|
|
google.protobuf.Timestamp collected_at = 1;
|
|
int64 age = 2;
|
|
string value = 3;
|
|
string error = 4;
|
|
}
|
|
Result result = 1;
|
|
|
|
message Description {
|
|
string display_name = 1;
|
|
string key = 2;
|
|
string script = 3;
|
|
google.protobuf.Duration interval = 4;
|
|
google.protobuf.Duration timeout = 5;
|
|
}
|
|
Description description = 2;
|
|
}
|
|
|
|
message Manifest {
|
|
bytes agent_id = 1;
|
|
string agent_name = 15;
|
|
string owner_username = 13;
|
|
bytes workspace_id = 14;
|
|
string workspace_name = 16;
|
|
uint32 git_auth_configs = 2;
|
|
map<string, string> environment_variables = 3;
|
|
string directory = 4;
|
|
string vs_code_port_proxy_uri = 5;
|
|
string motd_path = 6;
|
|
bool disable_direct_connections = 7;
|
|
bool derp_force_websockets = 8;
|
|
optional bytes parent_id = 18;
|
|
|
|
coder.tailnet.v2.DERPMap derp_map = 9;
|
|
repeated WorkspaceAgentScript scripts = 10;
|
|
repeated WorkspaceApp apps = 11;
|
|
repeated WorkspaceAgentMetadata.Description metadata = 12;
|
|
repeated WorkspaceAgentDevcontainer devcontainers = 17;
|
|
repeated WorkspaceSecret secrets = 19;
|
|
}
|
|
|
|
// WorkspaceSecret is a secret included in the agent manifest
|
|
// for injection into a workspace.
|
|
message WorkspaceSecret {
|
|
// Environment variable name to inject (e.g. "GITHUB_TOKEN").
|
|
// Empty string means this secret is not injected as an env var.
|
|
string env_name = 1;
|
|
// File path to write the secret value to (e.g.
|
|
// "~/.aws/credentials"). Empty string means this secret is not
|
|
// written to a file.
|
|
string file_path = 2;
|
|
// The decrypted secret value.
|
|
bytes value = 3;
|
|
}
|
|
|
|
message WorkspaceAgentDevcontainer {
|
|
bytes id = 1;
|
|
string workspace_folder = 2;
|
|
string config_path = 3;
|
|
string name = 4;
|
|
optional bytes subagent_id = 5;
|
|
}
|
|
|
|
message GetManifestRequest {}
|
|
|
|
message ServiceBanner {
|
|
bool enabled = 1;
|
|
string message = 2;
|
|
string background_color = 3;
|
|
}
|
|
|
|
message GetServiceBannerRequest {}
|
|
|
|
message Stats {
|
|
// ConnectionsByProto is a count of connections by protocol.
|
|
map<string, int64> connections_by_proto = 1;
|
|
// ConnectionCount is the number of connections received by an agent.
|
|
int64 connection_count = 2;
|
|
// ConnectionMedianLatencyMS is the median latency of all connections in milliseconds.
|
|
double connection_median_latency_ms = 3;
|
|
// RxPackets is the number of received packets.
|
|
int64 rx_packets = 4;
|
|
// RxBytes is the number of received bytes.
|
|
int64 rx_bytes = 5;
|
|
// TxPackets is the number of transmitted bytes.
|
|
int64 tx_packets = 6;
|
|
// TxBytes is the number of transmitted bytes.
|
|
int64 tx_bytes = 7;
|
|
|
|
// SessionCountVSCode is the number of connections received by an agent
|
|
// that are from our VS Code extension.
|
|
int64 session_count_vscode = 8;
|
|
// SessionCountJetBrains is the number of connections received by an agent
|
|
// that are from our JetBrains extension.
|
|
int64 session_count_jetbrains = 9;
|
|
// SessionCountReconnectingPTY is the number of connections received by an agent
|
|
// that are from the reconnecting web terminal.
|
|
int64 session_count_reconnecting_pty = 10;
|
|
// SessionCountSSH is the number of connections received by an agent
|
|
// that are normal, non-tagged SSH sessions.
|
|
int64 session_count_ssh = 11;
|
|
|
|
message Metric {
|
|
string name = 1;
|
|
|
|
enum Type {
|
|
TYPE_UNSPECIFIED = 0;
|
|
COUNTER = 1;
|
|
GAUGE = 2;
|
|
}
|
|
Type type = 2;
|
|
|
|
double value = 3;
|
|
|
|
message Label {
|
|
string name = 1;
|
|
string value = 2;
|
|
}
|
|
repeated Label labels = 4;
|
|
}
|
|
repeated Metric metrics = 12;
|
|
}
|
|
|
|
message UpdateStatsRequest{
|
|
Stats stats = 1;
|
|
}
|
|
|
|
message UpdateStatsResponse {
|
|
google.protobuf.Duration report_interval = 1;
|
|
}
|
|
|
|
message Lifecycle {
|
|
enum State {
|
|
STATE_UNSPECIFIED = 0;
|
|
CREATED = 1;
|
|
STARTING = 2;
|
|
START_TIMEOUT = 3;
|
|
START_ERROR = 4;
|
|
READY = 5;
|
|
SHUTTING_DOWN = 6;
|
|
SHUTDOWN_TIMEOUT = 7;
|
|
SHUTDOWN_ERROR = 8;
|
|
OFF = 9;
|
|
}
|
|
State state = 1;
|
|
google.protobuf.Timestamp changed_at = 2;
|
|
}
|
|
|
|
message UpdateLifecycleRequest {
|
|
Lifecycle lifecycle = 1;
|
|
}
|
|
|
|
enum AppHealth {
|
|
APP_HEALTH_UNSPECIFIED = 0;
|
|
DISABLED = 1;
|
|
INITIALIZING = 2;
|
|
HEALTHY = 3;
|
|
UNHEALTHY = 4;
|
|
}
|
|
|
|
message BatchUpdateAppHealthRequest {
|
|
message HealthUpdate {
|
|
bytes id = 1;
|
|
AppHealth health = 2;
|
|
}
|
|
repeated HealthUpdate updates = 1;
|
|
}
|
|
|
|
message BatchUpdateAppHealthResponse {}
|
|
|
|
message Startup {
|
|
string version = 1;
|
|
string expanded_directory = 2;
|
|
enum Subsystem {
|
|
SUBSYSTEM_UNSPECIFIED = 0;
|
|
ENVBOX = 1;
|
|
ENVBUILDER = 2;
|
|
EXECTRACE = 3;
|
|
}
|
|
repeated Subsystem subsystems = 3;
|
|
}
|
|
|
|
message UpdateStartupRequest{
|
|
Startup startup = 1;
|
|
}
|
|
|
|
message Metadata {
|
|
string key = 1;
|
|
WorkspaceAgentMetadata.Result result = 2;
|
|
}
|
|
|
|
message BatchUpdateMetadataRequest {
|
|
repeated Metadata metadata = 2;
|
|
}
|
|
|
|
message BatchUpdateMetadataResponse {}
|
|
|
|
message Log {
|
|
google.protobuf.Timestamp created_at = 1;
|
|
string output = 2;
|
|
|
|
enum Level {
|
|
LEVEL_UNSPECIFIED = 0;
|
|
TRACE = 1;
|
|
DEBUG = 2;
|
|
INFO = 3;
|
|
WARN = 4;
|
|
ERROR = 5;
|
|
}
|
|
Level level = 3;
|
|
}
|
|
|
|
message BatchCreateLogsRequest {
|
|
bytes log_source_id = 1;
|
|
repeated Log logs = 2;
|
|
}
|
|
|
|
message BatchCreateLogsResponse {
|
|
bool log_limit_exceeded = 1;
|
|
}
|
|
|
|
message GetAnnouncementBannersRequest {}
|
|
|
|
message GetAnnouncementBannersResponse {
|
|
repeated BannerConfig announcement_banners = 1;
|
|
}
|
|
|
|
message BannerConfig {
|
|
bool enabled = 1;
|
|
string message = 2;
|
|
string background_color = 3;
|
|
}
|
|
|
|
message WorkspaceAgentScriptCompletedRequest {
|
|
Timing timing = 1;
|
|
}
|
|
|
|
message WorkspaceAgentScriptCompletedResponse {
|
|
}
|
|
|
|
message Timing {
|
|
bytes script_id = 1;
|
|
google.protobuf.Timestamp start = 2;
|
|
google.protobuf.Timestamp end = 3;
|
|
int32 exit_code = 4;
|
|
|
|
enum Stage {
|
|
START = 0;
|
|
STOP = 1;
|
|
CRON = 2;
|
|
}
|
|
Stage stage = 5;
|
|
|
|
enum Status {
|
|
OK = 0;
|
|
EXIT_FAILURE = 1;
|
|
TIMED_OUT = 2;
|
|
PIPES_LEFT_OPEN = 3;
|
|
}
|
|
Status status = 6;
|
|
}
|
|
|
|
message GetResourcesMonitoringConfigurationRequest {
|
|
}
|
|
|
|
message GetResourcesMonitoringConfigurationResponse {
|
|
message Config {
|
|
int32 num_datapoints = 1;
|
|
int32 collection_interval_seconds = 2;
|
|
}
|
|
Config config = 1;
|
|
|
|
message Memory {
|
|
bool enabled = 1;
|
|
}
|
|
optional Memory memory = 2;
|
|
|
|
message Volume {
|
|
bool enabled = 1;
|
|
string path = 2;
|
|
}
|
|
repeated Volume volumes = 3;
|
|
}
|
|
|
|
message PushResourcesMonitoringUsageRequest {
|
|
message Datapoint {
|
|
message MemoryUsage {
|
|
int64 used = 1;
|
|
int64 total = 2;
|
|
}
|
|
message VolumeUsage {
|
|
string volume = 1;
|
|
int64 used = 2;
|
|
int64 total = 3;
|
|
}
|
|
|
|
google.protobuf.Timestamp collected_at = 1;
|
|
optional MemoryUsage memory = 2;
|
|
repeated VolumeUsage volumes = 3;
|
|
|
|
}
|
|
repeated Datapoint datapoints = 1;
|
|
}
|
|
|
|
message PushResourcesMonitoringUsageResponse {
|
|
}
|
|
|
|
message Connection {
|
|
enum Action {
|
|
ACTION_UNSPECIFIED = 0;
|
|
CONNECT = 1;
|
|
DISCONNECT = 2;
|
|
}
|
|
enum Type {
|
|
TYPE_UNSPECIFIED = 0;
|
|
SSH = 1;
|
|
VSCODE = 2;
|
|
JETBRAINS = 3;
|
|
RECONNECTING_PTY = 4;
|
|
}
|
|
|
|
bytes id = 1;
|
|
Action action = 2;
|
|
Type type = 3;
|
|
google.protobuf.Timestamp timestamp = 4;
|
|
string ip = 5;
|
|
int32 status_code = 6;
|
|
optional string reason = 7;
|
|
}
|
|
|
|
message ReportConnectionRequest {
|
|
Connection connection = 1;
|
|
}
|
|
|
|
message SubAgent {
|
|
string name = 1;
|
|
bytes id = 2;
|
|
bytes auth_token = 3;
|
|
}
|
|
|
|
message CreateSubAgentRequest {
|
|
string name = 1;
|
|
string directory = 2;
|
|
string architecture = 3;
|
|
string operating_system = 4;
|
|
|
|
message App {
|
|
message Healthcheck {
|
|
int32 interval = 1;
|
|
int32 threshold = 2;
|
|
string url = 3;
|
|
}
|
|
|
|
enum OpenIn {
|
|
SLIM_WINDOW = 0;
|
|
TAB = 1;
|
|
}
|
|
|
|
enum SharingLevel {
|
|
OWNER = 0;
|
|
AUTHENTICATED = 1;
|
|
PUBLIC = 2;
|
|
ORGANIZATION = 3;
|
|
}
|
|
|
|
string slug = 1;
|
|
optional string command = 2;
|
|
optional string display_name = 3;
|
|
optional bool external = 4;
|
|
optional string group = 5;
|
|
optional Healthcheck healthcheck = 6;
|
|
optional bool hidden = 7;
|
|
optional string icon = 8;
|
|
optional OpenIn open_in = 9;
|
|
optional int32 order = 10;
|
|
optional SharingLevel share = 11;
|
|
optional bool subdomain = 12;
|
|
optional string url = 13;
|
|
}
|
|
|
|
repeated App apps = 5;
|
|
|
|
enum DisplayApp {
|
|
VSCODE = 0;
|
|
VSCODE_INSIDERS = 1;
|
|
WEB_TERMINAL = 2;
|
|
SSH_HELPER = 3;
|
|
PORT_FORWARDING_HELPER = 4;
|
|
}
|
|
|
|
repeated DisplayApp display_apps = 6;
|
|
|
|
optional bytes id = 7;
|
|
}
|
|
|
|
message CreateSubAgentResponse {
|
|
message AppCreationError {
|
|
int32 index = 1;
|
|
optional string field = 2;
|
|
string error = 3;
|
|
}
|
|
|
|
SubAgent agent = 1;
|
|
repeated AppCreationError app_creation_errors = 2;
|
|
}
|
|
|
|
message DeleteSubAgentRequest {
|
|
bytes id = 1;
|
|
}
|
|
|
|
message DeleteSubAgentResponse {}
|
|
|
|
message ListSubAgentsRequest {}
|
|
|
|
message ListSubAgentsResponse {
|
|
repeated SubAgent agents = 1;
|
|
}
|
|
|
|
// BoundaryLog represents a log for a single resource access processed
|
|
// by boundary.
|
|
message BoundaryLog {
|
|
message HttpRequest {
|
|
string method = 1;
|
|
string url = 2;
|
|
// The rule that resulted in this HTTP request being allowed. Only populated
|
|
// when allowed = true because boundary denies requests by default and
|
|
// requires rule(s) that allow requests.
|
|
string matched_rule = 3;
|
|
}
|
|
|
|
// Whether boundary allowed this resource access.
|
|
bool allowed = 1;
|
|
|
|
// The timestamp when boundary processed this resource access.
|
|
google.protobuf.Timestamp time = 2;
|
|
|
|
// The resource being accessed by boundary.
|
|
oneof resource {
|
|
HttpRequest http_request = 3;
|
|
}
|
|
|
|
// Monotonically increasing integer assigned by boundary, starting at 0
|
|
// per session. Primary ordering key when boundary is in use.
|
|
int32 sequence_number = 4;
|
|
}
|
|
|
|
// ReportBoundaryLogsRequest is a request to re-emit the given BoundaryLogs.
|
|
message ReportBoundaryLogsRequest {
|
|
repeated BoundaryLog logs = 1;
|
|
// session_id identifies the boundary invocation that produced these
|
|
// logs. It is a UUID generated by boundary at startup and is the same
|
|
// for all batches produced by a single boundary run.
|
|
string session_id = 2;
|
|
// confined_process is the name of the process that boundary is
|
|
// confining (e.g. "claude-code", "codex", "copilot").
|
|
string confined_process_name = 3;
|
|
}
|
|
|
|
message ReportBoundaryLogsResponse {}
|
|
|
|
// UpdateAppStatusRequest updates the given Workspace App's status. c.f. agentsdk.PatchAppStatus
|
|
message UpdateAppStatusRequest {
|
|
string slug = 1;
|
|
|
|
enum AppStatusState {
|
|
WORKING = 0;
|
|
IDLE = 1;
|
|
COMPLETE = 2;
|
|
FAILURE = 3;
|
|
}
|
|
AppStatusState state = 2;
|
|
|
|
string message = 3;
|
|
string uri = 4;
|
|
}
|
|
|
|
message UpdateAppStatusResponse {}
|
|
|
|
// ContextResource is a single resolved workspace context
|
|
// resource (instruction file, skill meta, MCP config, or live
|
|
// MCP server tool list) pushed from the agent to coderd as part
|
|
// of a PushContextStateRequest snapshot.
|
|
//
|
|
// The resource kind is conveyed by which variant of the body
|
|
// oneof is set. Reserved variants for the Claude Code plugin
|
|
// RFC (plugin/hook/subagent/command bodies) are not emitted by
|
|
// v2.10 agents but will be added without renumbering.
|
|
message ContextResource {
|
|
// source is the resource's own locator: a canonical file path
|
|
// for file-backed kinds, or the MCP server name for
|
|
// mcp_server resources.
|
|
string source = 1;
|
|
// source_path is the user-declared scan root that produced
|
|
// this resource (empty for built-in roots, set to the owning
|
|
// .mcp.json for mcp_server entries declared in a user config).
|
|
optional string source_path = 2;
|
|
// content_hash is sha256 over the original on-disk bytes (or
|
|
// over the agent's canonical encoding for non-file kinds).
|
|
bytes content_hash = 3;
|
|
// size_bytes is the resource's original size in bytes.
|
|
uint64 size_bytes = 4;
|
|
Status status = 5;
|
|
// error carries the per-resource failure string when status
|
|
// is not OK; may also carry a non-fatal warning when status
|
|
// is OK.
|
|
string error = 6;
|
|
|
|
enum Status {
|
|
STATUS_UNSPECIFIED = 0;
|
|
OK = 1;
|
|
OVERSIZE = 2;
|
|
UNREADABLE = 3;
|
|
INVALID = 4;
|
|
EXCLUDED = 5;
|
|
}
|
|
|
|
// body conveys both the resource kind (via which variant is
|
|
// set) and the kind-specific payload. The variant is set even
|
|
// when status is not OK so coderd can still attribute the
|
|
// failure to a known kind.
|
|
oneof body {
|
|
InstructionFileBody instruction_file = 10;
|
|
SkillMetaBody skill = 11;
|
|
MCPConfigBody mcp_config = 12;
|
|
MCPServerBody mcp_server = 13;
|
|
}
|
|
|
|
// Reserved tags from the legacy v2.10 schema that carried
|
|
// id (1->renamed), kind enum, payload, description, and the
|
|
// removed plugin/hook/subagent/command flat fields. Keep them
|
|
// reserved so a future renumber cannot reintroduce them.
|
|
reserved 7, 8, 9, 14, 15, 16;
|
|
}
|
|
|
|
// InstructionFileBody carries a plain-text instruction file
|
|
// such as AGENTS.md, CLAUDE.md, or .cursorrules. The content is
|
|
// the verbatim file bytes (capped at the resolver's per-resource
|
|
// limit).
|
|
message InstructionFileBody {
|
|
bytes content = 1;
|
|
}
|
|
|
|
// SkillMetaBody carries the SKILL.md meta file content plus the
|
|
// fields parsed from its YAML front-matter. Supporting files in
|
|
// the skill directory are NOT included; clients fetch them on
|
|
// demand via the agent's local HTTP API.
|
|
message SkillMetaBody {
|
|
bytes meta = 1;
|
|
string name = 2;
|
|
string description = 3;
|
|
}
|
|
|
|
// MCPConfigBody is intentionally empty: the .mcp.json content
|
|
// can contain secrets in env blocks and must not leave the
|
|
// agent. content_hash and size_bytes on ContextResource still
|
|
// let coderd detect changes for cache invalidation.
|
|
message MCPConfigBody {
|
|
}
|
|
|
|
// MCPServerBody carries a live MCP server's resolved tool list,
|
|
// emitted by the agent's MCPProvider after the server has been
|
|
// connected.
|
|
message MCPServerBody {
|
|
string server_name = 1;
|
|
string description = 2;
|
|
repeated MCPTool tools = 3;
|
|
}
|
|
|
|
// MCPTool mirrors the MCP server-reported tool surface. The
|
|
// input schema is JSON Schema; we ship it as a google.protobuf
|
|
// Struct so coderd can introspect it without re-parsing JSON.
|
|
message MCPTool {
|
|
string name = 1;
|
|
string description = 2;
|
|
google.protobuf.Struct input_schema = 3;
|
|
}
|
|
|
|
message PushContextStateRequest {
|
|
uint64 version = 1;
|
|
bytes aggregate_hash = 2;
|
|
repeated ContextResource resources = 3;
|
|
bool initial = 4;
|
|
string snapshot_error = 6;
|
|
|
|
// Reserved tags from the pre-release v2.10 schema. schema_version
|
|
// was removed before the first release that ships v2.10 because
|
|
// it duplicated the agent API minor version (tailnet/proto.
|
|
// CurrentMinor); the proto bump and the existing Unimplemented
|
|
// fallback cover every forward-compat case it tried to address.
|
|
reserved 5;
|
|
}
|
|
|
|
message PushContextStateResponse {
|
|
bool accepted = 1;
|
|
}
|
|
|
|
service Agent {
|
|
rpc GetManifest(GetManifestRequest) returns (Manifest);
|
|
rpc GetServiceBanner(GetServiceBannerRequest) returns (ServiceBanner);
|
|
rpc UpdateStats(UpdateStatsRequest) returns (UpdateStatsResponse);
|
|
rpc UpdateLifecycle(UpdateLifecycleRequest) returns (Lifecycle);
|
|
rpc BatchUpdateAppHealths(BatchUpdateAppHealthRequest) returns (BatchUpdateAppHealthResponse);
|
|
rpc UpdateStartup(UpdateStartupRequest) returns (Startup);
|
|
rpc BatchUpdateMetadata(BatchUpdateMetadataRequest) returns (BatchUpdateMetadataResponse);
|
|
rpc BatchCreateLogs(BatchCreateLogsRequest) returns (BatchCreateLogsResponse);
|
|
rpc GetAnnouncementBanners(GetAnnouncementBannersRequest) returns (GetAnnouncementBannersResponse);
|
|
rpc ScriptCompleted(WorkspaceAgentScriptCompletedRequest) returns (WorkspaceAgentScriptCompletedResponse);
|
|
rpc GetResourcesMonitoringConfiguration(GetResourcesMonitoringConfigurationRequest) returns (GetResourcesMonitoringConfigurationResponse);
|
|
rpc PushResourcesMonitoringUsage(PushResourcesMonitoringUsageRequest) returns (PushResourcesMonitoringUsageResponse);
|
|
rpc ReportConnection(ReportConnectionRequest) returns (google.protobuf.Empty);
|
|
rpc CreateSubAgent(CreateSubAgentRequest) returns (CreateSubAgentResponse);
|
|
rpc DeleteSubAgent(DeleteSubAgentRequest) returns (DeleteSubAgentResponse);
|
|
rpc ListSubAgents(ListSubAgentsRequest) returns (ListSubAgentsResponse);
|
|
rpc ReportBoundaryLogs(ReportBoundaryLogsRequest) returns (ReportBoundaryLogsResponse);
|
|
rpc UpdateAppStatus(UpdateAppStatusRequest) returns (UpdateAppStatusResponse);
|
|
rpc PushContextState(PushContextStateRequest) returns (PushContextStateResponse);
|
|
}
|