From 4f4fa0e22f6bcbe76578fbbec8572710d98b5b16 Mon Sep 17 00:00:00 2001 From: Yao Date: Tue, 29 Sep 2026 23:19:32 +0800 Subject: [PATCH 01/14] docs: annotate every operation's responses and request conventions Rewrite the handler annotations so each operation leads with one short sentence, groups its rules into lists and declares every status the handler writes. Correct the deployment model configuration PUT body, which named a nonexistent x_agents_core.model_configuration field. Add docs/api/request-conventions.md for the headers, JSON body checks and list parameters every /v1 operation shares, and regenerate the three OpenAPI contracts with make openapi. --- docs/api/request-conventions.md | 67 +++++++++++++++++++ .../internal/api/admin_sessions_routes.go | 2 +- .../internal/api/admin_skills_routes.go | 12 +++- services/agents-api/internal/api/agents.go | 4 +- .../agents-api/internal/api/agents_delete.go | 2 +- .../agents-api/internal/api/agents_list.go | 2 +- .../agents-api/internal/api/agents_update.go | 2 +- .../agents-api/internal/api/credentials.go | 2 +- .../internal/api/credentials_delete.go | 2 +- .../internal/api/credentials_list.go | 2 +- .../api/environment_executor_management.go | 2 +- .../internal/api/environment_installation.go | 6 +- .../internal/api/environment_templates.go | 10 +-- .../agents-api/internal/api/environments.go | 2 +- services/agents-api/internal/api/handler.go | 4 +- .../internal/api/harness_model_providers.go | 2 +- services/agents-api/internal/api/items.go | 2 +- .../internal/api/project_api_keys.go | 6 +- .../internal/api/sandbox_deployment_setup.go | 6 +- .../internal/api/sandbox_e2b_discovery.go | 4 +- .../internal/api/sandbox_manager.go | 6 +- .../internal/api/session_deletion.go | 2 +- .../internal/api/session_metadata.go | 2 +- services/agents-api/internal/api/skills.go | 5 ++ .../agents-api/internal/api/skills_list.go | 2 + .../internal/api/skills_transfer.go | 4 ++ services/agents-api/internal/api/turns.go | 4 +- services/agents-api/internal/api/vaults.go | 4 +- .../agents-api/internal/api/vaults_delete.go | 2 +- .../agents-api/internal/api/vaults_list.go | 2 +- 30 files changed, 130 insertions(+), 44 deletions(-) create mode 100644 docs/api/request-conventions.md diff --git a/docs/api/request-conventions.md b/docs/api/request-conventions.md new file mode 100644 index 000000000..e59781992 --- /dev/null +++ b/docs/api/request-conventions.md @@ -0,0 +1,67 @@ +# Request conventions + +These rules apply to every `/v1` operation. Operation pages state only what differs +from them. + +## Headers + +| Header | Rule | +| --- | --- | +| `Authorization` | `Bearer ` on every operation. See [API namespaces and credentials](README.md). | +| `OpenAI-Beta` | Exactly one `agents=v1` value on every operation except Files (`/files`) and Skills (`/skills`). Otherwise 400 `invalid_beta`. The pinned SDK sends it. | +| `OpenAI-Organization`, `OpenAI-Project` | Optional. If present they must be `core` and `proj_`. | +| `Idempotency-Key` | Optional on Session creation and on event submission, up to 128 bytes. A Core extension: a retry with the same key and request returns the original result, and the same key with a different request returns 409 `idempotency_conflict`. A streamed Session creation retry is the exception; see Create an execution Session. The hosted service returned distinct Sessions for repeated creation keys; its event submission behavior is not documented. | + +## JSON request bodies + +Every operation with a JSON body checks it in this order, before any field +validation or resource lookup: + +1. The `Content-Type` must be `application/json` or another `application/*+json` + type, case-insensitive, with well-formed parameters. +2. The body must fit the operation's limit: 1 MiB, or 16 MiB for Session creation and + for creating or updating an Environment Template. Environment file uploads have + their own limits. A larger body returns 413 `request_too_large` with a Core + message naming the limit. +3. The body must be valid UTF-8 and one JSON value, with no unpaired surrogate + escape and no repeated key at any depth, and its root must be an object. An empty + body or `null` is treated as `{}`. + +Failures of checks 1 and 3 return 400 `invalid_request_error` with a null `param` +and the official message. + +Updating a Skill's default version (`POST /v1/skills/{skill_id}`) is the one +exception: it reads its body without these checks, up to 64 KiB, and an unreadable +body returns 400 `invalid_request`. + +Member names match exactly; a case variant is an unknown member. Text that contains +U+0000 or cannot be stored as UTF-8 returns 400 `invalid_request_error`. This is a +limit of Core's storage, not of the official API. + +## Lists + +Lists take `after`, `limit` and `order`; the Environment files list pages with +`path`, `page` and `order` instead. `order` is `asc` or `desc`; omitting it uses the +operation's default, and an explicitly empty value is invalid. Unknown query keys +are ignored, and a supported scalar key given twice is rejected. Array parameters, +such as the Vault and Credential `status[]` filter, may repeat. + +The `limit` bounds, the default order and the fields of each error differ between +the Agents API lists, Files and Skills. Each operation page states its bounds and how +an unresolved `after` cursor fails. The +[list query record](../../contracts/agents-api/list-query-semantics.md) has the +evidence for each family. + +## Errors + +Clients branch on the HTTP status and `error.code`, never on `message`. The +[error code registry](../../contracts/agents-api/error-codes.md) lists every code. + +## Compatibility notes + +Core implements the pinned OpenAI Agents API. Where an operation page says a +behavior is not yet verified against the hosted service, Core's behavior is +documented but has not been compared with the official service. The +[coverage record](../../contracts/agents-api/README.md) and +[operation evidence](../../contracts/agents-api/operation-evidence.md) hold the +details and the request evidence. diff --git a/services/agents-api/internal/api/admin_sessions_routes.go b/services/agents-api/internal/api/admin_sessions_routes.go index 7775b4e27..d8e8f803b 100644 --- a/services/agents-api/internal/api/admin_sessions_routes.go +++ b/services/agents-api/internal/api/admin_sessions_routes.go @@ -197,7 +197,7 @@ func (h *Handler) adminGetRuntimeObservation(w http.ResponseWriter, r *http.Requ // @Param end query integer true "Exclusive Unix-second end" minimum(1) maximum(9007199254740991) // @Param max_points query integer false "Maximum points per series; defaults to the lower of 120 and the advertised service maximum" minimum(2) maximum(10000) // @Success 200 {object} v1.RuntimeHistory -// @Failure 400,401,404,409,503 {object} CoreErrorResponse +// @Failure 400,401,404,409,500,503 {object} CoreErrorResponse // @Param project_id path string true "Project ID" // @Router /core/v1/projects/{project_id}/sessions/{session_id}/runtime-history [get] func (h *Handler) adminGetRuntimeHistory(w http.ResponseWriter, r *http.Request) { diff --git a/services/agents-api/internal/api/admin_skills_routes.go b/services/agents-api/internal/api/admin_skills_routes.go index 583968e5b..96b207d2a 100644 --- a/services/agents-api/internal/api/admin_skills_routes.go +++ b/services/agents-api/internal/api/admin_skills_routes.go @@ -8,9 +8,10 @@ import "net/http" // @Produce json // @Security DeploymentAdminAuth // @Param after query string false "Skill resource cursor" -// @Param limit query integer false "Page size; 0 returns an empty page" default(20) minimum(0) maximum(100) +// @Param limit query integer false "Page size, 1–100" default(20) minimum(1) maximum(100) // @Param order query string false "Creation order; omit for descending, explicit empty values are invalid" Enums(asc,desc) // @Success 200 {object} v1.SkillList +// @Failure 400,401,404,500,503 {object} CoreErrorResponse // @Param project_id path string true "Project ID" // @Router /core/v1/projects/{project_id}/skills [get] func (h *Handler) adminListSkills(w http.ResponseWriter, r *http.Request) { @@ -24,6 +25,7 @@ func (h *Handler) adminListSkills(w http.ResponseWriter, r *http.Request) { // @Security DeploymentAdminAuth // @Param skill_id path string true "Skill ID" // @Success 200 {object} v1.Skill +// @Failure 400,401,404,500,503 {object} CoreErrorResponse // @Param project_id path string true "Project ID" // @Router /core/v1/projects/{project_id}/skills/{skill_id} [get] func (h *Handler) adminGetSkill(w http.ResponseWriter, r *http.Request) { @@ -37,6 +39,7 @@ func (h *Handler) adminGetSkill(w http.ResponseWriter, r *http.Request) { // @Security DeploymentAdminAuth // @Param skill_id path string true "Skill ID" // @Success 200 {object} v1.SkillDeleted +// @Failure 400,401,404,500,503 {object} CoreErrorResponse // @Param project_id path string true "Project ID" // @Router /core/v1/projects/{project_id}/skills/{skill_id} [delete] func (h *Handler) adminDeleteSkill(w http.ResponseWriter, r *http.Request) { @@ -50,6 +53,7 @@ func (h *Handler) adminDeleteSkill(w http.ResponseWriter, r *http.Request) { // @Security DeploymentAdminAuth // @Param skill_id path string true "Skill ID" // @Success 200 {file} binary +// @Failure 400,401,404,500,503 {object} CoreErrorResponse // @Param project_id path string true "Project ID" // @Router /core/v1/projects/{project_id}/skills/{skill_id}/content [get] func (h *Handler) adminSkillContent(w http.ResponseWriter, r *http.Request) { @@ -63,9 +67,10 @@ func (h *Handler) adminSkillContent(w http.ResponseWriter, r *http.Request) { // @Security DeploymentAdminAuth // @Param skill_id path string true "Skill ID" // @Param after query string false "Version resource cursor" -// @Param limit query integer false "Page size; 0 returns an empty page" default(20) minimum(0) maximum(100) +// @Param limit query integer false "Page size, 1–100" default(20) minimum(1) maximum(100) // @Param order query string false "Version order; omit for descending, explicit empty values are invalid" Enums(asc,desc) // @Success 200 {object} v1.SkillVersionList +// @Failure 400,401,404,500,503 {object} CoreErrorResponse // @Param project_id path string true "Project ID" // @Router /core/v1/projects/{project_id}/skills/{skill_id}/versions [get] func (h *Handler) adminListSkillVersions(w http.ResponseWriter, r *http.Request) { @@ -80,6 +85,7 @@ func (h *Handler) adminListSkillVersions(w http.ResponseWriter, r *http.Request) // @Param skill_id path string true "Skill ID" // @Param version path string true "Concrete version number" // @Success 200 {object} v1.SkillVersion +// @Failure 400,401,404,500,503 {object} CoreErrorResponse // @Param project_id path string true "Project ID" // @Router /core/v1/projects/{project_id}/skills/{skill_id}/versions/{version} [get] func (h *Handler) adminGetSkillVersion(w http.ResponseWriter, r *http.Request) { @@ -94,6 +100,7 @@ func (h *Handler) adminGetSkillVersion(w http.ResponseWriter, r *http.Request) { // @Param skill_id path string true "Skill ID" // @Param version path string true "Concrete version number" // @Success 200 {object} v1.SkillVersionDeleted +// @Failure 400,401,404,500,503 {object} CoreErrorResponse // @Param project_id path string true "Project ID" // @Router /core/v1/projects/{project_id}/skills/{skill_id}/versions/{version} [delete] func (h *Handler) adminDeleteSkillVersion(w http.ResponseWriter, r *http.Request) { @@ -108,6 +115,7 @@ func (h *Handler) adminDeleteSkillVersion(w http.ResponseWriter, r *http.Request // @Param skill_id path string true "Skill ID" // @Param version path string true "Concrete version number" // @Success 200 {file} binary +// @Failure 400,401,404,500,503 {object} CoreErrorResponse // @Param project_id path string true "Project ID" // @Router /core/v1/projects/{project_id}/skills/{skill_id}/versions/{version}/content [get] func (h *Handler) adminSkillVersionContent(w http.ResponseWriter, r *http.Request) { diff --git a/services/agents-api/internal/api/agents.go b/services/agents-api/internal/api/agents.go index 77150d824..2a458b4ec 100644 --- a/services/agents-api/internal/api/agents.go +++ b/services/agents-api/internal/api/agents.go @@ -28,7 +28,7 @@ type AgentStore interface { // @Param OpenAI-Beta header string true "agents=v1" // @Param body body v1.CreateAgentRequest true "Reusable Agent configuration" // @Success 201 {object} v1.SavedAgent -// @Failure 400,401,413,500 {object} v1.ErrorResponse +// @Failure 400,401,413,500,503 {object} v1.ErrorResponse // @Router /agents [post] func (h *Handler) createAgent(w http.ResponseWriter, r *http.Request) { raw, ok := readJSONObject(w, r) @@ -70,7 +70,7 @@ func (h *Handler) createAgent(w http.ResponseWriter, r *http.Request) { // @Param OpenAI-Beta header string true "agents=v1" // @Param agent_id path string true "Agent ID" // @Success 200 {object} v1.SavedAgent -// @Failure 400,401,404,500 {object} v1.ErrorResponse +// @Failure 400,401,404,500,503 {object} v1.ErrorResponse // @Router /agents/{agent_id} [get] func (h *Handler) getAgent(w http.ResponseWriter, r *http.Request) { agent, err := h.lookupAgent(r.Context(), tenantID(r), chi.URLParam(r, "agent_id")) diff --git a/services/agents-api/internal/api/agents_delete.go b/services/agents-api/internal/api/agents_delete.go index 85b4d876b..e0279e9ad 100644 --- a/services/agents-api/internal/api/agents_delete.go +++ b/services/agents-api/internal/api/agents_delete.go @@ -17,7 +17,7 @@ import ( // @Param OpenAI-Beta header string true "agents=v1" // @Param agent_id path string true "Agent ID" // @Success 200 {object} v1.AgentDeleted -// @Failure 400,401,404,413,500 {object} v1.ErrorResponse +// @Failure 400,401,404,413,500,503 {object} v1.ErrorResponse // @Router /agents/{agent_id} [delete] func (h *Handler) deleteAgent(w http.ResponseWriter, r *http.Request) { body, ok := readJSONBody(w, r) diff --git a/services/agents-api/internal/api/agents_list.go b/services/agents-api/internal/api/agents_list.go index 8793d8666..8d347cd64 100644 --- a/services/agents-api/internal/api/agents_list.go +++ b/services/agents-api/internal/api/agents_list.go @@ -16,7 +16,7 @@ import ( // @Param limit query int64 false "Page size; 0 is treated as 1 and values above 100 as 100" minimum(0) default(20) // @Param order query string false "Creation order; omit for descending, explicit empty values are invalid" Enums(asc,desc) default(desc) // @Success 200 {object} v1.SavedAgentList -// @Failure 400,401,404,500 {object} v1.ErrorResponse +// @Failure 400,401,404,500,503 {object} v1.ErrorResponse // @Router /agents [get] func (h *Handler) listAgents(w http.ResponseWriter, r *http.Request) { options, ok := readClampedPage(w, r) diff --git a/services/agents-api/internal/api/agents_update.go b/services/agents-api/internal/api/agents_update.go index fddb61238..5a8a5448a 100644 --- a/services/agents-api/internal/api/agents_update.go +++ b/services/agents-api/internal/api/agents_update.go @@ -20,7 +20,7 @@ import ( // @Param agent_id path string true "Agent ID" // @Param body body v1.UpdateAgentRequest true "Supplied reusable Agent fields" // @Success 200 {object} v1.SavedAgent -// @Failure 400,401,404,413,500 {object} v1.ErrorResponse +// @Failure 400,401,404,413,500,503 {object} v1.ErrorResponse // @Router /agents/{agent_id} [post] func (h *Handler) updateAgent(w http.ResponseWriter, r *http.Request) { raw, ok := readJSONObject(w, r) diff --git a/services/agents-api/internal/api/credentials.go b/services/agents-api/internal/api/credentials.go index 068d9d6c4..8adfc5c35 100644 --- a/services/agents-api/internal/api/credentials.go +++ b/services/agents-api/internal/api/credentials.go @@ -88,7 +88,7 @@ func (h *Handler) createCredential(w http.ResponseWriter, r *http.Request) { // @Param vault_id path string true "Vault ID" // @Param credential_id path string true "Credential ID" // @Success 200 {object} v1.Credential -// @Failure 400,401,404,500 {object} v1.ErrorResponse +// @Failure 400,401,404,500,503 {object} v1.ErrorResponse // @Router /vaults/{vault_id}/credentials/{credential_id} [get] func (h *Handler) getCredential(w http.ResponseWriter, r *http.Request) { vaultID, ok := credentialResourceID(w, r, "vault_id") diff --git a/services/agents-api/internal/api/credentials_delete.go b/services/agents-api/internal/api/credentials_delete.go index 1981a78bc..10c8d7ec7 100644 --- a/services/agents-api/internal/api/credentials_delete.go +++ b/services/agents-api/internal/api/credentials_delete.go @@ -16,7 +16,7 @@ import ( // @Param vault_id path string true "Vault ID" // @Param credential_id path string true "Credential ID" // @Success 200 {object} v1.CredentialDeleted -// @Failure 400,401,404,413,500 {object} v1.ErrorResponse +// @Failure 400,401,404,413,500,503 {object} v1.ErrorResponse // @Router /vaults/{vault_id}/credentials/{credential_id} [delete] func (h *Handler) deleteCredential(w http.ResponseWriter, r *http.Request) { body, ok := readJSONBody(w, r) diff --git a/services/agents-api/internal/api/credentials_list.go b/services/agents-api/internal/api/credentials_list.go index 5619cc432..864a22151 100644 --- a/services/agents-api/internal/api/credentials_list.go +++ b/services/agents-api/internal/api/credentials_list.go @@ -19,7 +19,7 @@ import ( // @Param status query string false "Scalar status filter" Enums(active,archived) // @Param status[] query []string false "Array status filter; combined with status as a union" collectionFormat(multi) Enums(active,archived) // @Success 200 {object} v1.CredentialList -// @Failure 400,401,404,500 {object} v1.ErrorResponse +// @Failure 400,401,404,500,503 {object} v1.ErrorResponse // @Router /vaults/{vault_id}/credentials [get] func (h *Handler) listCredentials(w http.ResponseWriter, r *http.Request) { vaultID := credentialPathID(r, "vault_id") diff --git a/services/agents-api/internal/api/environment_executor_management.go b/services/agents-api/internal/api/environment_executor_management.go index c41b1de85..ee7f94aa6 100644 --- a/services/agents-api/internal/api/environment_executor_management.go +++ b/services/agents-api/internal/api/environment_executor_management.go @@ -112,7 +112,7 @@ func (h *Handler) listExecutorCredentials(w http.ResponseWriter, r *http.Request // @Param environment_id path string true "Environment UUID" // @Param body body api.EnvironmentExecutorCredentialRequest true "Request" // @Success 201 {object} store.IssuedExecutorCredential -// @Failure 400,401,404,409,500 {object} CoreErrorResponse +// @Failure 400,401,404,409,413,500 {object} CoreErrorResponse // @Router /core/v1/projects/{project_id}/environments/{environment_id}/executor-credentials [post] func (h *Handler) issueExecutorCredential(w http.ResponseWriter, r *http.Request, s EnvironmentExecutorStore) { // Check order: request body (400), target (404), archived Project (409), diff --git a/services/agents-api/internal/api/environment_installation.go b/services/agents-api/internal/api/environment_installation.go index 27d2d1666..a36d31097 100644 --- a/services/agents-api/internal/api/environment_installation.go +++ b/services/agents-api/internal/api/environment_installation.go @@ -91,7 +91,7 @@ func (h *Handler) installationAuthorization(w http.ResponseWriter, r *http.Reque // @Tags Native Installation // @Produce json // @Success 200 {object} v1.NativeInstallationContext -// @Failure 401,404,503 {object} CoreErrorResponse +// @Failure 401,404,500,503 {object} CoreErrorResponse // @Router /api/v1/agent-daemon/installation [post] func (h *Handler) prepareNativeInstallation(w http.ResponseWriter, r *http.Request) { _, claim, _, ok := h.installationAuthorization(w, r) @@ -126,7 +126,7 @@ type NativeInstallationClaim struct { // @Accept json // @Param body body api.NativeInstallationClaim true "Locally persisted executor secret" // @Success 204 -// @Failure 400,401,409,503 {object} CoreErrorResponse +// @Failure 400,401,409,413,500,503 {object} CoreErrorResponse // @Router /api/v1/agent-daemon/installation/claim [post] func (h *Handler) claimNativeInstallation(w http.ResponseWriter, r *http.Request) { s, _, token, ok := h.installationAuthorization(w, r) @@ -156,7 +156,7 @@ func (h *Handler) claimNativeInstallation(w http.ResponseWriter, r *http.Request // @Param project_id path string true "Project UUID" // @Param environment_id path string true "Environment UUID" // @Success 200 {object} v1.EnvironmentInstallation -// @Failure 401,404,409 {object} CoreErrorResponse +// @Failure 401,404,409,500 {object} CoreErrorResponse // @Router /core/v1/projects/{project_id}/environments/{environment_id}/installation [get] func (h *Handler) getEnvironmentInstallation(w http.ResponseWriter, r *http.Request) { binding, ok := h.adminProjectScope(w, r) diff --git a/services/agents-api/internal/api/environment_templates.go b/services/agents-api/internal/api/environment_templates.go index 105019546..6077922af 100644 --- a/services/agents-api/internal/api/environment_templates.go +++ b/services/agents-api/internal/api/environment_templates.go @@ -94,7 +94,7 @@ func readTemplateInput(w http.ResponseWriter, r *http.Request) (store.Environmen // @Param OpenAI-Beta header string true "agents=v1" // @Param body body v1.EnvironmentTemplateRequest true "Reusable configuration" // @Success 201 {object} v1.EnvironmentTemplate -// @Failure 400,401,413,500 {object} v1.ErrorResponse +// @Failure 400,401,413,500,503 {object} v1.ErrorResponse // @Router /agents/environments/templates [post] func (h *Handler) createEnvironmentTemplate(w http.ResponseWriter, r *http.Request) { in, ok := readTemplateInput(w, r) @@ -117,7 +117,7 @@ func (h *Handler) createEnvironmentTemplate(w http.ResponseWriter, r *http.Reque // @Param OpenAI-Beta header string true "agents=v1" // @Param environment_template_id path string true "Template ID" // @Success 200 {object} v1.EnvironmentTemplate -// @Failure 400,401,404,500 {object} v1.ErrorResponse +// @Failure 400,401,404,500,503 {object} v1.ErrorResponse // @Router /agents/environments/templates/{environment_template_id} [get] func (h *Handler) getEnvironmentTemplate(w http.ResponseWriter, r *http.Request) { value, err := h.store.GetEnvironmentTemplate(r.Context(), tenantID(r), chi.URLParam(r, "environment_template_id")) @@ -138,7 +138,7 @@ func (h *Handler) getEnvironmentTemplate(w http.ResponseWriter, r *http.Request) // @Param environment_template_id path string true "Template ID" // @Param body body v1.EnvironmentTemplateRequest true "Configuration replacements" // @Success 200 {object} v1.EnvironmentTemplate -// @Failure 400,401,404,413,500 {object} v1.ErrorResponse +// @Failure 400,401,404,413,500,503 {object} v1.ErrorResponse // @Router /agents/environments/templates/{environment_template_id} [post] func (h *Handler) updateEnvironmentTemplate(w http.ResponseWriter, r *http.Request) { in, ok := readTemplateInput(w, r) @@ -161,7 +161,7 @@ func (h *Handler) updateEnvironmentTemplate(w http.ResponseWriter, r *http.Reque // @Param OpenAI-Beta header string true "agents=v1" // @Param environment_template_id path string true "Template ID" // @Success 200 {object} v1.EnvironmentTemplateDeleted -// @Failure 400,401,404,500 {object} v1.ErrorResponse +// @Failure 400,401,404,500,503 {object} v1.ErrorResponse // @Router /agents/environments/templates/{environment_template_id} [delete] func (h *Handler) deleteEnvironmentTemplate(w http.ResponseWriter, r *http.Request) { id, err := h.store.DeleteEnvironmentTemplate(r.Context(), tenantID(r), chi.URLParam(r, "environment_template_id")) @@ -182,7 +182,7 @@ func (h *Handler) deleteEnvironmentTemplate(w http.ResponseWriter, r *http.Reque // @Param limit query integer false "Page size; 0 is treated as 1 and values above 100 as 100" default(20) minimum(0) // @Param order query string false "Creation order; omit for descending, explicit empty values are invalid" Enums(asc,desc) default(desc) // @Success 200 {object} v1.EnvironmentTemplateList -// @Failure 400,401,404,500 {object} v1.ErrorResponse +// @Failure 400,401,404,500,503 {object} v1.ErrorResponse // @Router /agents/environments/templates [get] func (h *Handler) listEnvironmentTemplates(w http.ResponseWriter, r *http.Request) { options, ok := readClampedPage(w, r) diff --git a/services/agents-api/internal/api/environments.go b/services/agents-api/internal/api/environments.go index e80c918bf..4d6bae9f2 100644 --- a/services/agents-api/internal/api/environments.go +++ b/services/agents-api/internal/api/environments.go @@ -18,7 +18,7 @@ import ( // @Param OpenAI-Beta header string true "agents=v1" // @Param environment_id path string true "Environment ID" // @Success 200 {object} v1.EnvironmentInfo -// @Failure 400,401,404,500 {object} v1.ErrorResponse +// @Failure 400,401,404,500,503 {object} v1.ErrorResponse // @Router /agents/environments/{environment_id} [get] func (h *Handler) getEnvironment(w http.ResponseWriter, r *http.Request) { environment, err := h.store.GetEnvironment(r.Context(), tenantID(r), chi.URLParam(r, "environment_id")) diff --git a/services/agents-api/internal/api/handler.go b/services/agents-api/internal/api/handler.go index dc3c51a26..d01561a4d 100644 --- a/services/agents-api/internal/api/handler.go +++ b/services/agents-api/internal/api/handler.go @@ -330,7 +330,7 @@ func (h *Handler) createSession(w http.ResponseWriter, r *http.Request) { // @Param OpenAI-Beta header string true "agents=v1" // @Param session_id path string true "Session ID" // @Success 200 {object} v1.Session -// @Failure 400,401,404,500 {object} v1.ErrorResponse +// @Failure 400,401,404,500,503 {object} v1.ErrorResponse // @Router /agents/sessions/{session_id} [get] func (h *Handler) getSession(w http.ResponseWriter, r *http.Request) { session, err := h.store.GetSession(r.Context(), tenantID(r), chi.URLParam(r, "session_id")) @@ -369,7 +369,7 @@ func (h *Handler) respondSessionStatus(w http.ResponseWriter, r *http.Request, s // @Param limit query int false "Page size; 0 is treated as 1 and values above 100 as 100" minimum(0) default(20) // @Param order query string false "Creation order; omit for descending, explicit empty values are invalid" Enums(asc,desc) default(desc) // @Success 200 {object} v1.SessionList -// @Failure 400,401,404,500 {object} v1.ErrorResponse +// @Failure 400,401,404,500,503 {object} v1.ErrorResponse // @Router /agents/sessions [get] func (h *Handler) listSessions(w http.ResponseWriter, r *http.Request) { options, ok := readClampedPage(w, r, "agent_id") diff --git a/services/agents-api/internal/api/harness_model_providers.go b/services/agents-api/internal/api/harness_model_providers.go index 51c132287..100c84f23 100644 --- a/services/agents-api/internal/api/harness_model_providers.go +++ b/services/agents-api/internal/api/harness_model_providers.go @@ -163,7 +163,7 @@ func requiredModelProviderShape() shape { // @Produce json // @Security DeploymentAdminAuth // @Param harness path string true "Harness" -// @Param body body v1.ModelConfigurationInput true "Complete model provider bundle" +// @Param body body v1.ModelConfigurationInput true "Complete model configuration" // @Success 200 {object} api.HarnessModelConfiguration // @Failure 400,401,404,413,500,503 {object} CoreErrorResponse // @Router /core/v1/harnesses/{harness}/model-configuration [put] diff --git a/services/agents-api/internal/api/items.go b/services/agents-api/internal/api/items.go index 119ad16a0..cd678dc6f 100644 --- a/services/agents-api/internal/api/items.go +++ b/services/agents-api/internal/api/items.go @@ -16,7 +16,7 @@ import ( // @Param limit query int false "Page size; 0 is treated as 1 and values above 100 as 100" minimum(0) default(20) // @Param order query string false "Creation order; omit for descending, explicit empty values are invalid" Enums(asc,desc) default(desc) // @Success 200 {object} v1.ItemList -// @Failure 400,401,404,500 {object} v1.ErrorResponse +// @Failure 400,401,404,500,503 {object} v1.ErrorResponse // @Router /agents/sessions/{session_id}/items [get] func (h *Handler) listItems(w http.ResponseWriter, r *http.Request) { options, ok := readClampedPage(w, r) diff --git a/services/agents-api/internal/api/project_api_keys.go b/services/agents-api/internal/api/project_api_keys.go index 84b329876..82d958f4b 100644 --- a/services/agents-api/internal/api/project_api_keys.go +++ b/services/agents-api/internal/api/project_api_keys.go @@ -131,7 +131,7 @@ func (h *Handler) listProjects(w http.ResponseWriter, r *http.Request) { // @Security DeploymentAdminAuth // @Param body body api.ProjectRequest true "Project display name" // @Success 201 {object} store.Project -// @Failure 400,401,409,500 {object} CoreErrorResponse +// @Failure 400,401,409,413,500 {object} CoreErrorResponse // @Router /core/v1/projects [post] func (h *Handler) createProject(w http.ResponseWriter, r *http.Request) { raw, ok := readJSONBodyLimit(w, r, 4096, "Project request is too large.") @@ -161,7 +161,7 @@ func (h *Handler) createProject(w http.ResponseWriter, r *http.Request) { // @Param project_id path string true "Project UUID" // @Param body body api.ProjectRequest true "Project display name" // @Success 200 {object} store.Project -// @Failure 400,401,404,409,500 {object} CoreErrorResponse +// @Failure 400,401,404,409,413,500 {object} CoreErrorResponse // @Router /core/v1/projects/{project_id} [post] func (h *Handler) renameProject(w http.ResponseWriter, r *http.Request) { binding, ok := h.adminProjectScope(w, r) @@ -243,7 +243,7 @@ func (h *Handler) listProjectAPIKeys(w http.ResponseWriter, r *http.Request) { // @Param project_id path string true "Project UUID" // @Param body body api.ProjectAPIKeyRequest true "Key display name" // @Success 201 {object} store.IssuedProjectAPIKey -// @Failure 400,401,404,409,500 {object} CoreErrorResponse +// @Failure 400,401,404,409,413,500 {object} CoreErrorResponse // @Router /core/v1/projects/{project_id}/keys [post] func (h *Handler) createProjectAPIKey(w http.ResponseWriter, r *http.Request) { binding, ok := h.adminProjectScope(w, r) diff --git a/services/agents-api/internal/api/sandbox_deployment_setup.go b/services/agents-api/internal/api/sandbox_deployment_setup.go index 5c06a104b..00671ccb2 100644 --- a/services/agents-api/internal/api/sandbox_deployment_setup.go +++ b/services/agents-api/internal/api/sandbox_deployment_setup.go @@ -80,7 +80,7 @@ func WithSandboxDeploymentChanges( // @Accept json // @Param body body api.SandboxDeploymentInput true "Deployment selection" // @Success 200 {object} store.RuntimeDeploymentView -// @Failure 400,401,409,500,503 {object} CoreErrorResponse +// @Failure 400,401,409,413,500,503 {object} CoreErrorResponse // @Router /core/v1/sandbox/deployment [post] func (h *Handler) initializeSandboxDeployment(w http.ResponseWriter, r *http.Request) { raw, ok := readJSONBody(w, r) @@ -115,7 +115,7 @@ func (h *Handler) initializeSandboxDeployment(w http.ResponseWriter, r *http.Req // @Accept json // @Param body body api.SandboxDeploymentChangeInput true "Replacement deployment selection" // @Success 200 {object} store.RuntimeDeploymentView -// @Failure 400,401,409,500,503 {object} CoreErrorResponse +// @Failure 400,401,409,413,500,503 {object} CoreErrorResponse // @Router /core/v1/sandbox/deployment [put] func (h *Handler) updateSandboxDeployment(w http.ResponseWriter, r *http.Request) { raw, ok := readJSONBody(w, r) @@ -150,7 +150,7 @@ func (h *Handler) updateSandboxDeployment(w http.ResponseWriter, r *http.Request // @Accept json // @Param body body store.SandboxResetRequest true "Reset mode and current deployment generation" // @Success 200 {object} store.RuntimeDeploymentView -// @Failure 400,401,409,500,503 {object} CoreErrorResponse +// @Failure 400,401,409,413,500,503 {object} CoreErrorResponse // @Router /core/v1/sandbox/deployment/reset [post] func (h *Handler) startSandboxReset(w http.ResponseWriter, r *http.Request) { raw, ok := readJSONBodyLimit(w, r, 4096, "Reset request is too large.") diff --git a/services/agents-api/internal/api/sandbox_e2b_discovery.go b/services/agents-api/internal/api/sandbox_e2b_discovery.go index 577852b67..9d9716600 100644 --- a/services/agents-api/internal/api/sandbox_e2b_discovery.go +++ b/services/agents-api/internal/api/sandbox_e2b_discovery.go @@ -33,7 +33,7 @@ func WithSandboxE2BDiscovery(discover func(context.Context, SandboxE2BDiscoveryI // @Security DeploymentAdminAuth // @Param body body api.SandboxE2BDiscoveryInput true "Transient E2B connection" // @Success 200 {object} api.SandboxE2BDiscoveryResult -// @Failure 400,401,503 {object} CoreErrorResponse +// @Failure 400,401,413,503 {object} CoreErrorResponse // @Router /core/v1/sandbox/e2b/templates [post] func (h *Handler) discoverSandboxE2BTemplates(w http.ResponseWriter, r *http.Request) { h.discoverSandboxE2B(w, r, "") @@ -48,7 +48,7 @@ func (h *Handler) discoverSandboxE2BTemplates(w http.ResponseWriter, r *http.Req // @Param template_id path string true "Template ID" // @Param body body api.SandboxE2BDiscoveryInput true "Transient E2B connection" // @Success 200 {object} api.SandboxE2BDiscoveryResult -// @Failure 400,401,503 {object} CoreErrorResponse +// @Failure 400,401,413,503 {object} CoreErrorResponse // @Router /core/v1/sandbox/e2b/templates/{template_id}/builds [post] func (h *Handler) discoverSandboxE2BBuilds(w http.ResponseWriter, r *http.Request) { h.discoverSandboxE2B(w, r, chi.URLParam(r, "template_id")) diff --git a/services/agents-api/internal/api/sandbox_manager.go b/services/agents-api/internal/api/sandbox_manager.go index d88883ce7..51d9ffd4e 100644 --- a/services/agents-api/internal/api/sandbox_manager.go +++ b/services/agents-api/internal/api/sandbox_manager.go @@ -110,7 +110,7 @@ func (h *Handler) sandboxNodes(w http.ResponseWriter, r *http.Request) { // @Accept json // @Param body body store.RuntimeNodeUpdate true "Request" // @Success 200 {object} api.SandboxMutationResponse -// @Failure 400,401,404,409,500,503 {object} CoreErrorResponse +// @Failure 400,401,404,409,413,500,503 {object} CoreErrorResponse // @Router /core/v1/sandbox/nodes/{node_id} [patch] func (h *Handler) updateSandboxNode(w http.ResponseWriter, r *http.Request) { raw, ok := readJSONBody(w, r) @@ -174,7 +174,7 @@ func (h *Handler) sandboxAllocations(w http.ResponseWriter, r *http.Request) { // @Accept json // @Param body body api.SandboxEnrollmentTokenRequest true "Request" // @Success 201 {object} api.SandboxEnrollmentToken -// @Failure 400,401,404,409,500,503 {object} CoreErrorResponse +// @Failure 400,401,404,409,413,500,503 {object} CoreErrorResponse // @Router /core/v1/sandbox/enrollment-tokens [post] func (h *Handler) createSandboxEnrollment(w http.ResponseWriter, r *http.Request) { raw, ok := readJSONBody(w, r) @@ -209,7 +209,7 @@ func (h *Handler) createSandboxEnrollment(w http.ResponseWriter, r *http.Request // @Accept json // @Param body body store.RuntimeNodeEnrollment true "Request" // @Success 201 {object} store.RuntimeNodeIdentity -// @Failure 400,401,404,409,500,503 {object} v1.ErrorResponse +// @Failure 400,401,404,409,413,500,503 {object} v1.ErrorResponse // @Router /api/v1/sandbox-node/enroll [post] func (h *Handler) enrollSandboxNode(w http.ResponseWriter, r *http.Request) { token, ok := sandboxBearer(r) diff --git a/services/agents-api/internal/api/session_deletion.go b/services/agents-api/internal/api/session_deletion.go index 48071f683..bef5d432d 100644 --- a/services/agents-api/internal/api/session_deletion.go +++ b/services/agents-api/internal/api/session_deletion.go @@ -18,7 +18,7 @@ import ( // @Param OpenAI-Beta header string true "agents=v1" // @Param session_id path string true "Session ID" // @Success 200 {object} v1.SessionDeleted -// @Failure 400,401,404,409,413,500 {object} v1.ErrorResponse +// @Failure 400,401,404,409,413,500,503 {object} v1.ErrorResponse // @Router /agents/sessions/{session_id} [delete] func (h *Handler) deleteSession(w http.ResponseWriter, r *http.Request) { body, ok := readJSONBody(w, r) diff --git a/services/agents-api/internal/api/session_metadata.go b/services/agents-api/internal/api/session_metadata.go index 718eaecd8..674afbed0 100644 --- a/services/agents-api/internal/api/session_metadata.go +++ b/services/agents-api/internal/api/session_metadata.go @@ -23,7 +23,7 @@ import ( // @Param session_id path string true "Session ID" // @Param body body v1.UpdateSessionRequest true "Session metadata" // @Success 200 {object} v1.Session -// @Failure 400,401,404,413,500 {object} v1.ErrorResponse +// @Failure 400,401,404,413,500,503 {object} v1.ErrorResponse // @Router /agents/sessions/{session_id} [post] func (h *Handler) updateSession(w http.ResponseWriter, r *http.Request) { raw, ok := readJSONObject(w, r) diff --git a/services/agents-api/internal/api/skills.go b/services/agents-api/internal/api/skills.go index ae326fb1c..b37a6a977 100644 --- a/services/agents-api/internal/api/skills.go +++ b/services/agents-api/internal/api/skills.go @@ -57,6 +57,7 @@ func (h *Handler) skillsReady(w http.ResponseWriter) bool { // @Security BearerAuth // @Param skill_id path string true "Skill ID" // @Success 200 {object} v1.Skill +// @Failure 400,401,404,500,503 {object} v1.ErrorResponse // @Router /skills/{skill_id} [get] func (h *Handler) getSkill(w http.ResponseWriter, r *http.Request) { if !h.skillsReady(w) { @@ -79,6 +80,7 @@ func (h *Handler) getSkill(w http.ResponseWriter, r *http.Request) { // @Param skill_id path string true "Skill ID" // @Param body body v1.SkillUpdateRequest true "Default version" // @Success 200 {object} v1.Skill +// @Failure 400,401,404,413,500,503 {object} v1.ErrorResponse // @Router /skills/{skill_id} [post] func (h *Handler) updateSkill(w http.ResponseWriter, r *http.Request) { if !h.skillsReady(w) { @@ -108,6 +110,7 @@ func (h *Handler) updateSkill(w http.ResponseWriter, r *http.Request) { // @Security BearerAuth // @Param skill_id path string true "Skill ID" // @Success 200 {object} v1.SkillDeleted +// @Failure 400,401,404,500,503 {object} v1.ErrorResponse // @Router /skills/{skill_id} [delete] func (h *Handler) deleteSkill(w http.ResponseWriter, r *http.Request) { if !h.skillsReady(w) { @@ -128,6 +131,7 @@ func (h *Handler) deleteSkill(w http.ResponseWriter, r *http.Request) { // @Param skill_id path string true "Skill ID" // @Param version path string true "Concrete version number" // @Success 200 {object} v1.SkillVersion +// @Failure 400,401,404,500,503 {object} v1.ErrorResponse // @Router /skills/{skill_id}/versions/{version} [get] func (h *Handler) getSkillVersion(w http.ResponseWriter, r *http.Request) { if !h.skillsReady(w) { @@ -149,6 +153,7 @@ func (h *Handler) getSkillVersion(w http.ResponseWriter, r *http.Request) { // @Param skill_id path string true "Skill ID" // @Param version path string true "Concrete version number" // @Success 200 {object} v1.SkillVersionDeleted +// @Failure 400,401,404,500,503 {object} v1.ErrorResponse // @Router /skills/{skill_id}/versions/{version} [delete] func (h *Handler) deleteSkillVersion(w http.ResponseWriter, r *http.Request) { if !h.skillsReady(w) { diff --git a/services/agents-api/internal/api/skills_list.go b/services/agents-api/internal/api/skills_list.go index 85ba28d11..5e0975a01 100644 --- a/services/agents-api/internal/api/skills_list.go +++ b/services/agents-api/internal/api/skills_list.go @@ -16,6 +16,7 @@ import ( // @Param limit query integer false "Page size; 0 returns an empty page" default(20) minimum(0) maximum(100) // @Param order query string false "Creation order; omit for descending, explicit empty values are invalid" Enums(asc,desc) // @Success 200 {object} v1.SkillList +// @Failure 400,401,404,500,503 {object} v1.ErrorResponse // @Router /skills [get] func (h *Handler) listSkills(w http.ResponseWriter, r *http.Request) { if !h.skillsReady(w) { @@ -51,6 +52,7 @@ func (h *Handler) listSkills(w http.ResponseWriter, r *http.Request) { // @Param limit query integer false "Page size; 0 returns an empty page" default(20) minimum(0) maximum(100) // @Param order query string false "Version order; omit for descending, explicit empty values are invalid" Enums(asc,desc) // @Success 200 {object} v1.SkillVersionList +// @Failure 400,401,404,500,503 {object} v1.ErrorResponse // @Router /skills/{skill_id}/versions [get] func (h *Handler) listSkillVersions(w http.ResponseWriter, r *http.Request) { if !h.skillsReady(w) { diff --git a/services/agents-api/internal/api/skills_transfer.go b/services/agents-api/internal/api/skills_transfer.go index 70b748897..0e41bc5bc 100644 --- a/services/agents-api/internal/api/skills_transfer.go +++ b/services/agents-api/internal/api/skills_transfer.go @@ -21,6 +21,7 @@ import ( // @Security BearerAuth // @Param files formData file true "Skill ZIP or directory files" // @Success 200 {object} v1.Skill +// @Failure 400,401,413,500,503 {object} v1.ErrorResponse // @Router /skills [post] func (h *Handler) createSkill(w http.ResponseWriter, r *http.Request) { h.uploadSkill(w, r, false) } @@ -33,6 +34,7 @@ func (h *Handler) createSkill(w http.ResponseWriter, r *http.Request) { h.upload // @Param files formData file true "Skill ZIP or directory files" // @Param default formData boolean false "Set as default" // @Success 200 {object} v1.SkillVersion +// @Failure 400,401,404,413,500,503 {object} v1.ErrorResponse // @Router /skills/{skill_id}/versions [post] func (h *Handler) createSkillVersion(w http.ResponseWriter, r *http.Request) { h.uploadSkill(w, r, true) @@ -85,6 +87,7 @@ func (h *Handler) uploadSkill(w http.ResponseWriter, r *http.Request, version bo // @Security BearerAuth // @Param skill_id path string true "Skill ID" // @Success 200 {file} binary +// @Failure 400,401,404,500,503 {object} v1.ErrorResponse // @Router /skills/{skill_id}/content [get] func (h *Handler) skillContent(w http.ResponseWriter, r *http.Request) { if !h.skillsReady(w) { @@ -113,6 +116,7 @@ func (h *Handler) skillContent(w http.ResponseWriter, r *http.Request) { // @Param skill_id path string true "Skill ID" // @Param version path string true "Concrete version number" // @Success 200 {file} binary +// @Failure 400,401,404,500,503 {object} v1.ErrorResponse // @Router /skills/{skill_id}/versions/{version}/content [get] func (h *Handler) skillVersionContent(w http.ResponseWriter, r *http.Request) { h.skillContent(w, r) diff --git a/services/agents-api/internal/api/turns.go b/services/agents-api/internal/api/turns.go index 4f51d676b..a0f2bdfa5 100644 --- a/services/agents-api/internal/api/turns.go +++ b/services/agents-api/internal/api/turns.go @@ -20,7 +20,7 @@ import ( // @Param session_id path string true "Session ID" // @Param turn_id path string true "Turn ID" // @Success 200 {object} v1.Turn -// @Failure 400,401,404,500 {object} v1.ErrorResponse +// @Failure 400,401,404,500,503 {object} v1.ErrorResponse // @Router /agents/sessions/{session_id}/turns/{turn_id} [get] func (h *Handler) getTurn(w http.ResponseWriter, r *http.Request) { sessionID := chi.URLParam(r, "session_id") @@ -53,7 +53,7 @@ func (h *Handler) getTurn(w http.ResponseWriter, r *http.Request) { // @Param limit query int false "Page size" minimum(1) maximum(100) default(20) // @Param order query string false "Creation order; omit for descending, explicit empty values are invalid" Enums(asc,desc) default(desc) // @Success 200 {object} v1.TurnList -// @Failure 400,401,404,500 {object} v1.ErrorResponse +// @Failure 400,401,404,500,503 {object} v1.ErrorResponse // @Router /agents/sessions/{session_id}/turns [get] func (h *Handler) listTurns(w http.ResponseWriter, r *http.Request) { options, ok := readPage(w, r) diff --git a/services/agents-api/internal/api/vaults.go b/services/agents-api/internal/api/vaults.go index 90b547435..7be8d2591 100644 --- a/services/agents-api/internal/api/vaults.go +++ b/services/agents-api/internal/api/vaults.go @@ -29,7 +29,7 @@ type VaultStore interface { // @Param OpenAI-Beta header string true "agents=v1" // @Param body body v1.CreateVaultRequest true "Vault name and metadata" // @Success 201 {object} v1.Vault -// @Failure 400,401,413,500 {object} v1.ErrorResponse +// @Failure 400,401,413,500,503 {object} v1.ErrorResponse // @Router /vaults [post] func (h *Handler) createVault(w http.ResponseWriter, r *http.Request) { raw, ok := readJSONObject(w, r) @@ -89,7 +89,7 @@ func (h *Handler) createVault(w http.ResponseWriter, r *http.Request) { // @Param OpenAI-Beta header string true "agents=v1" // @Param vault_id path string true "Vault ID" // @Success 200 {object} v1.Vault -// @Failure 400,401,404,500 {object} v1.ErrorResponse +// @Failure 400,401,404,500,503 {object} v1.ErrorResponse // @Router /vaults/{vault_id} [get] func (h *Handler) getVault(w http.ResponseWriter, r *http.Request) { id := chi.URLParam(r, "vault_id") diff --git a/services/agents-api/internal/api/vaults_delete.go b/services/agents-api/internal/api/vaults_delete.go index c67367713..ac84910f1 100644 --- a/services/agents-api/internal/api/vaults_delete.go +++ b/services/agents-api/internal/api/vaults_delete.go @@ -15,7 +15,7 @@ import ( // @Param OpenAI-Beta header string true "agents=v1" // @Param vault_id path string true "Vault ID" // @Success 200 {object} v1.VaultDeleted -// @Failure 400,401,404,413,500 {object} v1.ErrorResponse +// @Failure 400,401,404,413,500,503 {object} v1.ErrorResponse // @Router /vaults/{vault_id} [delete] func (h *Handler) deleteVault(w http.ResponseWriter, r *http.Request) { body, ok := readJSONBody(w, r) diff --git a/services/agents-api/internal/api/vaults_list.go b/services/agents-api/internal/api/vaults_list.go index 56c8ae6ad..496e39c4e 100644 --- a/services/agents-api/internal/api/vaults_list.go +++ b/services/agents-api/internal/api/vaults_list.go @@ -18,7 +18,7 @@ import ( // @Param status query string false "Scalar status filter" Enums(active,archived) // @Param status[] query []string false "Array status filter; combined with status as a union" collectionFormat(multi) Enums(active,archived) // @Success 200 {object} v1.VaultList -// @Failure 400,401,404,500 {object} v1.ErrorResponse +// @Failure 400,401,404,500,503 {object} v1.ErrorResponse // @Router /vaults [get] func (h *Handler) listVaults(w http.ResponseWriter, r *http.Request) { options, statuses, ok := readVaultPage(w, r) From 0c2a9367a0110326308fc480fc2e480576910b1a Mon Sep 17 00:00:00 2001 From: Yao Date: Tue, 29 Sep 2026 23:19:32 +0800 Subject: [PATCH 02/14] test: check the error code registry against emitted codes Add contracts/agents-api/error-codes.md, which lists every error code Core, the console (including the installer rejections it relays for managed HTTPS setup) and the daemon transport write, and separates them from node diagnostics, Session diagnostic categories, Runtime protocol result codes and client-generated codes. contract_conformance_test.go requires every registry row to be written somewhere, every written status and code to have a row, and every annotated operation to declare the statuses its handler writes. core_resource_errors_test.go pins the Beta error fields of the Core Files and Skills routes. Link the registry from the Core error, admin, executor credential contracts and the API index. --- contracts/agents-api/admin-api.md | 27 +- contracts/agents-api/core-errors.md | 7 +- .../environment-executor-credentials.md | 4 + contracts/agents-api/error-codes.md | 278 ++++++ docs/api/README.md | 21 +- .../internal/api/contract_conformance_test.go | 806 ++++++++++++++++++ .../internal/api/core_resource_errors_test.go | 98 +++ 7 files changed, 1237 insertions(+), 4 deletions(-) create mode 100644 contracts/agents-api/error-codes.md create mode 100644 services/agents-api/internal/api/contract_conformance_test.go create mode 100644 services/agents-api/internal/api/core_resource_errors_test.go diff --git a/contracts/agents-api/admin-api.md b/contracts/agents-api/admin-api.md index 87b6b6b5c..d9ddf21ce 100644 --- a/contracts/agents-api/admin-api.md +++ b/contracts/agents-api/admin-api.md @@ -66,9 +66,34 @@ unusable key before issuing another; plaintext cannot be recovered. Paths below are relative to `/projects/{project_id}`. The Project selects a tenant, including an archived Project; it does not authenticate. Shared resource handlers preserve their -public object serialization, pagination, errors and deletion preconditions. They +public object serialization, cursors, ordering and deletion preconditions; Skill +list bounds differ as the table below shows. They receive an explicit target tenant, not a fabricated caller identity. +Errors use the [Core envelope](core-errors.md). The shared list parser and +not-found mapping choose their error fields by request path, so every Core +resource route gets the Agents API Beta fields for those cases. For Agents, +Templates, Vaults, Credentials and Sessions this is the same family their `/v1` +routes use. Files and Skills differ: their `/v1` routes keep the separately +observed Files and Skills fields ([list query semantics](list-query-semantics.md)), +which the Core routes do not reproduce. Errors a handler writes directly keep +their `/v1` fields on both namespaces: an unknown Files `purpose` filter is 400 +with a null code and param `purpose`, and deleting the default Skill version is +400 `invalid_value` with param `version`. + +| Case | `/v1/files`, `/v1/skills` | Core `/files`, `/skills` | +| --- | --- | --- | +| Missing resource | 404, null `code` (Files: param `id`) | 404, `not_found_error` (Files: param `id`) | +| Unresolved Skill version `after` | 400 `invalid_value`, param `after` | 400 `invalid_request_error`, null param | +| Repeated list key | Files 400 `unsupported_parameter`; Skills 400 `duplicate_parameter` with the key as param | 400 `invalid_request_error`, null param | +| Invalid `order` | Files 400 with null `code`; Skills 400 `invalid_value`, param `order` | 400 `invalid_request_error`, null param | +| `limit` out of range | Files 400 with null `code`; Skills `integer_below_min_value` or `integer_above_max_value`, param `limit` | 400 `invalid_request_error`, null param | +| Skills `limit=0` | Empty page | 400 `invalid_request_error`; Core Skill lists accept 1–100 | + +Storage availability codes are the same on both namespaces: `file_storage_unavailable`, +`skill_storage_unavailable` and `file_transfer_unavailable` (503). The +[error code registry](error-codes.md) lists every code. + | Resource | GET routes | DELETE routes | | --- | --- | --- | | Agents | `/agents`, `/agents/{agent_id}` | `/agents/{agent_id}` | diff --git a/contracts/agents-api/core-errors.md b/contracts/agents-api/core-errors.md index 774123304..c3338c28a 100644 --- a/contracts/agents-api/core-errors.md +++ b/contracts/agents-api/core-errors.md @@ -50,7 +50,8 @@ through the proxy; the console does not reinterpret their codes or details. The first three use `type: "invalid_request_error"`; the last uses `type: "server_error"`. A Core `401 invalid_admin_key` remains distinguishable from a missing console sign-in. `/console/auth` keeps its existing -`{"error":"…"}` errors. Bare, retired and direct public/machine paths do not +`{"error":"…"}` errors without a code; their statuses are listed under +[console sign-in responses](error-codes.md#console-sign-in-responses). Bare, retired and direct public/machine paths do not become proxyable operations. Host, origin, authentication, credential stripping, path checks and the no-retry rule are unchanged. @@ -185,3 +186,7 @@ Model configuration writes additionally return `model_configuration_model_invali with `param: model`, or `harness_config_invalid` with `param: harness_config`. Both carry fixed messages without submitted values. Existing provider field errors retain their field params within the `model_provider` object. + +The [error code registry](error-codes.md) lists every code Core and the console +write, separates them from node diagnostics and client-generated codes, and is +checked against the code in both directions. diff --git a/contracts/agents-api/environment-executor-credentials.md b/contracts/agents-api/environment-executor-credentials.md index e9f8a185f..e91670d61 100644 --- a/contracts/agents-api/environment-executor-credentials.md +++ b/contracts/agents-api/environment-executor-credentials.md @@ -130,6 +130,10 @@ When Core permanently rejects enrollment or the WebSocket, the daemon reports th reason and parks without retrying until stopped. A protocol mismatch requires the matching current distribution; it does not trigger a migration. Transient transport failures retain the existing reconnect behavior and never replay execution. +Enrollment and the connection check answer failures with a plain-text status body +and no error code, so the daemon decides by status alone; the WebSocket and +bootstrap handlers answer the failures they detect with +`{"error":"","detail":"…"}` ([registry](error-codes.md#runtime-daemon-transport-codes)). Rotate the same `key_id`, stop the daemon, replace the configured credential JSON file, and start it again. Issuing a new key for an enrolled Environment fails with diff --git a/contracts/agents-api/error-codes.md b/contracts/agents-api/error-codes.md new file mode 100644 index 000000000..b84921b23 --- /dev/null +++ b/contracts/agents-api/error-codes.md @@ -0,0 +1,278 @@ +# Error codes + +This registry lists every error `code` Core, the console (including the +installer rejections it relays) and the daemon transport write, the response shapes that carry no code, and the codes the +TypeScript client creates itself. Operation-specific triggers and `param` values +stay in the resource contracts; this page says what each code means and where it +can appear. + +Two checks compare it with the code. `contract_conformance_test.go` in +`services/agents-api/internal/api` requires the status and code of every row to +be written somewhere and every written status and code to have a row, and the +statuses of the uncoded tables to equal the statuses their handlers write. +`apps/docs/scripts/verify-error-codes.mjs` does the same for client-generated +codes and for every code the client and Web compare against. The Namespaces and +Meaning columns are maintained by review. + +## Which "code" is meant + +The word names seven different things. Only the first three are HTTP error codes. + +| Layer | Where it appears | Examples | Reference | +| --- | --- | --- | --- | +| API envelope | `error.code` of a `/v1`, `/core/v1` or `/api/v1` JSON error, or of an event stream `error` frame | `invalid_request_error`, `project_archived`, `stream_interrupted` | [Agents API and Core API codes](#agents-api-and-core-api-codes), [event stream codes](#event-stream-error-codes) | +| Console envelope | `error.code` of an error Web's server writes for `/core/*` | `console_sign_in_required`, `core_unreachable` | [Console codes](#console-codes), [Core errors](core-errors.md) | +| Daemon transport | `error` member of an `/api/v1/agent-daemon/*` JSON error | `missing_bearer`, `incompatible_version` | [Runtime daemon transport codes](#runtime-daemon-transport-codes) | +| Runtime protocol result | `error_code` of a Core–Runtime message after connection, such as a workspace, preparation or cancellation result; Core validates each value against its message and maps it to its own outcome or stored cause; no API response returns it | `write_rejected`, `read_unconfirmed`, `cancel_timeout` | [Core–Runtime protocol](../../docs/runtime-protocol.md) and its typed payloads; not listed here | +| Node diagnostic | `diagnostic` value inside a node payload; never an HTTP status | `docker_unavailable`, `kvm_unavailable` | [Sandbox deployment](sandbox-deployment.md), [nodes](../../docs/getting-started/nodes.md) | +| Session diagnostic category | `code` of a failure category inside a successful Session diagnostics snapshot | `harness_error`, `runtime_disconnected` | [Diagnostic failure categories](core-errors.md#diagnostic-failure-categories) | +| Client identifier | `AgentCoreError.code` created by `packages/agents-client` without a response, or a local daemon/adapter error | `sandbox_configuration_unconfirmed`, `invalid_admin_response` | [Client-generated codes](#client-generated-codes), daemon and adapter guides | + +`error.type` is not a second code. It follows one rule: `server_error` for any 5xx, +`conflict_error` for any 409, `not_found_error` or `invalid_beta` when the code is +that value, and `invalid_request_error` otherwise. + +## Agents API and Core API codes + +`/v1`, `/core/v1` and `/api/v1` share one writer, so a code keeps its meaning in +every namespace. `/core/v1` adds optional `details` ([Core errors](core-errors.md)). +Clients branch on `code`, never on `message`. A `null` row is a response whose +`code` is null. + +| Status | Code | Namespaces | Meaning | +| --- | --- | --- | --- | +| 400 | `invalid_request_error` | all | Request validation failed: body fields, list queries on Agents API Beta lists and on the Core resource lists under `/projects/{project_id}`, cursors, MCP credential selection or unstorable text. `param` names the field when known | +| 400 | `invalid_request` | all | Malformed body, identifier or local request limit outside the official fields, including invalid queries on the Core Project, key, audit log and summary lists | +| 400 | `invalid_value` | `/v1`, `/core/v1` | Skills: invalid `order` or Skill version `after` on `/v1`; on both namespaces, deletion of the default Skill version (param `version`) | +| 400 | `duplicate_parameter` | `/v1` | Skills list key supplied more than once; `param` is the key | +| 400 | `integer_below_min_value` | `/v1` | Skills list `limit` below 0 | +| 400 | `integer_above_max_value` | `/v1` | Skills list `limit` above 100 | +| 400 | `unsupported_parameter` | `/v1`, `/core/v1` | A body on a deletion that accepts none, a repeated Files list key, or query parameters Runtime observation and history reads do not accept | +| 400 | `invalid_beta` | `/v1` | Missing or wrong `OpenAI-Beta: agents=v1` on an Agents API Beta route | +| 400 | `unsupported_or_invalid_configuration` | `/v1` | The configuration or input is outside what the selected harness supports | +| 400 | `model_provider_required` | `/v1` | The Session resolved no model provider and cannot run | +| 400 | `invalid_sandbox_configuration` | `/core/v1` | Sandbox deployment configuration is invalid | +| 400 | `invalid_name` | `/core/v1` | A Project, key or node name fails its length or character rules; `details.max_length` gives the limit | +| 400 | `invalid_node_capacity` | `/core/v1` | Node `max_active` or `max_retained` is outside 1-1000000, or retained is below active | +| 400 | `invalid_model_provider` | `/core/v1` | The model configuration body is missing or malformed; a complete bundle is required | +| 400 | `model_provider_base_url_invalid` | `/core/v1` | `base_url` is not HTTPS, or carries credentials, a query or a fragment | +| 400 | `model_provider_protocol_unsupported` | `/core/v1` | The protocol is unknown or unsupported by the harness; `details.allowed_protocols` lists the supported ones | +| 400 | `model_provider_api_key_invalid` | `/core/v1` | The key is empty, longer than 16384 characters or contains a prohibited character | +| 400 | `model_provider_token_limits_invalid` | `/core/v1` | `context_window` or `max_output_tokens` is invalid, or missing where the harness requires it | +| 400 | `model_configuration_model_invalid` | `/core/v1` | `model` is not a nonempty model identifier | +| 400 | `harness_config_invalid` | `/core/v1` | `harness_config` contains unsupported or invalid native model parameters | +| 400 | `e2b_api_key_invalid` | `/core/v1` | E2B rejected the API key (param `e2b.api_key`) | +| 400 | `e2b_template_build_invalid` | `/core/v1` | The E2B template build is not a ready immutable build with matching resources (param `e2b.template`) | +| 400 | null | `/v1`, `/core/v1` | Files list range and order errors on `/v1`, an unknown Files `purpose` filter (param `purpose`) on both namespaces, and public download of a `user_data` File | +| 401 | `invalid_api_key` | `/v1` | Files or Skills rejected a supplied Bearer Project API key | +| 401 | `invalid_admin_key` | `/core/v1` | The Core key is missing or wrong | +| 401 | `invalid_node_credential` | `/api/v1` | The node enrollment token or node credential is missing or wrong | +| 401 | `installation_authorization_invalid` | `/api/v1` | The native installation authorization is invalid or expired; get a new command from the Session | +| 401 | null | `/v1` | No valid Bearer Project API key on an Agents API Beta route, or none supplied to Files or Skills | +| 404 | `not_found_error` | `/v1`, `/core/v1` | The resource does not exist in the caller's or the selected Project's tenant | +| 404 | `not_found` | `/core/v1` | Unknown Core operation, unknown harness, or a harness without a deployment default model provider | +| 404 | `unsupported_operation` | `/v1` | Unknown `/v1` operation | +| 404 | null | `/v1` | Missing File or Skill on the public Files and Skills routes | +| 405 | `unsupported_operation` | all | Method not allowed, including HEAD on content downloads and Runtime reads | +| 409 | `conflict_error` | `/v1`, `/core/v1` | Official conflicts: Session not idle for deletion, pending input, MCP credential ambiguity, hosted environment failure or a different tool result | +| 409 | `turn_conflict` | `/v1` | The Turn cannot accept this input in its current state | +| 409 | `idempotency_conflict` | `/v1` | The Idempotency-Key was used with different input | +| 409 | `environment_unavailable` | `/v1` | The Environment no longer accepts new input | +| 409 | `environment_input_expired` | `/v1` | The Environment input deadline passed before admission | +| 409 | `environment_input_cancelled` | `/v1` | The Environment input was cancelled before admission | +| 409 | `project_exists` | `/core/v1` | The Project ID already exists | +| 409 | `project_api_key_exists` | `/core/v1` | The API key ID already exists; list its metadata and revoke it if the secret was not saved | +| 409 | `project_archived` | `/core/v1` | The target Project is archived | +| 409 | `executor_credential_exists` | `/core/v1` | The executor key ID already exists; rotate it explicitly to replace the secret | +| 409 | `runtime_history_unsupported` | `/core/v1` | Runtime history is not supported for this Session | +| 409 | `sandbox_deployment_conflict` | `/core/v1`, `/api/v1` | The sandbox deployment cannot change in its current state | +| 409 | `sandbox_configuration_error` | `/core/v1` | The deployment cannot be served as configured, for example E2B with a loopback public URL | +| 409 | `sandbox_node_address_mismatch` | `/core/v1`, `/api/v1` | The node uses a different Core address than the installation public URL | +| 409 | `sandbox_specification_mismatch` | `/core/v1`, `/api/v1` | The node's resource limits or Runtime release do not match the active deployment | +| 409 | `runtime_node_in_use` | `/core/v1` | The node still holds allocations, snapshots, reservations or pending cleanup | +| 409 | `runtime_local_node_configured` | `/core/v1` | The local node is enabled in deployment configuration and cannot be removed | +| 409 | `sandbox_generation_stale` | `/core/v1` | The deployment generation changed; `details.current_generation` gives the new one. Refresh before submitting again | +| 409 | `sandbox_reset_required` | `/core/v1` | The change needs a reset first, such as another backend or E2B team; `details` names both providers | +| 409 | `sandbox_in_use` | `/core/v1` | Hosted sandbox resources still belong to the deployment; `details.allocations` and `details.pending` count them | +| 409 | `sandbox_reset_in_progress` | `/core/v1` | A sandbox reset is in progress, so the deployment cannot change | +| 409 | `sandbox_not_configured` | `/core/v1` | The operation needs a configured sandbox deployment | +| 409 | `e2b_team_mismatch` | `/core/v1` | The E2B key cannot manage the retained deployment; reset before changing teams (param `e2b.api_key`) | +| 413 | `request_too_large` | all | The body exceeds the operation's limit, or an uploaded File or Skill exceeds its content limit | +| 500 | `internal_error` | all | An unexpected persistence failure; no detail is exposed | +| 503 | `authentication_unavailable` | `/v1` | Project API key authentication is temporarily unavailable; written before any operation runs | +| 503 | `execution_unavailable` | `/v1`, `/core/v1` | Execution is not available on this service, or a Core Runtime observation list exceeded its request budget | +| 503 | `stream_unavailable` | `/v1` | Live events or streaming creation are unavailable | +| 503 | `credential_storage_unavailable` | `/v1`, `/core/v1` | Credential encryption is not configured | +| 503 | `file_storage_unavailable` | `/v1`, `/core/v1` | Source File storage is not configured | +| 503 | `file_transfer_unavailable` | `/v1`, `/core/v1` | The bounded transfer deadline cannot be set for an upload or download | +| 503 | `skill_storage_unavailable` | `/v1`, `/core/v1` | Skill storage is not configured | +| 503 | `artifact_storage_unavailable` | `/v1`, `/core/v1` | Artifact storage is not configured | +| 503 | `subagent_storage_unavailable` | `/v1` | Subagent storage is not configured | +| 503 | `execution_configuration_unavailable` | `/core/v1` | Session execution configuration cannot be read | +| 503 | `runtime_history_unavailable` | `/core/v1` | Durable Runtime history is not configured or temporarily unavailable | +| 503 | `core_metrics_unavailable` | `/core/v1` | Core metrics are not configured or could not be read | +| 503 | `runtime_node_unavailable` | `/core/v1`, `/api/v1` | The selected sandbox node is unavailable or has no capacity | +| 503 | `sandbox_credential_unavailable` | `/core/v1`, `/api/v1` | Sandbox credentials cannot be decrypted; check the service credential encryption configuration | +| 503 | `sandbox_reset_in_progress` | `/v1` | Hosted admission is paused while a sandbox reset runs; nothing was admitted | +| 503 | `sandbox_nodes_preparing` | `/v1` | The nodes with free capacity are still preparing the deployment's Runtime | +| 503 | `e2b_request_unconfirmed` | `/core/v1` | E2B verification could not be confirmed; nothing is replayed | +| 503 | `provider_unavailable` | `/core/v1` | E2B template discovery is unavailable; check the credential, endpoint and connection | +| 503 | `diagnostics_unavailable` | `/core/v1` | The Session diagnostics reader is not configured | +| 503 | `installation_unavailable` | `/api/v1` | Matching native installation artifacts are unavailable on this Core | + +The namespace column shows where each code is expected. Codes from the shared +stored-error mapping can appear on any operation whose storage reports that +condition. No 503 carries `Retry-After`. + +Core's reverse-path canonicalization answers a path that cannot be decoded with a +plain-text 400 before any namespace is selected; a parsed request path always +decodes, so this is not expected in practice. + +## Event stream error codes + +A live event stream has already answered 200. Core reports its own interruption +as an `event: error` frame whose `error` object has `code`, `type` and `message` +but no `param`; see [history, events and usage](history-events-usage.md). + +| Status | Code | Meaning | +| --- | --- | --- | +| 200 | `stream_interrupted` | The live stream was interrupted; reconnect, then read the Session and its saved Items to recover | + +## Console codes + +Web's server writes these for `/core/*` requests it rejects before forwarding, +and for the console-local `POST /console/installation/domain` HTTPS setup request. +See [Core errors](core-errors.md#console-generated-failures) and +[Web request boundaries](../../docs/web/architecture.md#request-boundaries). + +| Status | Code | Meaning | +| --- | --- | --- | +| 400 | `console_request_invalid` | Request path, method or upgrade is unsafe | +| 400 | `domain_setup_unavailable` | Domain setup: this installation uses an external reverse proxy, so HTTPS is configured there | +| 400 | `invalid_request` | Domain setup: the request body exceeds 2 KiB | +| 401 | `console_sign_in_required` | Console session is missing or expired | +| 403 | `console_origin_rejected` | Host, Origin or Fetch Metadata checks failed | +| 502 | `core_unreachable` | Core transport failed or Core tried to redirect | +| 502 | `installation_unreachable` | Domain setup: the installer did not answer or returned an invalid or 5xx response; run `oac status` on the server | + +## Installation domain setup codes + +`POST /console/installation/domain` relays these installer rejections unchanged +in `{"error":{"code":"…","message":"…"}}`. The installation controller in +`deploy/install/ingress.py` writes them; see [Web management](../../docs/api/web-management.md) +and the [installer contract](../../docs/maintainers.md#managed-https-ownership). +Failures after the `202` acceptance are reported through the status `message`, +not as codes. This table is maintained by review. + +| Status | Code | Meaning | +| --- | --- | --- | +| 400 | `domain_setup_unavailable` | Managed HTTPS needs a combined Docker installation | +| 400 | `invalid_hostname` | The installer's hostname validation rejected the value | +| 400 | `invalid_confirmation` | `confirm_public_url_change` does not equal the new HTTPS URL | +| 400 | `invalid_request` | The body is missing, larger than 2 KiB, not JSON or has other members | +| 401 | `unauthorized` | The installer rejected the console's Core key | +| 409 | `configuration_pending` | `config.json` has pending edits; apply or revert them first | +| 409 | `installation_not_ready` | The installation has not been applied yet | +| 409 | `installation_not_running` | Core, Web, the gateway or the installation service is not running | +| 409 | `generated_files_edited` | Generated files were edited by hand; resolve them with `oac apply` | +| 409 | `public_url_confirmation_required` | The address changes existing bindings; resubmit with `confirm_public_url_change` | +| 409 | `installation_busy` | Another installation operation holds the lock, or the installer rejected the change | + +## Console sign-in responses + +`/console/auth`, `/console/auth/login`, `/console/auth/logout` and the other +signed-in console pages outside `/core/*` answer failures as +`{"error":""}` with no code. Clients branch on the status. + +| Status | Code | Meaning | +| --- | --- | --- | +| 400 | null | The login body is not a JSON object with only a non-empty `core_key` | +| 401 | null | Wrong Core key, or a console page requested without a session | +| 403 | null | Host, Origin or Fetch Metadata checks failed outside `/core/*` | +| 404 | null | Unknown `/console/auth/*` route | +| 405 | null | Login or logout without POST (`Allow: POST`) | +| 415 | null | The login body is not `application/json` | +| 429 | null | Sign-in is busy (`Retry-After: 1`) or ten failed attempts in one minute (`Retry-After: 60`) | +| 503 | null | A session token could not be generated | + +Outside `/core/*` the console also answers an unsafe path with a plain-text 400, +a wrong method on static pages and `/node-install/*` with a plain-text 405 +(`Allow: GET, HEAD`), and unknown or direct `/v1` and `/api/v1` paths with a +plain-text 404. After sign-in, `/core` and `/core/*` paths outside `/core/v1` +also get a plain-text 404. `GET /healthz` returns `200 ok` without +authentication. + +## Runtime daemon transport codes + +`/api/v1/agent-daemon/ws`, `/bootstrap` and `/device-status` answer the failures +their handlers detect as `{"error":"","detail":""}`. `detail` is +diagnostic text, not a stable value. The router in front of them answers an +unknown `/api/v1/agent-daemon/*` path with a plain-text 404 and a wrong method with +an empty 405, and a failed WebSocket handshake on `ws` is answered as plain text by +the WebSocket library, so clients must not assume the JSON body on every +failure. + +| Status | Code | Meaning | +| --- | --- | --- | +| 400 | `missing_params` | `device_id`, `version` or the Bearer credential is missing | +| 400 | `missing_device_id` | The bootstrap body or device-status query has no `device_id` | +| 400 | `bad_json` | The bootstrap body is not valid JSON | +| 401 | `missing_bearer` | No Bearer daemon credential | +| 401 | `unknown_device` | The device is not enrolled | +| 401 | `bad_credential` | The daemon credential does not match the device | +| 403 | `wrong_runtime_type` | The credential belongs to another Runtime type | +| 405 | `method_not_allowed` | Bootstrap without POST, if the handler is reached; the router's empty 405 normally answers first | +| 426 | `incompatible_version` | The daemon version is not supported by this Core | +| 500 | `internal` | Authentication failed unexpectedly | +| 503 | `bootstrap_unavailable` | The Runtime connection address is unavailable | + +## Plain-text transport responses + +These routes answer failures with a `text/plain` body and no code. + +| Status | Code | Routes | Meaning | +| --- | --- | --- | --- | +| 400 | null | `POST agent-daemon/enroll`, `GET agent-daemon/connection` | Invalid body or query | +| 401 | null | enroll, connection, `GET sandbox-node/connect` | Missing or rejected credential | +| 405 | null | enroll, connection | Wrong method (`Allow` names the method) | +| 409 | null | enroll, connection, sandbox-node/connect | The Environment is bound to another executor, or the node identity is already connected | +| 503 | null | enroll, connection, sandbox-node/connect | Enrollment storage, node authentication or the connection owner is unavailable | + +## Client-generated codes + +`packages/agents-client` creates these `AgentCoreError` codes itself; Core never +sends them. + +Codes that report a malformed response use status 502 (or 0 for Core metrics) +and mean the client rejected what Core returned; they never indicate a request +error. + +| Code | Meaning | +| --- | --- | +| `invalid_admin_response` | An administration or sandbox administration response has the wrong shape (`AdminClient`, `SandboxAdminClient`) | +| `invalid_response` | A Core metrics response has the wrong shape (`CoreMetricsClient`) | +| `sandbox_configuration_unconfirmed` | A sandbox configuration write failed without a confirmed outcome, or its reason was withheld because it could echo the key; refresh before submitting again | +| `credential_write_failed` | A Vault credential write was rejected; the client keeps the status but never parses the body, which could reflect the secret | +| `invalid_environment_template` | An Environment Template response has the wrong shape | +| `invalid_environment_template_list` | An Environment Template list has the wrong shape | +| `invalid_vault_resource` | A Vault response has the wrong shape or another ID | +| `invalid_vault_list` | A Vault list has the wrong shape | +| `invalid_vault_deletion` | A Vault deletion receipt has the wrong shape or another ID | +| `invalid_vault_credential` | Credential metadata has the wrong shape or another ID | +| `invalid_vault_credential_list` | A Credential list has the wrong shape | +| `invalid_vault_credential_deletion` | A Credential deletion receipt has the wrong shape or another ID | +| `invalid_session_vaults` | A Session's Vault attachments have the wrong shape | +| `invalid_environment_resource` | An Environment response has the wrong shape | +| `invalid_environment_file` | An Environment file response has the wrong shape | +| `invalid_environment_files` | An Environment files page has the wrong shape | +| `invalid_session_resource` | A Session response has the wrong shape | +| `invalid_session_list` | A Session list has the wrong shape | +| `invalid_history_resource` | A Turn, Item or other history response has the wrong shape | +| `invalid_runtime_observation` | A Runtime observation has the wrong shape | +| `invalid_stream_event` | An event stream frame has the wrong shape | +| `empty_stream` | An event stream closed before its first event | +| `invalid_source_file` | Source File metadata has the wrong shape | +| `invalid_source_file_list` | A Files list has the wrong shape | +| `invalid_source_file_content` | Source File content is incomplete or has the wrong headers | +| `invalid_skill_resource` | A Skill or Skill version response has the wrong shape | +| `invalid_skill_content` | Skill content is incomplete or has the wrong headers | diff --git a/docs/api/README.md b/docs/api/README.md index 41f9a47f1..4c2869193 100644 --- a/docs/api/README.md +++ b/docs/api/README.md @@ -17,7 +17,8 @@ A credential used in another namespace gets 401: a Project API key on `/core/v1` **Routing.** The reverse proxy sends `/v1` and `/api/v1` to Core and everything else to Web ([proxy setup](../getting-started/install.md#https-and-the-reverse-proxy)). Browsers reach `/core/v1` only through Web's server, which adds the Core key after -sign-in; Web returns 404 for `/v1` and `/api/v1`. Operator scripts call `/core/v1` +sign-in; Web returns 404 for `/v1` and `/api/v1`, and answers an unauthenticated +`GET /healthz` liveness probe with `200 ok`. Operator scripts call `/core/v1` on Core's loopback port. Details: [Web and Core](web-management.md). ## Public API @@ -25,7 +26,8 @@ on Core's loopback port. Details: [Web and Core](web-management.md). Applications call `/v1` with a Project API key. The routes are exactly the 58 pairs in [upstream-routes.json](../../contracts/agents-api/upstream-routes.json). The [Agents API guide](public-agent-api.md) explains every resource with SDK and HTTP -examples. +examples. [Request conventions](request-conventions.md) covers the headers, JSON body +checks and list parameters every `/v1` operation shares. ## Core API @@ -90,6 +92,15 @@ the Core key or a Project API key. | `POST agent-daemon/enroll`, `GET agent-daemon/connection` | Self-hosted executor and its installer | Executor credential from `/core/v1/projects/{project_id}/environments/{environment_id}/executor-credentials` | [Executor credentials](../../contracts/agents-api/environment-executor-credentials.md) | | WebSocket `GET agent-daemon/ws`, `POST agent-daemon/bootstrap`, `GET agent-daemon/device-status` | Runtime daemons | Daemon credential: Core writes one into each hosted sandbox it prepares; a self-hosted executor uses its executor credential | [Runtime enrollment](../../services/agents-api/README.md#user-managed-runtime-enrollment) | +Only the three `sandbox-node` HTTP routes are in the machine OpenAPI and use the +JSON error envelope. The node WebSocket and the daemon transport are served +beside the API router: `agent-daemon/enroll`, `agent-daemon/connection` and +`sandbox-node/connect` answer failures with a plain-text body and no code, and +`agent-daemon/ws`, `bootstrap` and `device-status` answer the failures their +handlers detect with `{"error":"","detail":"…"}`; router and WebSocket +handshake failures stay plain text. Both are listed in the +[error code registry](../../contracts/agents-api/error-codes.md#runtime-daemon-transport-codes). + ## Contract sources - [Pinned upstream baseline](../../contracts/agents-api/upstream.json): OpenAI @@ -133,3 +144,9 @@ The console-local `GET`/`POST /console/installation/domain` surface uses the sig browser session and same-origin checks. It delegates only domain setup to the installer, with the server-held Core key over a private Unix socket; it is not part of the Agents API or Core management API. See [Web request boundaries](../web/architecture.md#request-boundaries). + +Core administration failures use the [Core error envelope](../../contracts/agents-api/core-errors.md), +including typed optional safe details and distinct console proxy rejection codes. +The [error code registry](../../contracts/agents-api/error-codes.md) lists every error +code in all three namespaces, the console and the daemon transport, and is checked +against the code. diff --git a/services/agents-api/internal/api/contract_conformance_test.go b/services/agents-api/internal/api/contract_conformance_test.go new file mode 100644 index 000000000..a16bafe69 --- /dev/null +++ b/services/agents-api/internal/api/contract_conformance_test.go @@ -0,0 +1,806 @@ +package api + +// These checks keep the published responses and error codes tied to the code +// that writes them. They read source only; no handler runs. See +// contracts/agents-api/error-codes.md for the registry they compare against. + +import ( + "fmt" + "go/ast" + "go/parser" + "go/token" + "os" + "path/filepath" + "regexp" + "slices" + "sort" + "strconv" + "strings" + "testing" + + "gopkg.in/yaml.v3" +) + +const conformanceRepoRoot = "../../../.." + +// statusValues maps the net/http constants this repository writes. An unknown +// constant fails the check instead of being silently ignored. +var statusValues = map[string]int{ + "StatusOK": 200, "StatusCreated": 201, "StatusAccepted": 202, "StatusNoContent": 204, + "StatusBadRequest": 400, "StatusUnauthorized": 401, "StatusForbidden": 403, "StatusNotFound": 404, + "StatusMethodNotAllowed": 405, "StatusConflict": 409, "StatusRequestEntityTooLarge": 413, + "StatusUnsupportedMediaType": 415, "StatusUpgradeRequired": 426, "StatusTooManyRequests": 429, + "StatusInternalServerError": 500, "StatusBadGateway": 502, "StatusServiceUnavailable": 503, + "StatusGatewayTimeout": 504, +} + +type sourcePackage struct { + fset *token.FileSet + files []*ast.File + funcs map[string]*ast.FuncDecl // "Name" or "Receiver.Name" +} + +func parseSourcePackage(t *testing.T, dir string) sourcePackage { + t.Helper() + fset := token.NewFileSet() + entries, err := os.ReadDir(dir) + if err != nil { + t.Fatal(err) + } + result := sourcePackage{fset: fset, funcs: map[string]*ast.FuncDecl{}} + for _, entry := range entries { + name := entry.Name() + if entry.IsDir() || !strings.HasSuffix(name, ".go") || strings.HasSuffix(name, "_test.go") { + continue + } + file, err := parser.ParseFile(fset, filepath.Join(dir, name), nil, parser.ParseComments) + if err != nil { + t.Fatal(err) + } + result.files = append(result.files, file) + for _, decl := range file.Decls { + if fn, ok := decl.(*ast.FuncDecl); ok { + result.funcs[funcKey(fn)] = fn + } + } + } + return result +} + +func funcKey(fn *ast.FuncDecl) string { + if fn.Recv == nil || len(fn.Recv.List) == 0 { + return fn.Name.Name + } + typ := fn.Recv.List[0].Type + if star, ok := typ.(*ast.StarExpr); ok { + typ = star.X + } + if ident, ok := typ.(*ast.Ident); ok { + return ident.Name + "." + fn.Name.Name + } + return fn.Name.Name +} + +// statusConstant returns the value of an http.StatusX selector. +func statusConstant(t *testing.T, expr ast.Expr) (int, bool) { + selector, ok := expr.(*ast.SelectorExpr) + if !ok { + return 0, false + } + pkg, ok := selector.X.(*ast.Ident) + if !ok || pkg.Name != "http" || !strings.HasPrefix(selector.Sel.Name, "Status") || selector.Sel.Name == "StatusText" { + return 0, false + } + value, known := statusValues[selector.Sel.Name] + if !known { + t.Fatalf("add http.%s to statusValues", selector.Sel.Name) + } + return value, true +} + +// errorWriters take the HTTP status as their second argument. +var errorWriters = map[string]bool{"writeError": true, "writeAPIError": true, "writeCoreError": true} + +// statusArgument reads a status argument: an http.StatusX constant or an +// integer literal in the HTTP status range, such as writeError(w, 503, ...). +func statusArgument(t *testing.T, expr ast.Expr) (int, bool) { + if status, ok := statusConstant(t, expr); ok { + return status, true + } + literal, ok := expr.(*ast.BasicLit) + if !ok || literal.Kind != token.INT { + return 0, false + } + value, err := strconv.Atoi(literal.Value) + return value, err == nil && value >= 100 && value <= 599 +} + +func stringLiteral(expr ast.Expr) (string, bool) { + literal, ok := expr.(*ast.BasicLit) + if !ok || literal.Kind != token.STRING { + return "", false + } + value, err := strconv.Unquote(literal.Value) + return value, err == nil +} + +// writtenStatuses collects the http.StatusX constants a function body uses as +// values. Comparisons and switch cases read a status rather than write one. +func writtenStatuses(t *testing.T, body ast.Node) map[int]bool { + skip := map[ast.Expr]bool{} + ast.Inspect(body, func(node ast.Node) bool { + switch n := node.(type) { + case *ast.BinaryExpr: + if n.Op == token.EQL || n.Op == token.NEQ { + skip[n.X], skip[n.Y] = true, true + } + case *ast.CaseClause: + for _, expr := range n.List { + skip[expr] = true + } + } + return true + }) + statuses := map[int]bool{} + ast.Inspect(body, func(node ast.Node) bool { + // A literal status is counted only where an error writer takes it. + if call, ok := node.(*ast.CallExpr); ok && len(call.Args) > 1 { + if ident, ok := call.Fun.(*ast.Ident); ok && errorWriters[ident.Name] { + if literal, ok := call.Args[1].(*ast.BasicLit); ok { + if status, ok := statusArgument(t, literal); ok { + statuses[status] = true + } + } + } + } + expr, ok := node.(ast.Expr) + if !ok || skip[expr] { + return true + } + if status, ok := statusConstant(t, expr); ok { + statuses[status] = true + return false + } + return true + }) + return statuses +} + +// references lists package functions and methods a function calls or passes +// as a value. Without type information a method resolves only through the +// function's own receiver or a Handler named h; w.WriteHeader on an interface +// and field calls such as h.store.Get stay unresolved. +func (p sourcePackage) references(fn *ast.FuncDecl) []string { + receivers := map[string]string{"h": "Handler"} + if fn.Recv != nil && len(fn.Recv.List) > 0 && len(fn.Recv.List[0].Names) > 0 { + if receiver, _, ok := strings.Cut(funcKey(fn), "."); ok { + receivers[fn.Recv.List[0].Names[0].Name] = receiver + } + } + var out []string + selected := map[*ast.Ident]bool{} + ast.Inspect(fn.Body, func(node ast.Node) bool { + switch n := node.(type) { + case *ast.SelectorExpr: + selected[n.Sel] = true + if ident, ok := n.X.(*ast.Ident); ok { + if receiver, ok := receivers[ident.Name]; ok { + if _, exists := p.funcs[receiver+"."+n.Sel.Name]; exists { + out = append(out, receiver+"."+n.Sel.Name) + } + } + return false + } + case *ast.Ident: + if selected[n] { + return true + } + if fn, ok := p.funcs[n.Name]; ok && fn.Recv == nil { + out = append(out, n.Name) + } + } + return true + }) + return out +} + +type operation struct { + handler, method, path string + declared map[int]bool + successes, failures int +} + +var ( + routerAnnotation = regexp.MustCompile(`^@Router\s+(\S+)\s+\[(\w+)\]`) + statusAnnotation = regexp.MustCompile(`^@(Success|Failure)\s+([0-9,]+)(\s|$)`) +) + +func annotatedOperations(p sourcePackage) []operation { + var out []operation + for key, fn := range p.funcs { + if fn.Doc == nil { + continue + } + op := operation{handler: key, declared: map[int]bool{}} + for _, comment := range fn.Doc.List { + line := strings.TrimSpace(strings.TrimPrefix(comment.Text, "//")) + if match := routerAnnotation.FindStringSubmatch(line); match != nil { + op.path, op.method = match[1], strings.ToUpper(match[2]) + } + if match := statusAnnotation.FindStringSubmatch(line); match != nil { + for _, value := range strings.Split(match[2], ",") { + status, _ := strconv.Atoi(value) + op.declared[status] = true + } + if match[1] == "Success" { + op.successes++ + } else { + op.failures++ + } + } + } + if op.path != "" { + out = append(out, op) + } + } + sort.Slice(out, func(i, j int) bool { return out[i].path+out[i].method < out[j].path+out[j].method }) + return out +} + +// storeDispatcher maps stored-error sentinels to many statuses. Which sentinel +// a store call returns is not visible statically, so an operation reaching it +// is required to declare only what every lookup can produce: 500 for an +// unknown persistence failure and, when the path names a resource, 404. Any +// status the dispatcher writes is allowed as a declaration. +const storeDispatcher = "writeStoreError" + +// middlewareStatuses are written before an operation's handler runs. Paths +// are relative to the contract base path, so /v1 operations have no prefix. +func middlewareStatuses(path string) []int { + switch { + case strings.HasPrefix(path, "/core/v1/"): + return []int{401} // invalid_admin_key + case strings.HasPrefix(path, "/api/v1/"): + return []int{401} // enrollment token or node credential + case strings.HasPrefix(path, "/files") || strings.HasPrefix(path, "/skills"): + // authenticateProject: invalid_api_key or null code; authentication_unavailable. + return []int{401, 503} + default: + // authenticate adds the OpenAI-Beta check: 400 invalid_beta. + return []int{400, 401, 503} + } +} + +// reachableStatuses maps each status a handler can write to the first function +// found writing it, so a failure names where the status comes from, and +// reports whether the handler reaches the stored-error dispatcher. +func (p sourcePackage) reachableStatuses(t *testing.T, handler string) (map[int]string, bool) { + statuses := map[int]string{} + usesStore := false + seen := map[string]bool{} + queue := []string{handler} + for len(queue) > 0 { + key := queue[0] + queue = queue[1:] + if seen[key] { + continue + } + seen[key] = true + if key == storeDispatcher { + usesStore = true + continue + } + fn := p.funcs[key] + if fn == nil || fn.Body == nil { + continue + } + for status := range writtenStatuses(t, fn.Body) { + if _, ok := statuses[status]; !ok { + statuses[status] = key + } + } + queue = append(queue, p.references(fn)...) + } + return statuses, usesStore +} + +func sortedStatuses(values map[int]bool) []int { + out := make([]int, 0, len(values)) + for value := range values { + out = append(out, value) + } + sort.Ints(out) + return out +} + +// publishedOperations counts the operations of the three generated contracts. +func publishedOperations(t *testing.T) int { + t.Helper() + count := 0 + for _, name := range []string{"openapi.yaml", "core.openapi.yaml", "runtime.openapi.yaml"} { + raw, err := os.ReadFile(filepath.Join(conformanceRepoRoot, "contracts/agents-api", name)) + if err != nil { + t.Fatal(err) + } + var document struct { + Paths map[string]map[string]any `yaml:"paths"` + } + if err := yaml.Unmarshal(raw, &document); err != nil { + t.Fatal(name, err) + } + for _, item := range document.Paths { + for method := range item { + switch method { + case "get", "put", "post", "delete", "options", "head", "patch", "trace": + count++ + } + } + } + } + return count +} + +// withoutSuccess lists operations that never succeed, with the reason. +var withoutSuccess = map[string]string{ + // Every stored File has purpose user_data, whose download returns 400 as + // the official API does; the operation exists only for route parity. + "Handler.sourceFileContent": "user_data Files cannot be downloaded", +} + +// TestAnnotatedResponsesCoverWrittenStatuses requires every published +// operation to declare a success and a failure response (G1), every status its +// handler, its own helpers or its middleware can write, and no failure status +// that none of them can write (G2). +func TestAnnotatedResponsesCoverWrittenStatuses(t *testing.T) { + p := parseSourcePackage(t, ".") + storeStatuses := writtenStatuses(t, p.funcs[storeDispatcher].Body) + operations := annotatedOperations(p) + if published := publishedOperations(t); len(operations) != published { + t.Errorf("found %d annotated operations, but the contracts publish %d; run make openapi", len(operations), published) + } + for _, op := range operations { + name := op.method + " " + op.path + " (" + op.handler + ")" + if _, exempt := withoutSuccess[op.handler]; op.successes == 0 && !exempt { + t.Errorf("%s declares no @Success response", name) + } + if op.failures == 0 { + t.Errorf("%s declares no @Failure response", name) + } + required, usesStore := p.reachableStatuses(t, op.handler) + possible := map[int]bool{} + for status := range required { + possible[status] = true + } + for _, status := range middlewareStatuses(op.path) { + possible[status] = true + if _, ok := required[status]; !ok { + required[status] = "authentication middleware" + } + } + if usesStore { + for status := range storeStatuses { + possible[status] = true + } + baseline := []int{500} + if strings.Contains(op.path, "{") { + baseline = append(baseline, 404) + } + for _, status := range baseline { + if _, ok := required[status]; !ok { + required[status] = storeDispatcher + } + } + } + var missing []string + for status, source := range required { + if !op.declared[status] { + missing = append(missing, fmt.Sprintf("%d (from %s)", status, source)) + } + } + sort.Strings(missing) + if len(missing) > 0 { + t.Errorf("%s can write %s but does not declare it (declares %v)", name, strings.Join(missing, ", "), sortedStatuses(op.declared)) + } + var impossible []int + for status := range op.declared { + if status >= 400 && !possible[status] { + impossible = append(impossible, status) + } + } + sort.Ints(impossible) + if len(impossible) > 0 { + t.Errorf("%s declares %v, which neither its handler, its helpers nor its middleware can write", name, impossible) + } + } +} + +// emittedCode is one (status, code) pair a writer call can produce. A status of +// 0 means the call passes a variable status. +type emittedCode struct { + status int + code string +} + +func (e emittedCode) String() string { + if e.code == "" { + return fmt.Sprintf("%d null", e.status) + } + return fmt.Sprintf("%d %s", e.status, e.code) +} + +// emittedCodes collects (status, code) pairs from calls to the named writers, +// whose status and code are the arguments at the given positions. A code +// passed as a local variable resolves to the string literals assigned to it in +// the same function; an empty code is the null code. +func emittedCodes(t *testing.T, p sourcePackage, writers map[string][2]int) map[emittedCode][]string { + out := map[emittedCode][]string{} + for key, fn := range p.funcs { + if fn.Body == nil { + continue + } + if _, wrapper := writers[key]; wrapper { + continue + } + assigned := map[string][]string{} + // Variables assigned from a multi-value call, such as + // status, code := mapAuthError(err), are covered by returnedCodes. + fromCall := map[string]bool{} + ast.Inspect(fn.Body, func(node ast.Node) bool { + if assign, ok := node.(*ast.AssignStmt); ok && len(assign.Rhs) == 1 && len(assign.Lhs) > 1 { + if _, call := assign.Rhs[0].(*ast.CallExpr); call { + for _, lhs := range assign.Lhs { + if ident, ok := lhs.(*ast.Ident); ok { + fromCall[ident.Name] = true + } + } + } + } + if assign, ok := node.(*ast.AssignStmt); ok && len(assign.Lhs) == len(assign.Rhs) { + for i, lhs := range assign.Lhs { + if ident, ok := lhs.(*ast.Ident); ok { + if value, ok := stringLiteral(assign.Rhs[i]); ok { + assigned[ident.Name] = append(assigned[ident.Name], value) + } + } + } + } + return true + }) + ast.Inspect(fn.Body, func(node ast.Node) bool { + call, ok := node.(*ast.CallExpr) + if !ok { + return true + } + ident, ok := call.Fun.(*ast.Ident) + if !ok { + return true + } + positions, ok := writers[ident.Name] + if !ok || len(call.Args) <= positions[1] { + return true + } + status, _ := statusArgument(t, call.Args[positions[0]]) + var codes []string + if value, ok := stringLiteral(call.Args[positions[1]]); ok { + codes = []string{value} + } else if variable, ok := call.Args[positions[1]].(*ast.Ident); ok { + codes = assigned[variable.Name] + if len(codes) == 0 && fromCall[variable.Name] { + return true + } + if len(codes) == 0 { + t.Errorf("%s: cannot resolve code variable %s", p.fset.Position(call.Pos()), variable.Name) + } + } else if field, ok := call.Args[positions[1]].(*ast.SelectorExpr); ok && field.Sel.Name == "Code" && typedVariables(fn)[identName(field.X)] != "" { + typ := typedVariables(fn)[identName(field.X)] + codes = typedCodes[typ] + if len(codes) == 0 { + t.Errorf("%s: no %s{Code: ...} literals found for %s.Code", p.fset.Position(call.Pos()), typ, identName(field.X)) + } + } else { + t.Errorf("%s: code argument is neither a literal, a local variable nor a typed error's Code", p.fset.Position(call.Pos())) + } + for _, code := range codes { + // An empty code is a null code; it is compared with the null rows. + if status == 0 { + t.Errorf("%s: code %s is written with a variable status", p.fset.Position(call.Pos()), code) + } + position := p.fset.Position(call.Pos()) + out[emittedCode{status, code}] = append(out[emittedCode{status, code}], filepath.Base(position.Filename)+":"+strconv.Itoa(position.Line)) + } + return true + }) + } + return out +} + +// typedCodes maps a validation error type to the codes its literals set. A +// writer that passes field.Code, for a variable declared as that type, can +// write any of them. Filled by collectTypedCodes before the registry check. +var typedCodes = map[string][]string{} + +// typedErrorTypes are the error types whose Code member reaches an error writer, +// with the packages that construct them. +var typedErrorTypes = map[string]string{ + "AdminValidationError": "services/agents-api/internal/store", + "ModelProviderError": "contracts/agents-api/v1", +} + +func collectTypedCodes(t *testing.T) { + for typ, dir := range typedErrorTypes { + p := parseSourcePackage(t, filepath.Join(conformanceRepoRoot, dir)) + seen := map[string]bool{} + for _, file := range p.files { + ast.Inspect(file, func(node ast.Node) bool { + literal, ok := node.(*ast.CompositeLit) + if !ok || identName(literal.Type) != typ { + return true + } + for _, element := range literal.Elts { + if pair, ok := element.(*ast.KeyValueExpr); ok && identName(pair.Key) == "Code" { + code, ok := stringLiteral(pair.Value) + if !ok { + t.Errorf("%s: %s.Code is not a string literal", p.fset.Position(pair.Pos()), typ) + } else if !seen[code] { + seen[code] = true + typedCodes[typ] = append(typedCodes[typ], code) + } + } + } + return true + }) + } + if len(typedCodes[typ]) == 0 { + t.Fatalf("no %s literals in %s", typ, dir) + } + } +} + +// identName is the name of an identifier or the selected name of pkg.Name. +func identName(expr ast.Expr) string { + switch e := expr.(type) { + case *ast.Ident: + return e.Name + case *ast.SelectorExpr: + return e.Sel.Name + case *ast.StarExpr: + return identName(e.X) + } + return "" +} + +// typedVariables maps variables declared as `var name *T` or `var name T` in a +// function to T, for the typed error types above. +func typedVariables(fn *ast.FuncDecl) map[string]string { + out := map[string]string{} + ast.Inspect(fn.Body, func(node ast.Node) bool { + spec, ok := node.(*ast.ValueSpec) + if !ok || spec.Type == nil { + return true + } + if typ := identName(spec.Type); typedErrorTypes[typ] != "" { + for _, name := range spec.Names { + out[name.Name] = typ + } + } + return true + }) + return out +} + +// returnedCodes collects functions that return (http.StatusX, "code"). +func returnedCodes(t *testing.T, p sourcePackage, out map[emittedCode][]string) { + for _, fn := range p.funcs { + if fn.Body == nil { + continue + } + ast.Inspect(fn.Body, func(node ast.Node) bool { + ret, ok := node.(*ast.ReturnStmt) + if !ok || len(ret.Results) != 2 { + return true + } + status, ok := statusConstant(t, ret.Results[0]) + code, isString := stringLiteral(ret.Results[1]) + if ok && isString { + position := p.fset.Position(ret.Pos()) + out[emittedCode{status, code}] = append(out[emittedCode{status, code}], filepath.Base(position.Filename)+":"+strconv.Itoa(position.Line)) + } + return true + }) + } +} + +// streamErrorCodes collects v1.StreamError{Code: "..."} literals: error frames +// inside an event stream whose response status is already 200. +func streamErrorCodes(p sourcePackage) map[emittedCode][]string { + out := map[emittedCode][]string{} + for _, file := range p.files { + ast.Inspect(file, func(node ast.Node) bool { + literal, ok := node.(*ast.CompositeLit) + if !ok { + return true + } + selector, ok := literal.Type.(*ast.SelectorExpr) + if !ok || selector.Sel.Name != "StreamError" { + return true + } + for _, element := range literal.Elts { + if pair, ok := element.(*ast.KeyValueExpr); ok { + if key, ok := pair.Key.(*ast.Ident); ok && key.Name == "Code" { + if code, ok := stringLiteral(pair.Value); ok { + position := p.fset.Position(pair.Pos()) + out[emittedCode{200, code}] = append(out[emittedCode{200, code}], filepath.Base(position.Filename)+":"+strconv.Itoa(position.Line)) + } + } + } + } + return true + }) + } + return out +} + +// registrySection returns the (status, code) rows of one registry section. Rows +// look like "| 409 | `project_exists` | ... |"; the code cell may be null. +func registrySection(t *testing.T, heading string) map[emittedCode]bool { + t.Helper() + raw, err := os.ReadFile(filepath.Join(conformanceRepoRoot, "contracts/agents-api/error-codes.md")) + if err != nil { + t.Fatal(err) + } + row := regexp.MustCompile("^\\| *([0-9]{3}) *\\| *(`[a-z0-9_]+`|null) *\\|") + rows := map[emittedCode]bool{} + inside, found := false, false + for _, line := range strings.Split(string(raw), "\n") { + if strings.HasPrefix(line, "## ") { + inside = strings.TrimSpace(strings.TrimPrefix(line, "## ")) == heading + found = found || inside + continue + } + if !inside { + continue + } + if match := row.FindStringSubmatch(line); match != nil { + status, _ := strconv.Atoi(match[1]) + code := strings.Trim(match[2], "`") + if code == "null" { + code = "" + } + if rows[emittedCode{status, code}] { + t.Errorf("error-codes.md %q lists %d %s twice", heading, status, code) + } + rows[emittedCode{status, code}] = true + } + } + if !found { + t.Fatalf("error-codes.md has no section %q", heading) + } + return rows +} + +func compareRegistry(t *testing.T, heading string, emitted map[emittedCode][]string) { + t.Helper() + listed := registrySection(t, heading) + var undocumented, unused []string + for pair, sites := range emitted { + if !listed[pair] { + slices.Sort(sites) + undocumented = append(undocumented, pair.String()+" at "+strings.Join(sites, ", ")) + } + } + for pair := range listed { + if _, ok := emitted[pair]; !ok { + unused = append(unused, pair.String()) + } + } + sort.Strings(undocumented) + sort.Strings(unused) + for _, entry := range undocumented { + t.Errorf("%s: emitted but not listed in error-codes.md: %s", heading, entry) + } + for _, entry := range unused { + t.Errorf("%s: listed in error-codes.md but never emitted: %s", heading, entry) + } +} + +// callStatuses collects the http.StatusX argument at index of every call to +// name, which is a local function or variable, or "http.Error". +func callStatuses(t *testing.T, p sourcePackage, name string, index int) map[int]bool { + out := map[int]bool{} + for _, file := range p.files { + ast.Inspect(file, func(node ast.Node) bool { + call, ok := node.(*ast.CallExpr) + if !ok || len(call.Args) <= index { + return true + } + called := "" + switch fun := call.Fun.(type) { + case *ast.Ident: + called = fun.Name + case *ast.SelectorExpr: + if pkg, ok := fun.X.(*ast.Ident); ok { + called = pkg.Name + "." + fun.Sel.Name + } + } + if called == name { + if status, ok := statusConstant(t, call.Args[index]); ok { + out[status] = true + } + } + return true + }) + } + return out +} + +// registryStatuses returns the statuses of every row in one registry section, +// including rows whose code is null. +func registryStatuses(t *testing.T, heading string) map[int]bool { + t.Helper() + raw, err := os.ReadFile(filepath.Join(conformanceRepoRoot, "contracts/agents-api/error-codes.md")) + if err != nil { + t.Fatal(err) + } + row := regexp.MustCompile(`^\| *([0-9]{3}) *\|`) + out := map[int]bool{} + inside := false + for _, line := range strings.Split(string(raw), "\n") { + if strings.HasPrefix(line, "## ") { + inside = strings.TrimSpace(strings.TrimPrefix(line, "## ")) == heading + continue + } + if match := row.FindStringSubmatch(line); inside && match != nil { + status, _ := strconv.Atoi(match[1]) + out[status] = true + } + } + return out +} + +// TestUncodedResponsesMatchRegistry covers responses without a code: the +// console sign-in errors and the plain-text machine transport errors. +func TestUncodedResponsesMatchRegistry(t *testing.T) { + console := parseSourcePackage(t, filepath.Join(conformanceRepoRoot, "services/core-console")) + signIn := callStatuses(t, console, "authError", 1) + if got, want := sortedStatuses(registryStatuses(t, "Console sign-in responses")), sortedStatuses(signIn); !slices.Equal(got, want) { + t.Errorf("Console sign-in responses list %v; authError writes %v", got, want) + } + transport := map[int]bool{} + enrollment := parseSourcePackage(t, filepath.Join(conformanceRepoRoot, "services/agents-api/internal/runtimeenrollment")) + for status := range callStatuses(t, enrollment, "fail", 0) { + transport[status] = true + } + node := parseSourcePackage(t, filepath.Join(conformanceRepoRoot, "services/agents-api/internal/sandbox/node")) + for status := range callStatuses(t, node, "http.Error", 2) { + transport[status] = true + } + if got, want := sortedStatuses(registryStatuses(t, "Plain-text transport responses")), sortedStatuses(transport); !slices.Equal(got, want) { + t.Errorf("Plain-text transport responses list %v; the handlers write %v", got, want) + } +} + +// TestErrorCodeRegistryMatchesEmittedCodes keeps the error code registry and +// the service's (status, code) pairs equal in both directions (G3). +func TestErrorCodeRegistryMatchesEmittedCodes(t *testing.T) { + collectTypedCodes(t) + // A code assigned from a helper's (status, code) result is skipped at the + // writer call, so returnedCodes must run on every package. + api := parseSourcePackage(t, ".") + codes := emittedCodes(t, api, map[string][2]int{ + "writeError": {1, 2}, "writeAPIError": {1, 2}, "writeCoreError": {1, 2}, + }) + returnedCodes(t, api, codes) + compareRegistry(t, "Agents API and Core API codes", codes) + + console := parseSourcePackage(t, filepath.Join(conformanceRepoRoot, "services/core-console")) + consoleCodes := emittedCodes(t, console, map[string][2]int{"consoleCoreError": {1, 2}}) + returnedCodes(t, console, consoleCodes) + compareRegistry(t, "Console codes", consoleCodes) + + compareRegistry(t, "Event stream error codes", streamErrorCodes(api)) + + gateway := parseSourcePackage(t, filepath.Join(conformanceRepoRoot, "internal/agentdaemon/gateway")) + daemon := emittedCodes(t, gateway, map[string][2]int{"writeAuthError": {1, 2}}) + returnedCodes(t, gateway, daemon) + compareRegistry(t, "Runtime daemon transport codes", daemon) +} diff --git a/services/agents-api/internal/api/core_resource_errors_test.go b/services/agents-api/internal/api/core_resource_errors_test.go new file mode 100644 index 000000000..4be34548c --- /dev/null +++ b/services/agents-api/internal/api/core_resource_errors_test.go @@ -0,0 +1,98 @@ +package api + +import ( + "context" + "encoding/json" + "net/http" + "net/http/httptest" + "testing" + + "github.com/MiniMax-AI-Dev/parsar/services/agents-api/internal/store" +) + +// errorProbeFiles reports every File as missing and lists nothing. +type errorProbeFiles struct{ SourceFileStore } + +func (errorProbeFiles) GetSourceFile(context.Context, string, string) (store.SourceFile, error) { + return store.SourceFile{}, store.ErrNotFound +} +func (errorProbeFiles) ListSourceFiles(context.Context, string, string, int, bool, *string) (store.SourceFilePage, error) { + return store.SourceFilePage{}, nil +} + +// errorProbeSkills reports every Skill as missing, rejects every Skill version +// cursor and refuses every version deletion as the default version. +type errorProbeSkills struct{ SkillStore } + +func (errorProbeSkills) GetSkill(context.Context, string, string) (store.Skill, error) { + return store.Skill{}, store.ErrNotFound +} +func (errorProbeSkills) ListSkills(context.Context, string, string, int, bool) (store.SkillPage, error) { + return store.SkillPage{}, nil +} +func (errorProbeSkills) ListSkillVersions(_ context.Context, _, _, after string, _ int, _ bool) (store.SkillVersionPage, error) { + if after != "" { + return store.SkillVersionPage{}, &store.InvalidCursorError{Message: "cursor"} + } + return store.SkillVersionPage{}, nil +} +func (errorProbeSkills) DeleteSkillVersion(context.Context, string, string, string) (store.SkillVersion, error) { + return store.SkillVersion{}, store.ErrDefaultSkillVersion +} + +// The Files and Skills error family is chosen by request path. Through the +// real routes, Core gets the Agents API Beta fields from the shared list +// parser and not-found mapping, while errors a handler writes itself keep their +// public fields. admin-api.md documents both; these cases keep it true. +func TestCoreFilesAndSkillsUseTheBetaErrorFamily(t *testing.T) { + h, _, _ := adminTestHandler(t, WithSourceFiles(errorProbeFiles{}), WithSkills(errorProbeSkills{})) + type result struct { + status int + code, param any + } + request := func(t *testing.T, method, path, key string) result { + t.Helper() + r := httptest.NewRequest(method, path, nil) + r.Header.Set("Authorization", "Bearer "+key) + w := httptest.NewRecorder() + h.ServeHTTP(w, r) + if w.Code == http.StatusOK { + return result{status: w.Code} + } + var body struct { + Error struct { + Code any `json:"code"` + Param any `json:"param"` + } `json:"error"` + } + if err := json.Unmarshal(w.Body.Bytes(), &body); err != nil { + t.Fatalf("%s %s: %d %s", method, path, w.Code, w.Body.String()) + } + return result{w.Code, body.Error.Code, body.Error.Param} + } + beta := result{400, "invalid_request_error", nil} + for _, test := range []struct { + name, method, path string + public, core result + }{ + {"missing File", http.MethodGet, "/files/file-1", result{404, nil, "id"}, result{404, "not_found_error", "id"}}, + {"missing Skill", http.MethodGet, "/skills/skill-1", result{404, nil, nil}, result{404, "not_found_error", nil}}, + {"unresolved Skill version cursor", http.MethodGet, "/skills/skill-1/versions?after=skillver_x", result{400, "invalid_value", "after"}, beta}, + {"repeated Files limit", http.MethodGet, "/files?limit=1&limit=2", result{400, "unsupported_parameter", nil}, beta}, + {"repeated Skills limit", http.MethodGet, "/skills?limit=1&limit=2", result{400, "duplicate_parameter", "limit"}, beta}, + {"invalid Files order", http.MethodGet, "/files?order=sideways", result{400, nil, nil}, beta}, + {"invalid Skills order", http.MethodGet, "/skills?order=sideways", result{400, "invalid_value", "order"}, beta}, + {"Files limit 0", http.MethodGet, "/files?limit=0", result{400, nil, nil}, beta}, + {"Skills limit 0", http.MethodGet, "/skills?limit=0", result{status: 200}, beta}, + {"Skills limit above maximum", http.MethodGet, "/skills?limit=101", result{400, "integer_above_max_value", "limit"}, beta}, + {"unknown Files purpose", http.MethodGet, "/files?purpose=bogus", result{400, nil, "purpose"}, result{400, nil, "purpose"}}, + {"default Skill version deletion", http.MethodDelete, "/skills/skill-1/versions/1", result{400, "invalid_value", "version"}, result{400, "invalid_value", "version"}}, + } { + if got := request(t, test.method, "/v1"+test.path, "caller"); got != test.public { + t.Errorf("%s on /v1: got %+v, want %+v", test.name, got, test.public) + } + if got := request(t, test.method, "/core/v1/projects/"+managementProjectID+test.path, "admin"); got != test.core { + t.Errorf("%s on /core/v1: got %+v, want %+v", test.name, got, test.core) + } + } +} From d925bf0b35f87e9b79961225e02259a6a3b5c3da Mon Sep 17 00:00:00 2001 From: Yao Date: Tue, 29 Sep 2026 23:19:32 +0800 Subject: [PATCH 03/14] docs: render one page per API operation on the documentation site A tag page carried up to 11 operations with full schemas, took 4-10 s to render and weighed 1.4-1.8 MB. Generate one page per operation in a folder per tag, keep an overview at the former tag URL, split each description into a lead and details, and stop generating TypeScript copies of every response schema. Sidebar links no longer prefetch. verify-api-copy checks folder navigation and overviews against the operation pages, verify-error-codes checks client-generated codes and every code the client and Web compare against, and the route gate accounts for the transport paths outside the OpenAPI contracts. Record keys are POSIX paths so generated records verify on Windows. --- apps/docs/app/[[...slug]]/page.tsx | 2 +- apps/docs/app/layout.tsx | 11 +- apps/docs/components/api-page.tsx | 12 +- apps/docs/package.json | 3 +- apps/docs/scripts/check-browser.mjs | 16 +- apps/docs/scripts/check-python.test.mjs | 2 +- apps/docs/scripts/contracts.mjs | 34 +++++ apps/docs/scripts/contracts.test.mjs | 27 +++- apps/docs/scripts/generate-api-reference.mjs | 119 +++++++++++++-- apps/docs/scripts/guides.json | 12 ++ apps/docs/scripts/test_contract_routes.py | 6 + apps/docs/scripts/verify-api-copy.mjs | 37 +++-- .../scripts/verify-contract-freshness.mjs | 3 +- apps/docs/scripts/verify-contract-routes.py | 68 ++++++++- apps/docs/scripts/verify-error-codes.mjs | 138 ++++++++++++++++++ 15 files changed, 453 insertions(+), 37 deletions(-) create mode 100644 apps/docs/scripts/verify-error-codes.mjs diff --git a/apps/docs/app/[[...slug]]/page.tsx b/apps/docs/app/[[...slug]]/page.tsx index ce9b7c35f..e50932d01 100644 --- a/apps/docs/app/[[...slug]]/page.tsx +++ b/apps/docs/app/[[...slug]]/page.tsx @@ -22,7 +22,7 @@ export default async function DocsPageRoute({ const MDX = page.data.body return ( - + {page.data.title} {page.data.description} diff --git a/apps/docs/app/layout.tsx b/apps/docs/app/layout.tsx index a14a4972e..02bb568e8 100644 --- a/apps/docs/app/layout.tsx +++ b/apps/docs/app/layout.tsx @@ -16,7 +16,16 @@ export default function RootLayout({ children }: { children: ReactNode }) { - {children} + + {children} + diff --git a/apps/docs/components/api-page.tsx b/apps/docs/components/api-page.tsx index 3976f2a65..02417a3c7 100644 --- a/apps/docs/components/api-page.tsx +++ b/apps/docs/components/api-page.tsx @@ -9,5 +9,15 @@ export async function APIPage({ ...props }: Omit & { document: string }) { // References never collect credentials or dispatch requests from the browser. - return + // Response schemas are shown in full; generating a TypeScript copy of every + // response for every status compiled the same schemas again and was about + // half of each page's render time. + return ( + + ) } diff --git a/apps/docs/package.json b/apps/docs/package.json index d736c306b..15251f1e4 100644 --- a/apps/docs/package.json +++ b/apps/docs/package.json @@ -8,11 +8,12 @@ "dev": "next dev --port 4000", "build": "fumadocs-mdx && next build && node scripts/verify-prerender.mjs", "api:generate": "node scripts/generate-api-reference.mjs", - "verify": "pnpm verify:contracts && pnpm verify:routes && pnpm verify:copy && pnpm verify:docs && pnpm verify:links", + "verify": "pnpm verify:contracts && pnpm verify:routes && pnpm verify:copy && pnpm verify:docs && pnpm verify:errors && pnpm verify:links", "verify:contracts": "node scripts/verify-contract-freshness.mjs", "verify:routes": "node scripts/check-python.mjs routes", "verify:copy": "node scripts/verify-api-copy.mjs", "verify:docs": "node scripts/verify-docs-facts.mjs", + "verify:errors": "node scripts/verify-error-codes.mjs", "verify:links": "node scripts/verify-links.mjs", "check:prerender": "node scripts/verify-prerender.mjs", "check:site": "node scripts/check-site.mjs", diff --git a/apps/docs/scripts/check-browser.mjs b/apps/docs/scripts/check-browser.mjs index 8bd3476ff..0dbda2254 100644 --- a/apps/docs/scripts/check-browser.mjs +++ b/apps/docs/scripts/check-browser.mjs @@ -18,7 +18,17 @@ page.on('pageerror', error => failures.push(error.message)) const screenshots = process.env.DOCS_SCREENSHOT_DIR if (screenshots) fs.mkdirSync(screenshots, { recursive: true }) try { - for (const route of ['/', '/install', '/configure', '/console', '/execution-model', '/api-reference/agents', '/api-reference/core/sandbox-manager', '/api-reference/machine/sandbox-node', '/harness-onboarding']) { + // Tag overviews name the surface credential; operation pages document the + // Authorization header of that operation. + const credentials = { + '/api-reference/agents': 'Project API key', + '/api-reference/core/sandbox-manager': 'Core key', + '/api-reference/machine/sandbox-node': 'enrollment', + '/api-reference/agents/list-reusable-agents': 'Authorization', + '/api-reference/core/sandbox-manager/retrieve-sandbox-deployment': 'Authorization', + '/api-reference/machine/sandbox-node/enroll-a-sandbox-node': 'Authorization', + } + for (const route of ['/', '/install', '/configure', '/console', '/execution-model', ...Object.keys(credentials), '/harness-onboarding']) { const response = await page.goto(origin + route, { waitUntil: 'networkidle' }) assert.equal(response.status(), 200, route) assert.ok(await page.locator('h1').count(), 'Missing page title: ' + route) @@ -26,7 +36,7 @@ try { assert.ok((await page.title()).includes('OpenAgentCore Docs'), 'Wrong page metadata: ' + route) if (route.includes('/api-reference/')) { assert.equal(await page.locator('input, form, textarea').count(), 0, 'Reference exposes request controls: ' + route) - assert.ok((await page.locator('body').innerText()).includes('Authorization'), 'Missing credential documentation: ' + route) + assert.ok((await page.locator('body').innerText()).includes(credentials[route]), 'Missing credential documentation: ' + route) } if (screenshots && ['/', '/console', '/execution-model', '/api-reference/core/sandbox-manager', '/harness-onboarding'].includes(route)) { await page.screenshot({ path: path.join(screenshots, (route.replaceAll('/', '-') || 'home') + '.png'), fullPage: false }) @@ -37,7 +47,7 @@ try { assert.ok(await page.evaluate(() => document.documentElement.scrollWidth <= window.innerWidth + 1), 'Mobile page overflows viewport') assert.deepEqual(failures, [], 'Browser runtime errors') assert.deepEqual(unexpected, [], 'Documentation made external requests') - console.log('Nine desktop routes, developer navigation, mobile layout and read-only API controls passed; no external requests.') + console.log('Twelve desktop routes, developer navigation, mobile layout, API credentials and read-only API controls passed; no external requests.') } finally { await context.close() await browser.close() diff --git a/apps/docs/scripts/check-python.test.mjs b/apps/docs/scripts/check-python.test.mjs index 05d5b6697..dc21cf6ee 100644 --- a/apps/docs/scripts/check-python.test.mjs +++ b/apps/docs/scripts/check-python.test.mjs @@ -22,7 +22,7 @@ test('route gate and Python regressions honor the selected interpreter without s }) assert.equal(result.status, 0, result.stdout + result.stderr) if (mode === 'routes') assert.match(result.stdout, /Contract operations:\s+[1-9]\d*\b/) - else assert.match(result.stderr, /Ran 2 tests/) + else assert.match(result.stderr, /Ran 3 tests/) } const invocations = fs.readFileSync(log, 'utf8').trim().split('\n').map(line => JSON.parse(line)) assert.equal(invocations.length, 2) diff --git a/apps/docs/scripts/contracts.mjs b/apps/docs/scripts/contracts.mjs index e8b6356e3..789e05cdd 100644 --- a/apps/docs/scripts/contracts.mjs +++ b/apps/docs/scripts/contracts.mjs @@ -14,6 +14,40 @@ export const surfaces = [ { id: 'runtime-api', file: 'runtime.openapi.yaml', directory: '/machine', title: 'Machine connection API', prefix: '/api/v1', credential: 'Route-specific node enrollment, node, daemon, or executor credential', authority: 'Generated local machine contract. These connections reach Core directly, never through Web.' }, ] export function sourcePath(surface) { return path.join(repoRoot, 'contracts/agents-api', surface.file) } + +// A contract route as a caller sends it. Core and machine routes already carry +// their namespace; public routes are relative to /v1. +export function fullPath(surface, route) { + return route === surface.prefix || route.startsWith(surface.prefix + '/') ? route : surface.prefix + route +} + +// An operation description is a short lead and optional details. The lead is +// the first paragraph, or for a single paragraph its first sentences up to at +// least 40 characters ("Core key only." alone says too little). +export function splitDescription(text = '') { + const trimmed = text.trim() + const paragraph = trimmed.indexOf('\n\n') + if (paragraph >= 0) return { lead: trimmed.slice(0, paragraph).trim(), details: trimmed.slice(paragraph + 2).trim() } + const sentence = /[.!?](?=\s+[A-Z`"(])/g + let end = -1 + for (let match; (match = sentence.exec(trimmed));) { + end = match.index + 1 + if (end >= 40) break + } + if (end < 0 || end >= trimmed.length - 1) return { lead: trimmed, details: '' } + return { lead: trimmed.slice(0, end), details: trimmed.slice(end).trim() } +} + +// Markdown from a contract, made safe for MDX: braces and angle brackets stay +// literal text outside code spans. +// Page descriptions render as plain text, so the lead drops inline markdown. +export function plainText(text) { + return text.replace(/\[([^\]]*)\]\([^)]*\)/g, '$1').replace(/\*\*([^*]*)\*\*/g, '$1').replace(/`([^`]*)`/g, '$1') +} + +export function mdxText(text) { + return text.split(/(`+[^`]*`+)/g).map((part, i) => i % 2 ? part : part.replaceAll('{', '{').replaceAll('}', '}').replaceAll('<', '<')).join('') +} export function normalise(surface, source = yaml.load(fs.readFileSync(sourcePath(surface), 'utf8'))) { if (source.swagger !== '2.0' && !/^3\./.test(source.openapi ?? '')) throw new Error('Unsupported contract format: ' + surface.file) const base = source.basePath === '/' ? '' : (source.basePath ?? '') diff --git a/apps/docs/scripts/contracts.test.mjs b/apps/docs/scripts/contracts.test.mjs index bf191d9af..cb050eba7 100644 --- a/apps/docs/scripts/contracts.test.mjs +++ b/apps/docs/scripts/contracts.test.mjs @@ -6,7 +6,32 @@ import path from 'node:path' import yaml from 'js-yaml' import { createOpenAPI } from 'fumadocs-openapi/server' import { schemaToString } from '../node_modules/fumadocs-openapi/dist/utils/schema-to-string.js' -import { appRoot, normalise, surfaces } from './contracts.mjs' +import { appRoot, normalise, surfaces, splitDescription, mdxText, plainText, fullPath } from './contracts.mjs' + +test('overview paths carry the namespace a caller sends', () => { + const [publicApi, coreApi] = surfaces + assert.equal(fullPath(publicApi, '/agents/{agent_id}'), '/v1/agents/{agent_id}') + assert.equal(fullPath(coreApi, '/core/v1/sandbox/deployment'), '/core/v1/sandbox/deployment') + assert.equal(fullPath(publicApi, '/v1'), '/v1') +}) + +test('operation descriptions split into a lead and details', () => { + assert.deepEqual(splitDescription('Saves an Agent.\n\n- Limit one.\n- Limit two.'), { lead: 'Saves an Agent.', details: '- Limit one.\n- Limit two.' }) + // A single paragraph splits after the first sentences that reach 40 characters. + assert.deepEqual(splitDescription('Core key only. Returns the harnesses Core supports. Keys are never returned.'), + { lead: 'Core key only. Returns the harnesses Core supports.', details: 'Keys are never returned.' }) + // Abbreviations and paths do not end a sentence; a short description stays whole. + assert.deepEqual(splitDescription('Returns metadata, e.g. the ID, for /v1.x files.'), { lead: 'Returns metadata, e.g. the ID, for /v1.x files.', details: '' }) + assert.deepEqual(splitDescription(undefined), { lead: '', details: '' }) +}) + +test('a lead loses inline markdown because page descriptions are plain text', () => { + assert.equal(plainText('With `stream=true`, see **[Request conventions](/request-conventions)**.'), 'With stream=true, see Request conventions.') +}) + +test('contract markdown is escaped for MDX outside code spans only', () => { + assert.equal(mdxText('an empty body is {} and `{}` or '), 'an empty body is {} and `{}` or <key>') +}) test('public rendering preserves operation prose, schemas and project authentication', () => { const fixture = { swagger: '2.0', info: { title: 'Example', version: '1' }, basePath: '/v1', paths: { diff --git a/apps/docs/scripts/generate-api-reference.mjs b/apps/docs/scripts/generate-api-reference.mjs index b9b706b46..fb3191619 100644 --- a/apps/docs/scripts/generate-api-reference.mjs +++ b/apps/docs/scripts/generate-api-reference.mjs @@ -1,12 +1,18 @@ #!/usr/bin/env node // Render the actual contracts without copying prose from superseded API surfaces. +// +// One page per operation, in one folder per tag. A page renders a single +// operation: a whole tag on one page (up to 11 operations with their full +// request and response schemas) took 4-10 seconds to render and weighed +// 1.4-1.8 MB, which stalled navigation. Each tag folder keeps an overview page +// at the former tag URL, so /api-reference/sessions still resolves. import { generateFilesOnly } from 'fumadocs-openapi' import { createOpenAPI } from 'fumadocs-openapi/server' import yaml from 'js-yaml' import fs from 'node:fs' import path from 'node:path' import crypto from 'node:crypto' -import { appRoot, repoRoot, surfaces, sourcePath, normalise } from './contracts.mjs' +import { appRoot, repoRoot, surfaces, sourcePath, normalise, methods, splitDescription, mdxText, plainText, fullPath } from './contracts.mjs' const root = path.join(appRoot, 'content/docs/api-reference') fs.rmSync(root, { recursive: true, force: true }) fs.mkdirSync(root, { recursive: true }) @@ -14,25 +20,106 @@ fs.rmSync(path.join(appRoot, 'openapi'), { recursive: true, force: true }) fs.mkdirSync(path.join(appRoot, 'openapi')) const record = { sources: {}, outputs: {} } const digest = file => crypto.createHash('sha256').update(fs.readFileSync(file)).digest('hex') +const slug = text => text.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '') +// Record keys are POSIX paths, so a record generated on Linux verifies on Windows. +const key = (from, file) => path.relative(from, file).split(path.sep).join('/') +const write = (file, text) => { + fs.mkdirSync(path.dirname(file), { recursive: true }) + fs.writeFileSync(file, text) + record.outputs[key(appRoot, file)] = digest(file) +} +const yamlString = text => JSON.stringify(text) + +// The lead goes under the title and into search metadata; the details render in +// the page body above the request. +function withSplitDescription(content) { + const match = /^---\n([\s\S]*?)\n---\n/.exec(content) + if (!match) throw new Error('Generated page without frontmatter') + const frontmatter = yaml.load(match[1]) + const { lead, details } = splitDescription(frontmatter.description) + frontmatter.description = plainText(lead) + const body = content.slice(match[0].length) + const at = body.indexOf(' s.directory === '/' + folder)) throw new Error(`Tag ${JSON.stringify(tag)} collides with the ${folder} reference.`) + folderOf.set(folder, tag) + } + const pageOf = new Map() + for (const { folder, operations } of tags.values()) { + const taken = new Set() + for (const entry of operations) { + const name = slug(entry.operation.summary || `${entry.method} ${entry.route}`) + if (taken.has(name)) throw new Error(`Two ${folder} operations share the page name ${name}; give them distinct summaries.`) + taken.add(name) + pageOf.set(`${entry.method} ${entry.route}`, { folder, name }) + } + } + const files = await generateFilesOnly({ + input: createOpenAPI({ input: [output] }), + per: 'operation', + groupBy: 'tag', + slugify: slug, + name: entry => { + const page = pageOf.get(`${entry.item.method} ${entry.item.path}`) + if (!page) throw new Error('Unexpected generated entry: ' + JSON.stringify(entry.item)) + return page.name + }, + }) const directory = root + surface.directory - fs.mkdirSync(directory, { recursive: true }) + const expected = new Set([...pageOf.values()].map(page => `${page.folder}/${page.name}.mdx`)) for (const file of files) { - const target = path.join(directory, file.path) - fs.writeFileSync(target, file.content.replace(/document=\{[^}]*\}/, `document={${JSON.stringify(surface.id)}}`)) - record.outputs[path.relative(appRoot, target)] = digest(target) + const relative = file.path.split(path.sep).join('/') + if (!expected.delete(relative)) throw new Error('Unexpected generated page: ' + relative) + write(path.join(directory, relative), withSplitDescription(file.content).replace(/document=\{[^}]*\}/, `document={${JSON.stringify(surface.id)}}`)) + } + if (expected.size) throw new Error('Operations without a generated page: ' + [...expected].join(', ')) + const pages = pageOf.size + // Each tag folder: an overview at the tag URL and the operations in contract order. + for (const [tag, { folder, operations }] of tags) { + const rows = operations.map(({ route, method, operation }) => { + const page = pageOf.get(`${method} ${route}`) + return `| [${operation.summary ?? route}](/api-reference${surface.directory}/${folder}/${page.name}) | \`${method.toUpperCase()}\` | \`${fullPath(surface, route)}\` |` + }) + const description = `${tag}. ${surface.title}: ${surface.credential}.` + write(path.join(directory, folder, 'index.mdx'), `---\ntitle: ${yamlString(tag)}\ndescription: ${yamlString(description)}\n---\n\n${surface.authority}\n\n| Operation | Method | Path |\n| --- | --- | --- |\n${rows.join('\n')}\n`) + // Leaving index out of pages makes it the folder's own link: the tag name + // opens the overview and expands the operations. + write(path.join(directory, folder, 'meta.json'), JSON.stringify({ title: tag, pages: operations.map(({ route, method }) => pageOf.get(`${method} ${route}`).name) }, null, 2) + '\n') } - const pages = ['index', ...files.map(file => file.path.replace(/\.mdx$/, ''))] - if (!surface.directory) pages.push('core', 'machine') - fs.writeFileSync(path.join(directory, 'meta.json'), JSON.stringify({ title: surface.title, pages }, null, 2) + '\n') - const body = `---\ntitle: ${surface.title}\ndescription: ${surface.prefix} — ${surface.credential}.\n---\n\n${surface.authority}\n\n**Credential:** ${surface.credential}. Examples use reserved \`example.com\` origins. This reference does not send requests or collect credentials.\n\n${surface.id === 'runtime-api' ? 'This schema covers node configuration, enrollment and identity. Daemon WebSockets and executor connection details are described in the [machine overview](/public-api#machine-connection-api).\n\n' : ''}${surface.id === 'core-api' ? 'Operator scripts use Core’s loopback port. The public entry routes management through Web, which requires its signed-in session and supplies the Core key on the server.\n\n' : ''}[API namespaces and credentials](/public-api) · [Application reference](/api-reference) · [Administration reference](/api-reference/core) · [Machine reference](/api-reference/machine)\n\n` + files.map(file => `- [${file.path.replace(/\.mdx$/, '')}](/api-reference${surface.directory}/${file.path.replace(/\.mdx$/, '')})`).join('\n') + '\n' - fs.writeFileSync(path.join(directory, 'index.mdx'), body) - record.sources[path.relative(repoRoot, sourcePath(surface))] = digest(sourcePath(surface)) - record.outputs[path.relative(appRoot, output)] = digest(output) - for (const name of ['meta.json', 'index.mdx']) record.outputs[path.relative(appRoot, path.join(directory, name))] = digest(path.join(directory, name)) - console.log(surface.id + ': ' + files.length + ' tag pages') + const folders = [...tags.values()].map(tag => tag.folder) + // As in tag folders, the surface overview is the folder's own link. + const meta = [...folders] + if (!surface.directory) meta.push('core', 'machine') + write(path.join(directory, 'meta.json'), JSON.stringify({ title: surface.title, pages: meta }, null, 2) + '\n') + const body = `---\ntitle: ${surface.title}\ndescription: ${surface.prefix} — ${surface.credential}.\n---\n\n${surface.authority}\n\n**Credential:** ${surface.credential}. Examples use reserved \`example.com\` origins. This reference does not send requests or collect credentials.\n\n${surface.id === 'runtime-api' ? 'This schema covers node configuration, enrollment and identity, and native Runtime installation. Daemon WebSockets and executor connection details are described in the [machine overview](/public-api#machine-connection-api).\n\n' : ''}${surface.id === 'core-api' ? 'Operator scripts use Core’s loopback port. The public entry routes management through Web, which requires its signed-in session and supplies the Core key on the server.\n\n' : ''}[API namespaces and credentials](/public-api) · [Application reference](/api-reference) · [Administration reference](/api-reference/core) · [Machine reference](/api-reference/machine) · [Error codes](/error-codes)\n\n` + [...tags].map(([tag, { folder, operations }]) => `- [${tag}](/api-reference${surface.directory}/${folder}) · ${operations.length} ${operations.length === 1 ? 'operation' : 'operations'}`).join('\n') + '\n' + write(path.join(directory, 'index.mdx'), body) + record.sources[key(repoRoot, sourcePath(surface))] = digest(sourcePath(surface)) + record.outputs[key(appRoot, output)] = digest(output) + console.log(`${surface.id}: ${pages} operation pages in ${tags.size} tags`) } fs.writeFileSync(path.join(appRoot, 'openapi/sources.json'), JSON.stringify(record, null, 2) + '\n') diff --git a/apps/docs/scripts/guides.json b/apps/docs/scripts/guides.json index 5ef23e97a..3572a2d47 100644 --- a/apps/docs/scripts/guides.json +++ b/apps/docs/scripts/guides.json @@ -53,6 +53,12 @@ "title": "API namespaces and credentials", "description": "The public application API, private administration API and machine connection interface." }, + { + "slug": "request-conventions", + "source": "docs/api/request-conventions.md", + "title": "Request conventions", + "description": "Headers, JSON body checks, list parameters and errors shared by every /v1 operation." + }, { "slug": "agents-and-tools", "source": "contracts/agents-api/execution-tools.md", @@ -110,6 +116,12 @@ "title": "Core administration API", "description": "Management operations and their server-side credential boundary." }, + { + "slug": "error-codes", + "source": "contracts/agents-api/error-codes.md", + "title": "Error codes", + "description": "Every error code Core, the console and the machine transport write, and what each means." + }, { "slug": "observability", "source": "contracts/agents-api/runtime-observability-api.md", diff --git a/apps/docs/scripts/test_contract_routes.py b/apps/docs/scripts/test_contract_routes.py index 243b9dd75..d6f8b3050 100644 --- a/apps/docs/scripts/test_contract_routes.py +++ b/apps/docs/scripts/test_contract_routes.py @@ -19,6 +19,12 @@ def test_nested_registration_inherits_parent_scope(self): child = routes.Region('r.Get("/projects/{project_id}", h.getProject)') self.assertEqual(child.routes({"r": "/core/v1"}), [("/core/v1/projects/{project_id}", "GET")]) + def test_transport_paths_are_all_accounted_for(self): + registered = routes.transport_paths() + self.assertIn("/api/v1/sandbox-node/connect", registered) + self.assertIn("/api/v1/agent-daemon/ws", registered) + self.assertEqual(registered, set(routes.TRANSPORT)) + def test_unrelated_router_does_not_acquire_a_prefix(self): region = routes.Region('unknown.Get("/projects", handler)') self.assertEqual(region.routes({"r": "/core/v1"}), []) diff --git a/apps/docs/scripts/verify-api-copy.mjs b/apps/docs/scripts/verify-api-copy.mjs index 743a100ef..d1fa5d381 100644 --- a/apps/docs/scripts/verify-api-copy.mjs +++ b/apps/docs/scripts/verify-api-copy.mjs @@ -1,25 +1,44 @@ #!/usr/bin/env node -// Compare every rendered operation and schema with the current contract projection. +// Compare every rendered operation and schema with the current contract projection, +// and every tag folder's navigation and overview with its operation pages. import fs from 'node:fs' import path from 'node:path' import yaml from 'js-yaml' import assert from 'node:assert/strict' -import { appRoot, surfaces, normalise, methods } from './contracts.mjs' +import { appRoot, surfaces, normalise, methods, fullPath } from './contracts.mjs' let count = 0 for (const surface of surfaces) { const actual = yaml.load(fs.readFileSync(path.join(appRoot, 'openapi', surface.id + '.yaml'), 'utf8')) assert.deepEqual(actual, normalise(surface), surface.id + ': rendered contract differs') const listed = [] const dir = path.join(appRoot, 'content/docs/api-reference') + surface.directory - for (const name of fs.readdirSync(dir).filter(n => n.endsWith('.mdx') && n !== 'index.mdx')) { - const content = fs.readFileSync(path.join(dir, name), 'utf8') - assert.ok(content.includes('document={' + JSON.stringify(surface.id) + '}'), 'Wrong reference credential surface: ' + name) - const operations = content.match(/operations=\{(\[[\s\S]*?\])\}/) - assert.ok(operations, 'Missing operations: ' + name) - for (const op of JSON.parse(operations[1])) listed.push(op.method + ' ' + op.path) + // Operation pages live one level down, in a folder per tag; index.mdx files + // are overviews. Other surfaces' directories (core, machine) are skipped. + const other = new Set(surfaces.filter(s => s.directory && s !== surface).map(s => s.directory.slice(1))) + const folders = fs.readdirSync(dir, { withFileTypes: true }).filter(e => e.isDirectory() && !other.has(e.name)).map(e => e.name) + const routes = new Set(Object.entries(actual.paths).flatMap(([route, item]) => methods.filter(m => item[m]).map(m => `${m.toUpperCase()} ${fullPath(surface, route)}`))) + for (const folder of folders) { + const folderDir = path.join(dir, folder) + const pages = fs.readdirSync(folderDir).filter(n => n.endsWith('.mdx') && n !== 'index.mdx').map(n => n.slice(0, -4)) + // The sidebar shows exactly the folder's pages; a page missing from meta.json is unreachable. + const meta = JSON.parse(fs.readFileSync(path.join(folderDir, 'meta.json'), 'utf8')) + assert.deepEqual([...meta.pages].sort(), [...pages].sort(), `${surface.id}/${folder}: meta.json pages differ from its operation pages`) + // The overview links every page once, with the path a caller sends. + const overview = fs.readFileSync(path.join(folderDir, 'index.mdx'), 'utf8') + const rows = [...overview.matchAll(/^\| \[[^\]]*\]\(([^)]+)\) \| `([A-Z]+)` \| `([^`]+)` \|$/gm)] + assert.deepEqual(rows.map(r => r[1].split('/').pop()).sort(), [...pages].sort(), `${surface.id}/${folder}: overview rows differ from its operation pages`) + for (const [, , method, route] of rows) assert.ok(routes.has(`${method} ${route}`), `${surface.id}/${folder}: overview lists ${method} ${route}, which the contract does not publish`) + for (const name of pages) { + const content = fs.readFileSync(path.join(folderDir, name + '.mdx'), 'utf8') + assert.ok(content.includes('document={' + JSON.stringify(surface.id) + '}'), 'Wrong reference credential surface: ' + folder + '/' + name) + const operations = content.match(/operations=\{(\[[\s\S]*?\])\}/) + assert.ok(operations, 'Missing operations: ' + folder + '/' + name) + for (const op of JSON.parse(operations[1])) listed.push(op.method + ' ' + op.path) + } } const expected = Object.entries(actual.paths).flatMap(([route, item]) => methods.filter(m => item[m]).map(m => m + ' ' + route)) assert.deepEqual([...new Set(listed)].sort(), expected.sort(), 'Missing or obsolete API page: ' + surface.id) + assert.equal(listed.length, expected.length, 'An operation has more than one page: ' + surface.id) count += expected.length } -console.log(count + ' operations, schemas, descriptions and credential surfaces match current contracts.') +console.log(count + ' operations, schemas, descriptions, navigation, overviews and credential surfaces match current contracts.') diff --git a/apps/docs/scripts/verify-contract-freshness.mjs b/apps/docs/scripts/verify-contract-freshness.mjs index 785c6dc3c..d72357523 100644 --- a/apps/docs/scripts/verify-contract-freshness.mjs +++ b/apps/docs/scripts/verify-contract-freshness.mjs @@ -10,7 +10,8 @@ assert.deepEqual(Object.keys(record.sources).sort(), surfaces.map(s => 'contract function filesUnder(directory) { return fs.readdirSync(directory, { withFileTypes: true }).flatMap(entry => { const file = path.join(directory, entry.name) - return entry.isDirectory() ? filesUnder(file) : [path.relative(appRoot, file)] + // Record keys are POSIX paths on every platform. + return entry.isDirectory() ? filesUnder(file) : [path.relative(appRoot, file).split(path.sep).join('/')] }) } const rendered = [...filesUnder(path.join(appRoot, 'openapi')), ...filesUnder(path.join(appRoot, 'content/docs/api-reference'))] diff --git a/apps/docs/scripts/verify-contract-routes.py b/apps/docs/scripts/verify-contract-routes.py index c9f51d2f5..ebeb90a92 100644 --- a/apps/docs/scripts/verify-contract-routes.py +++ b/apps/docs/scripts/verify-contract-routes.py @@ -41,6 +41,30 @@ IGNORED = {("/healthz", "GET"): "liveness probe, not part of the Agent API"} +# Machine transport served beside the API router by cmd/server. These are not +# REST operations and no OpenAPI contract publishes them; each must be named in +# the API index, and its error shapes in contracts/agents-api/error-codes.md. +SERVER = REPO / "services/agents-api/cmd/server/http_routes.go" +GATEWAY = REPO / "internal/agentdaemon/gateway/routes.go" +# The Runtime gateway mounts the daemon routes under this prefix. +GATEWAY_MOUNT = REPO / "services/agents-api/internal/runtime/gateway.go" +MOUNT = re.compile(r"\.Route\(\s*\"([^\"]+)\"\s*,\s*func\([^)]*\)\s*\{\s*gateway\.RegisterRoutes\(") +INDEX = REPO / "docs/api/README.md" +# mux.Handle or mux.HandleFunc, with the handler expression. +MUX = re.compile(r"\bmux\.Handle(?:Func)?\(\s*\"([^\"]+)\"\s*,\s*([\w.]+)") +# A chi Handle or HandleFunc mounts a non-REST handler, such as static artifacts. +CHI_HANDLE = re.compile(r"\b\w+\.Handle(?:Func)?\(\s*\"(/api/v1/[^\"]+)\"") +TRANSPORT = { + "/api/v1/agent-daemon/": "prefix of the daemon gateway routes below", + "/api/v1/agent-daemon/enroll": "self-hosted executor enrollment; plain-text errors", + "/api/v1/agent-daemon/connection": "self-hosted executor connection check; plain-text errors", + "/api/v1/agent-daemon/ws": "daemon WebSocket", + "/api/v1/agent-daemon/bootstrap": "daemon bootstrap", + "/api/v1/agent-daemon/device-status": "daemon self-check", + "/api/v1/sandbox-node/connect": "node WebSocket; plain-text errors", + "/api/v1/agent-daemon/install/": "public immutable native installer artifacts", +} + # Differences between the contract and the registered route that the reference # accepts on purpose, keyed (path, method) as the contract spells them. ACCEPTED = {} @@ -190,7 +214,7 @@ def main() -> int: base = (document.get("basePath") or "").rstrip("/") for route, item in (document.get("paths") or {}).items(): for method in item: - if method in ("get", "post", "put", "patch", "delete", "head", "options"): + if method in ("get", "post", "put", "patch", "delete", "head", "options", "trace"): documented.setdefault(((base + route) or "/", method.upper()), label) guard_paths = set() @@ -220,7 +244,47 @@ def main() -> int: print(" %-6s %-72s [%s]" % (method, path, documented[(path, method)])) for path, method in accepted: print(" ok %-72s %s" % (path, ACCEPTED[(path, method)])) - return 1 if real or undocumented else 0 + print() + transport_problems = check_transport() + return 1 if real or undocumented or transport_problems else 0 + + +def transport_paths() -> set[str]: + """Paths cmd/server mounts beside the API, plus the daemon gateway routes.""" + server = SERVER.read_text(encoding="utf-8") + # Paths handed back to the API router are API routes, checked by [A] and [B]. + paths = {path for path, handler in MUX.findall(server) if path != "/" and handler != "apiHandler"} + for name in sorted(API.glob("*.go")): + if not name.name.endswith("_test.go"): + paths.update(path.rstrip("*") for path in CHI_HANDLE.findall(name.read_text(encoding="utf-8"))) + mounts = MOUNT.findall(GATEWAY_MOUNT.read_text(encoding="utf-8")) + if len(mounts) != 1: + raise ValueError("expected one gateway.RegisterRoutes mount in " + str(GATEWAY_MOUNT)) + gateway = Region(GATEWAY.read_text(encoding="utf-8")) + paths.update(path for path, _ in gateway.routes({"r": mounts[0]})) + return paths + + +def check_transport() -> int: + registered = transport_paths() + index = INDEX.read_text(encoding="utf-8") + problems = [] + for path in sorted(registered - TRANSPORT.keys()): + problems.append("registered transport path with no TRANSPORT entry: " + path) + for path in sorted(TRANSPORT.keys() - registered): + problems.append("TRANSPORT entry no longer registered: " + path) + for path in sorted(registered & TRANSPORT.keys()): + tail = path[len("/api/v1/"):].rstrip("/") + # The index names each route in backticks, optionally after its method. + mention = re.compile(r"`(?:[A-Z]+ )?" + re.escape(tail) + r"`") + if not path.endswith("/") and not mention.search(index): + problems.append("transport path missing from docs/api/README.md: " + path) + print(" [C] Machine transport outside the contracts: %d (%d problems)" % (len(registered), len(problems))) + for path in sorted(registered & TRANSPORT.keys()): + print(" ok %-72s %s" % (path, TRANSPORT[path])) + for problem in problems: + print(" " + problem) + return len(problems) if __name__ == "__main__": diff --git a/apps/docs/scripts/verify-error-codes.mjs b/apps/docs/scripts/verify-error-codes.mjs new file mode 100644 index 000000000..46450e99b --- /dev/null +++ b/apps/docs/scripts/verify-error-codes.mjs @@ -0,0 +1,138 @@ +#!/usr/bin/env node +// Keep client-side error codes tied to the registry: codes the TypeScript +// client creates itself and codes the client and Web compare against. +// +// This is half of the registry check. The other half, every status and code the +// Go services write, is services/agents-api/internal/api/contract_conformance_test.go, +// which runs in `make check-agents-api`, not in `pnpm verify`. Both run in CI. +import fs from 'node:fs' +import path from 'node:path' +import assert from 'node:assert/strict' +import { repoRoot } from './contracts.mjs' + +const registry = fs.readFileSync(path.join(repoRoot, 'contracts/agents-api/error-codes.md'), 'utf8') + +// Codes by registry section, from the code column of each table row. +const sections = new Map() +let heading = null +for (const line of registry.split('\n')) { + if (line.startsWith('## ')) { heading = line.slice(3).trim(); sections.set(heading, new Set()); continue } + const cells = line.split('|').map(cell => cell.trim()) + if (!heading || cells.length < 3) continue + for (const cell of cells.slice(1, 3)) { + const match = /^`([a-z0-9_]+)`$/.exec(cell) + if (match) { sections.get(heading).add(match[1]); break } + } +} +const known = new Set([...sections.values()].flatMap(set => [...set])) + +// Session diagnostic categories are not HTTP codes; core-errors.md owns them. +const coreErrors = fs.readFileSync(path.join(repoRoot, 'contracts/agents-api/core-errors.md'), 'utf8') +const diagnostics = /^## Diagnostic failure categories\n([\s\S]*?)(?=^## |(?![\s\S]))/m.exec(coreErrors) +assert.ok(diagnostics, 'core-errors.md has no Diagnostic failure categories section') +for (const match of diagnostics[1].matchAll(/^\| `([a-z0-9_]+)` \|/gm)) known.add(match[1]) + +// Codes Web still compares against although nothing emits them, with the owner's +// follow-up. An entry here is a known defect, not an accepted code. +const retired = new Map() + +function sources(directory) { + return fs.readdirSync(directory, { withFileTypes: true }).flatMap(entry => { + const file = path.join(directory, entry.name) + if (entry.isDirectory()) return entry.name === 'node_modules' ? [] : sources(file) + return /\.(ts|tsx)$/.test(entry.name) && !/\.test\.(ts|tsx)$/.test(entry.name) ? [file] : [] + }) +} + +// Top-level arguments of the call whose "(" is at index open. Strings, +// template literals and nested brackets are skipped; this is enough for the +// client sources, which a type checker already keeps well formed. +function callArguments(text, open) { + const args = [] + let depth = 0, start = open + 1, quote = null + for (let i = open; i < text.length; i++) { + const c = text[i] + if (quote) { + if (c === '\\') i++ + else if (c === quote) quote = null + continue + } + if (c === '"' || c === "'" || c === '`') quote = c + else if ('([{'.includes(c)) depth++ + else if (')]}'.includes(c)) { + depth-- + if (depth === 0) { args.push(text.slice(start, i).trim()); return Object.assign(args.filter(a => a !== ''), { end: i }) } + } else if (c === ',' && depth === 1) { args.push(text.slice(start, i).trim()); start = i + 1 } + } + return args +} +const literal = arg => /^"([a-z0-9_]+)"$/.exec(arg ?? '')?.[1] +const calls = (text, name) => [...text.matchAll(new RegExp(`(?()]*>)?\\s*\\(`, 'g'))] + .map(match => callArguments(text, match.index + match[0].length - 1)) + +const files = ['packages/agents-client/src', 'apps/web/src'].flatMap(root => sources(path.join(repoRoot, root))) + .map(file => ({ file, text: fs.readFileSync(file, 'utf8') })) + +// A forwarder is a function that passes one of its parameters on as an +// AgentCoreError code, directly or through another forwarder. Codes given to a +// forwarder as literals are created codes as well. +const forwarders = new Map([['AgentCoreError', 2]]) // new AgentCoreError(message, status, code, param?) +const definitions = files.flatMap(({ text }) => [...text.matchAll(/\bfunction\s+(\w+)\s*(?:<[^()]*>)?\s*\(/g)].map(match => { + const open = match.index + match[0].length - 1 + const list = callArguments(text, open) + const params = list.map(param => /^(?:\.\.\.)?(\w+)/.exec(param)?.[1]) + // A return type may itself be an object type, so the body is taken up to the + // function's closing brace at column 0 rather than from the first "{". + const start = list.end ?? open + const close = text.indexOf('\n}', start) + return { name: match[1], params, body: text.slice(start, close < 0 ? text.length : close + 2) } +})) +for (let changed = true; changed;) { + changed = false + for (const { name, params, body } of definitions) { + if (forwarders.has(name)) continue + for (const [target, index] of forwarders) { + const forwarded = calls(body, target).map(args => params.indexOf(args[index])).find(position => position >= 0) + if (forwarded !== undefined) { forwarders.set(name, forwarded); changed = true; break } + } + } +} + +const created = new Map() +const compared = new Map() +const note = (map, code, file) => map.set(code, [...(map.get(code) ?? []), path.relative(repoRoot, file)]) +for (const { file, text } of files) { + for (const [name, index] of forwarders) { + for (const args of calls(text, name)) { + const code = literal(args[index]) + if (code) note(created, code, file) + } + } + for (const match of text.matchAll(/(typeof\s+[\w.?]*)?\bcode\s*[!=]==?\s*"([a-z0-9_]+)"|"([a-z0-9_]+)"\s*[!=]==?\s*[\w.?]*\bcode\b/g)) { + if (match[1]) continue // typeof value.code === "string" checks a type, not a code + note(compared, match[2] ?? match[3], file) + } +} + +const client = sections.get('Client-generated codes') +assert.ok(client, 'error-codes.md has no Client-generated codes section') +const server = new Set([...sections].filter(([name]) => name !== 'Client-generated codes').flatMap(([, codes]) => [...codes])) +const problems = [] +for (const [code, sites] of created) { + // The client may rebuild a Core error with the same code, dropping unsafe fields. + if (!client.has(code) && !server.has(code)) problems.push(`client creates ${code} (${[...new Set(sites)].join(', ')}) but the Client-generated codes table does not list it`) +} +for (const code of client) { + if (!created.has(code)) problems.push(`Client-generated codes lists ${code}, which no client source creates`) + if (server.has(code)) problems.push(`${code} is listed both as a Core code and as client-generated`) +} +for (const [code, files] of compared) { + if (!known.has(code) && !retired.has(code)) problems.push(`${[...new Set(files)].join(', ')} compares against ${code}, which error-codes.md does not list`) +} +for (const [code, reason] of retired) { + if (known.has(code)) problems.push(`${code} is listed in error-codes.md; remove it from the retired list`) + if (!compared.has(code)) problems.push(`${code} is no longer compared; remove it from the retired list`) + else console.warn('Known defect: ' + reason) +} +assert.deepEqual(problems, [], 'Error code registry is out of date:\n' + problems.join('\n')) +console.log(`${created.size} client-created codes (through ${forwarders.size - 1} forwarding helpers) and ${compared.size} compared codes match the registry.`) From b2e7993c583631fe4946309d3a8ae2fe91571044 Mon Sep 17 00:00:00 2001 From: Yao Date: Wed, 30 Sep 2026 07:09:55 +0800 Subject: [PATCH 04/14] docs: drop the stale bootstrap_unavailable registry row Nothing writes this code, and the registry check reported the stale row. --- contracts/agents-api/error-codes.md | 1 - 1 file changed, 1 deletion(-) diff --git a/contracts/agents-api/error-codes.md b/contracts/agents-api/error-codes.md index b84921b23..e6c5df0f4 100644 --- a/contracts/agents-api/error-codes.md +++ b/contracts/agents-api/error-codes.md @@ -224,7 +224,6 @@ failure. | 405 | `method_not_allowed` | Bootstrap without POST, if the handler is reached; the router's empty 405 normally answers first | | 426 | `incompatible_version` | The daemon version is not supported by this Core | | 500 | `internal` | Authentication failed unexpectedly | -| 503 | `bootstrap_unavailable` | The Runtime connection address is unavailable | ## Plain-text transport responses From 01a08c689e9e93fd139c18a4e73d115d64226dd5 Mon Sep 17 00:00:00 2001 From: Yao Date: Wed, 30 Sep 2026 07:36:29 +0800 Subject: [PATCH 05/14] docs: complete the error code registry Rename "Agents API and Core API codes" to "HTTP API codes": its anchor tripped the retired-identifier name guard. List the sandbox_error and environment_connection_failed error objects the store records in Session events, and scan internal/store for them in the registry test. Scope out Turn error.code, which Core always publishes as internal_error. Add the console api-keys 404, the domain setup 405 and the installer artifact 405/404 responses; include unconfigured Runtime observation in execution_unavailable; correct which machine routes the OpenAPI publishes; and drop the list-query note from admin Files and Skills operations that are not lists. --- apps/docs/scripts/verify-contract-routes.py | 3 +- contracts/agents-api/error-codes.md | 31 +++++++++++++------ docs/api/README.md | 5 +-- .../internal/api/contract_conformance_test.go | 15 ++++++--- 4 files changed, 38 insertions(+), 16 deletions(-) diff --git a/apps/docs/scripts/verify-contract-routes.py b/apps/docs/scripts/verify-contract-routes.py index ebeb90a92..836e0b9dd 100644 --- a/apps/docs/scripts/verify-contract-routes.py +++ b/apps/docs/scripts/verify-contract-routes.py @@ -43,7 +43,8 @@ # Machine transport served beside the API router by cmd/server. These are not # REST operations and no OpenAPI contract publishes them; each must be named in -# the API index, and its error shapes in contracts/agents-api/error-codes.md. +# the API index. Their error shapes are listed in contracts/agents-api/error-codes.md +# and checked by the Go registry tests, not here. SERVER = REPO / "services/agents-api/cmd/server/http_routes.go" GATEWAY = REPO / "internal/agentdaemon/gateway/routes.go" # The Runtime gateway mounts the daemon routes under this prefix. diff --git a/contracts/agents-api/error-codes.md b/contracts/agents-api/error-codes.md index e6c5df0f4..1b968d813 100644 --- a/contracts/agents-api/error-codes.md +++ b/contracts/agents-api/error-codes.md @@ -16,23 +16,24 @@ Meaning columns are maintained by review. ## Which "code" is meant -The word names seven different things. Only the first three are HTTP error codes. +The word names eight different things. Only the first three are HTTP error codes. | Layer | Where it appears | Examples | Reference | | --- | --- | --- | --- | -| API envelope | `error.code` of a `/v1`, `/core/v1` or `/api/v1` JSON error, or of an event stream `error` frame | `invalid_request_error`, `project_archived`, `stream_interrupted` | [Agents API and Core API codes](#agents-api-and-core-api-codes), [event stream codes](#event-stream-error-codes) | +| API envelope | `error.code` of a `/v1`, `/core/v1` or `/api/v1` JSON error, or of an error object inside a Session event | `invalid_request_error`, `project_archived`, `stream_interrupted` | [HTTP API codes](#http-api-codes), [Session event codes](#session-event-error-codes) | | Console envelope | `error.code` of an error Web's server writes for `/core/*` | `console_sign_in_required`, `core_unreachable` | [Console codes](#console-codes), [Core errors](core-errors.md) | | Daemon transport | `error` member of an `/api/v1/agent-daemon/*` JSON error | `missing_bearer`, `incompatible_version` | [Runtime daemon transport codes](#runtime-daemon-transport-codes) | | Runtime protocol result | `error_code` of a Core–Runtime message after connection, such as a workspace, preparation or cancellation result; Core validates each value against its message and maps it to its own outcome or stored cause; no API response returns it | `write_rejected`, `read_unconfirmed`, `cancel_timeout` | [Core–Runtime protocol](../../docs/runtime-protocol.md) and its typed payloads; not listed here | | Node diagnostic | `diagnostic` value inside a node payload; never an HTTP status | `docker_unavailable`, `kvm_unavailable` | [Sandbox deployment](sandbox-deployment.md), [nodes](../../docs/getting-started/nodes.md) | | Session diagnostic category | `code` of a failure category inside a successful Session diagnostics snapshot | `harness_error`, `runtime_disconnected` | [Diagnostic failure categories](core-errors.md#diagnostic-failure-categories) | +| Turn error | `error.code` of a failed Turn or subagent Turn in a successful read; Core always publishes `internal_error`, and the other values of the pinned enum are never returned | `internal_error` | The cause is in the [diagnostic failure categories](core-errors.md#diagnostic-failure-categories); not listed here | | Client identifier | `AgentCoreError.code` created by `packages/agents-client` without a response, or a local daemon/adapter error | `sandbox_configuration_unconfirmed`, `invalid_admin_response` | [Client-generated codes](#client-generated-codes), daemon and adapter guides | `error.type` is not a second code. It follows one rule: `server_error` for any 5xx, `conflict_error` for any 409, `not_found_error` or `invalid_beta` when the code is that value, and `invalid_request_error` otherwise. -## Agents API and Core API codes +## HTTP API codes `/v1`, `/core/v1` and `/api/v1` share one writer, so a code keeps its meaning in every namespace. `/core/v1` adds optional `details` ([Core errors](core-errors.md)). @@ -100,7 +101,7 @@ Clients branch on `code`, never on `message`. A `null` row is a response whose | 413 | `request_too_large` | all | The body exceeds the operation's limit, or an uploaded File or Skill exceeds its content limit | | 500 | `internal_error` | all | An unexpected persistence failure; no detail is exposed | | 503 | `authentication_unavailable` | `/v1` | Project API key authentication is temporarily unavailable; written before any operation runs | -| 503 | `execution_unavailable` | `/v1`, `/core/v1` | Execution is not available on this service, or a Core Runtime observation list exceeded its request budget | +| 503 | `execution_unavailable` | `/v1`, `/core/v1` | Execution or Core Runtime observation is not available on this service, or a Core Runtime observation list exceeded its request budget | | 503 | `stream_unavailable` | `/v1` | Live events or streaming creation are unavailable | | 503 | `credential_storage_unavailable` | `/v1`, `/core/v1` | Credential encryption is not configured | | 503 | `file_storage_unavailable` | `/v1`, `/core/v1` | Source File storage is not configured | @@ -128,15 +129,21 @@ Core's reverse-path canonicalization answers a path that cannot be decoded with plain-text 400 before any namespace is selected; a parsed request path always decodes, so this is not expected in practice. -## Event stream error codes +## Session event error codes -A live event stream has already answered 200. Core reports its own interruption -as an `event: error` frame whose `error` object has `code`, `type` and `message` -but no `param`; see [history, events and usage](history-events-usage.md). +These codes appear inside Session events, in a live stream that has already +answered 200 and in the saved event history. Core's own interruption is an +`event: error` frame whose `error` object has `code`, `type` and `message` but no +`param`. A hosted provisioning failure records the pinned `error` event, with a +null `param`, and the Environment state `error` of +`agent.session.environment.failed`, which has no `param`. See +[history, events and usage](history-events-usage.md). | Status | Code | Meaning | | --- | --- | --- | | 200 | `stream_interrupted` | The live stream was interrupted; reconnect, then read the Session and its saved Items to recover | +| 200 | `sandbox_error` | `error` event, type `environment_error`: the hosted Environment failed to provision; the message is a safe reason without command output | +| 200 | `environment_connection_failed` | Environment state error, type `environment_error`, in `agent.session.environment.failed` | ## Console codes @@ -199,7 +206,9 @@ Outside `/core/*` the console also answers an unsafe path with a plain-text 400, a wrong method on static pages and `/node-install/*` with a plain-text 405 (`Allow: GET, HEAD`), and unknown or direct `/v1` and `/api/v1` paths with a plain-text 404. After sign-in, `/core` and `/core/*` paths outside `/core/v1` -also get a plain-text 404. `GET /healthz` returns `200 ok` without +also get a plain-text 404, `/console/api-keys` and its subpaths a plain-text 404, +and `/console/installation/domain` with a method other than GET or POST a +plain-text 405 (`Allow: GET, POST`). `GET /healthz` returns `200 ok` without authentication. ## Runtime daemon transport codes @@ -237,6 +246,10 @@ These routes answer failures with a `text/plain` body and no code. | 409 | null | enroll, connection, sandbox-node/connect | The Environment is bound to another executor, or the node identity is already connected | | 503 | null | enroll, connection, sandbox-node/connect | Enrollment storage, node authentication or the connection owner is unavailable | +The public installer artifacts under `/api/v1/agent-daemon/install/{version}/` +answer a method other than GET or HEAD with an empty 405 and an unknown file with +a plain-text 404. + ## Client-generated codes `packages/agents-client` creates these `AgentCoreError` codes itself; Core never diff --git a/docs/api/README.md b/docs/api/README.md index 4c2869193..cb8bcc127 100644 --- a/docs/api/README.md +++ b/docs/api/README.md @@ -92,8 +92,9 @@ the Core key or a Project API key. | `POST agent-daemon/enroll`, `GET agent-daemon/connection` | Self-hosted executor and its installer | Executor credential from `/core/v1/projects/{project_id}/environments/{environment_id}/executor-credentials` | [Executor credentials](../../contracts/agents-api/environment-executor-credentials.md) | | WebSocket `GET agent-daemon/ws`, `POST agent-daemon/bootstrap`, `GET agent-daemon/device-status` | Runtime daemons | Daemon credential: Core writes one into each hosted sandbox it prepares; a self-hosted executor uses its executor credential | [Runtime enrollment](../../services/agents-api/README.md#user-managed-runtime-enrollment) | -Only the three `sandbox-node` HTTP routes are in the machine OpenAPI and use the -JSON error envelope. The node WebSocket and the daemon transport are served +Only the three `sandbox-node` HTTP routes and the two native installation routes +(`agent-daemon/installation` and its `/claim` subroute) are in the machine OpenAPI +and use the JSON error envelope. The node WebSocket and the daemon transport are served beside the API router: `agent-daemon/enroll`, `agent-daemon/connection` and `sandbox-node/connect` answer failures with a plain-text body and no code, and `agent-daemon/ws`, `bootstrap` and `device-status` answer the failures their diff --git a/services/agents-api/internal/api/contract_conformance_test.go b/services/agents-api/internal/api/contract_conformance_test.go index a16bafe69..d38aeee06 100644 --- a/services/agents-api/internal/api/contract_conformance_test.go +++ b/services/agents-api/internal/api/contract_conformance_test.go @@ -610,8 +610,8 @@ func returnedCodes(t *testing.T, p sourcePackage, out map[emittedCode][]string) } } -// streamErrorCodes collects v1.StreamError{Code: "..."} literals: error frames -// inside an event stream whose response status is already 200. +// streamErrorCodes collects v1.StreamError{Code: "..."} literals: error objects +// inside Session events, whose response status is already 200. func streamErrorCodes(p sourcePackage) map[emittedCode][]string { out := map[emittedCode][]string{} for _, file := range p.files { @@ -790,14 +790,21 @@ func TestErrorCodeRegistryMatchesEmittedCodes(t *testing.T) { "writeError": {1, 2}, "writeAPIError": {1, 2}, "writeCoreError": {1, 2}, }) returnedCodes(t, api, codes) - compareRegistry(t, "Agents API and Core API codes", codes) + compareRegistry(t, "HTTP API codes", codes) console := parseSourcePackage(t, filepath.Join(conformanceRepoRoot, "services/core-console")) consoleCodes := emittedCodes(t, console, map[string][2]int{"consoleCoreError": {1, 2}}) returnedCodes(t, console, consoleCodes) compareRegistry(t, "Console codes", consoleCodes) - compareRegistry(t, "Event stream error codes", streamErrorCodes(api)) + // The stream writes its own interruption; the store records the error objects + // of saved Session events. + events := streamErrorCodes(api) + store := parseSourcePackage(t, filepath.Join(conformanceRepoRoot, "services/agents-api/internal/store")) + for code, sites := range streamErrorCodes(store) { + events[code] = append(events[code], sites...) + } + compareRegistry(t, "Session event error codes", events) gateway := parseSourcePackage(t, filepath.Join(conformanceRepoRoot, "internal/agentdaemon/gateway")) daemon := emittedCodes(t, gateway, map[string][2]int{"writeAuthError": {1, 2}}) From e530688c4a0644991b769f51fd48f0fc4e1bc59e Mon Sep 17 00:00:00 2001 From: Yao Date: Wed, 30 Sep 2026 08:06:38 +0800 Subject: [PATCH 06/14] test: check installer domain codes and fix registry namespaces Compare the installation domain setup table with the rejections deploy/install/ingress.py answers with before it accepts a request. The machine routes share the stored-error writer, so list /api/v1 for invalid_name, not_found_error, idempotency_conflict, executor_credential_exists and 409 sandbox_reset_in_progress, and /v1 for runtime_node_unavailable, with the machine-specific triggers. Widen turn_conflict to Environment file writes. Request conventions: the Environment files list also takes limit, and a mismatched scope header gets the rejected-key 401. Drop the U+0000 rule that Session metadata and Vault creation repeated. --- contracts/agents-api/error-codes.md | 23 ++++---- docs/api/request-conventions.md | 6 +-- .../internal/api/contract_conformance_test.go | 54 +++++++++++++++++++ 3 files changed, 69 insertions(+), 14 deletions(-) diff --git a/contracts/agents-api/error-codes.md b/contracts/agents-api/error-codes.md index 1b968d813..601859b5a 100644 --- a/contracts/agents-api/error-codes.md +++ b/contracts/agents-api/error-codes.md @@ -11,8 +11,9 @@ Two checks compare it with the code. `contract_conformance_test.go` in be written somewhere and every written status and code to have a row, and the statuses of the uncoded tables to equal the statuses their handlers write. `apps/docs/scripts/verify-error-codes.mjs` does the same for client-generated -codes and for every code the client and Web compare against. The Namespaces and -Meaning columns are maintained by review. +codes and for every code the client and Web compare against, and the Go test +also compares the installation domain setup codes with the installer. The +Namespaces and Meaning columns are maintained by review. ## Which "code" is meant @@ -36,7 +37,7 @@ that value, and `invalid_request_error` otherwise. ## HTTP API codes `/v1`, `/core/v1` and `/api/v1` share one writer, so a code keeps its meaning in -every namespace. `/core/v1` adds optional `details` ([Core errors](core-errors.md)). +every namespace; a row names a namespace-specific trigger where one differs. `/core/v1` adds optional `details` ([Core errors](core-errors.md)). Clients branch on `code`, never on `message`. A `null` row is a response whose `code` is null. @@ -53,7 +54,7 @@ Clients branch on `code`, never on `message`. A `null` row is a response whose | 400 | `unsupported_or_invalid_configuration` | `/v1` | The configuration or input is outside what the selected harness supports | | 400 | `model_provider_required` | `/v1` | The Session resolved no model provider and cannot run | | 400 | `invalid_sandbox_configuration` | `/core/v1` | Sandbox deployment configuration is invalid | -| 400 | `invalid_name` | `/core/v1` | A Project, key or node name fails its length or character rules; `details.max_length` gives the limit | +| 400 | `invalid_name` | `/core/v1`, `/api/v1` | A Project, key or node name, including the name a node enrolls with, fails its length or character rules; on `/core/v1`, `details.max_length` gives the limit | | 400 | `invalid_node_capacity` | `/core/v1` | Node `max_active` or `max_retained` is outside 1-1000000, or retained is below active | | 400 | `invalid_model_provider` | `/core/v1` | The model configuration body is missing or malformed; a complete bundle is required | | 400 | `model_provider_base_url_invalid` | `/core/v1` | `base_url` is not HTTPS, or carries credentials, a query or a fragment | @@ -70,21 +71,21 @@ Clients branch on `code`, never on `message`. A `null` row is a response whose | 401 | `invalid_node_credential` | `/api/v1` | The node enrollment token or node credential is missing or wrong | | 401 | `installation_authorization_invalid` | `/api/v1` | The native installation authorization is invalid or expired; get a new command from the Session | | 401 | null | `/v1` | No valid Bearer Project API key on an Agents API Beta route, or none supplied to Files or Skills | -| 404 | `not_found_error` | `/v1`, `/core/v1` | The resource does not exist in the caller's or the selected Project's tenant | +| 404 | `not_found_error` | `/v1`, `/core/v1`, `/api/v1` | The resource does not exist in the caller's or the selected Project's tenant, or the Environment of a native installation no longer exists | | 404 | `not_found` | `/core/v1` | Unknown Core operation, unknown harness, or a harness without a deployment default model provider | | 404 | `unsupported_operation` | `/v1` | Unknown `/v1` operation | | 404 | null | `/v1` | Missing File or Skill on the public Files and Skills routes | | 405 | `unsupported_operation` | all | Method not allowed, including HEAD on content downloads and Runtime reads | | 409 | `conflict_error` | `/v1`, `/core/v1` | Official conflicts: Session not idle for deletion, pending input, MCP credential ambiguity, hosted environment failure or a different tool result | -| 409 | `turn_conflict` | `/v1` | The Turn cannot accept this input in its current state | -| 409 | `idempotency_conflict` | `/v1` | The Idempotency-Key was used with different input | +| 409 | `turn_conflict` | `/v1` | The Session or Turn cannot accept this change in its current state, such as an Environment file write while Session input is pending | +| 409 | `idempotency_conflict` | `/v1`, `/api/v1` | The Idempotency-Key was used with different input; on sandbox node enrollment, the node ID is already enrolled | | 409 | `environment_unavailable` | `/v1` | The Environment no longer accepts new input | | 409 | `environment_input_expired` | `/v1` | The Environment input deadline passed before admission | | 409 | `environment_input_cancelled` | `/v1` | The Environment input was cancelled before admission | | 409 | `project_exists` | `/core/v1` | The Project ID already exists | | 409 | `project_api_key_exists` | `/core/v1` | The API key ID already exists; list its metadata and revoke it if the secret was not saved | | 409 | `project_archived` | `/core/v1` | The target Project is archived | -| 409 | `executor_credential_exists` | `/core/v1` | The executor key ID already exists; rotate it explicitly to replace the secret | +| 409 | `executor_credential_exists` | `/core/v1`, `/api/v1` | The executor key ID already exists; rotate it explicitly to replace the secret. On the native installation claim, the Environment already has another, rotated or revoked executor credential | | 409 | `runtime_history_unsupported` | `/core/v1` | Runtime history is not supported for this Session | | 409 | `sandbox_deployment_conflict` | `/core/v1`, `/api/v1` | The sandbox deployment cannot change in its current state | | 409 | `sandbox_configuration_error` | `/core/v1` | The deployment cannot be served as configured, for example E2B with a loopback public URL | @@ -95,7 +96,7 @@ Clients branch on `code`, never on `message`. A `null` row is a response whose | 409 | `sandbox_generation_stale` | `/core/v1` | The deployment generation changed; `details.current_generation` gives the new one. Refresh before submitting again | | 409 | `sandbox_reset_required` | `/core/v1` | The change needs a reset first, such as another backend or E2B team; `details` names both providers | | 409 | `sandbox_in_use` | `/core/v1` | Hosted sandbox resources still belong to the deployment; `details.allocations` and `details.pending` count them | -| 409 | `sandbox_reset_in_progress` | `/core/v1` | A sandbox reset is in progress, so the deployment cannot change | +| 409 | `sandbox_reset_in_progress` | `/core/v1`, `/api/v1` | A sandbox reset is in progress, so the deployment cannot change and nodes cannot enroll or read their configuration | | 409 | `sandbox_not_configured` | `/core/v1` | The operation needs a configured sandbox deployment | | 409 | `e2b_team_mismatch` | `/core/v1` | The E2B key cannot manage the retained deployment; reset before changing teams (param `e2b.api_key`) | | 413 | `request_too_large` | all | The body exceeds the operation's limit, or an uploaded File or Skill exceeds its content limit | @@ -112,7 +113,7 @@ Clients branch on `code`, never on `message`. A `null` row is a response whose | 503 | `execution_configuration_unavailable` | `/core/v1` | Session execution configuration cannot be read | | 503 | `runtime_history_unavailable` | `/core/v1` | Durable Runtime history is not configured or temporarily unavailable | | 503 | `core_metrics_unavailable` | `/core/v1` | Core metrics are not configured or could not be read | -| 503 | `runtime_node_unavailable` | `/core/v1`, `/api/v1` | The selected sandbox node is unavailable or has no capacity | +| 503 | `runtime_node_unavailable` | `/v1`, `/core/v1`, `/api/v1` | The selected sandbox node is unavailable, or no node has capacity for a new hosted Session | | 503 | `sandbox_credential_unavailable` | `/core/v1`, `/api/v1` | Sandbox credentials cannot be decrypted; check the service credential encryption configuration | | 503 | `sandbox_reset_in_progress` | `/v1` | Hosted admission is paused while a sandbox reset runs; nothing was admitted | | 503 | `sandbox_nodes_preparing` | `/v1` | The nodes with free capacity are still preparing the deployment's Runtime | @@ -169,7 +170,7 @@ in `{"error":{"code":"…","message":"…"}}`. The installation controller in `deploy/install/ingress.py` writes them; see [Web management](../../docs/api/web-management.md) and the [installer contract](../../docs/maintainers.md#managed-https-ownership). Failures after the `202` acceptance are reported through the status `message`, -not as codes. This table is maintained by review. +not as codes. | Status | Code | Meaning | | --- | --- | --- | diff --git a/docs/api/request-conventions.md b/docs/api/request-conventions.md index e59781992..c4e18b9ff 100644 --- a/docs/api/request-conventions.md +++ b/docs/api/request-conventions.md @@ -9,7 +9,7 @@ from them. | --- | --- | | `Authorization` | `Bearer ` on every operation. See [API namespaces and credentials](README.md). | | `OpenAI-Beta` | Exactly one `agents=v1` value on every operation except Files (`/files`) and Skills (`/skills`). Otherwise 400 `invalid_beta`. The pinned SDK sends it. | -| `OpenAI-Organization`, `OpenAI-Project` | Optional. If present they must be `core` and `proj_`. | +| `OpenAI-Organization`, `OpenAI-Project` | Optional. If present they must be `core` and `proj_`; otherwise the request gets the same 401 as a rejected key. | | `Idempotency-Key` | Optional on Session creation and on event submission, up to 128 bytes. A Core extension: a retry with the same key and request returns the original result, and the same key with a different request returns 409 `idempotency_conflict`. A streamed Session creation retry is the exception; see Create an execution Session. The hosted service returned distinct Sessions for repeated creation keys; its event submission behavior is not documented. | ## JSON request bodies @@ -40,8 +40,8 @@ limit of Core's storage, not of the official API. ## Lists -Lists take `after`, `limit` and `order`; the Environment files list pages with -`path`, `page` and `order` instead. `order` is `asc` or `desc`; omitting it uses the +Lists take `after`, `limit` and `order`; the Environment files list takes `path`, +`limit` and `order` and continues with an opaque `page` token instead of `after`. `order` is `asc` or `desc`; omitting it uses the operation's default, and an explicitly empty value is invalid. Unknown query keys are ignored, and a supported scalar key given twice is rejected. Array parameters, such as the Vault and Credential `status[]` filter, may repeat. diff --git a/services/agents-api/internal/api/contract_conformance_test.go b/services/agents-api/internal/api/contract_conformance_test.go index d38aeee06..4058f7f4d 100644 --- a/services/agents-api/internal/api/contract_conformance_test.go +++ b/services/agents-api/internal/api/contract_conformance_test.go @@ -811,3 +811,57 @@ func TestErrorCodeRegistryMatchesEmittedCodes(t *testing.T) { returnedCodes(t, gateway, daemon) compareRegistry(t, "Runtime daemon transport codes", daemon) } + +// TestInstallationDomainCodesMatchRegistry keeps the relayed installer +// rejections equal to the codes deploy/install/ingress.py answers with before +// it accepts a domain request. verify and execute run after the 202, so their +// codes reach the caller only as the status message. +func TestInstallationDomainCodesMatchRegistry(t *testing.T) { + const source = "deploy/install/ingress.py" + raw, err := os.ReadFile(filepath.Join(conformanceRepoRoot, source)) + if err != nil { + t.Fatal(err) + } + text := string(raw) + definition := regexp.MustCompile(`(?m)^def (\w+)\(`) + enclosing := func(offset int) string { + name := "" + for _, match := range definition.FindAllStringSubmatchIndex(text[:offset], -1) { + name = text[match[2]:match[3]] + } + return name + } + line := func(offset int) string { return source + ":" + strconv.Itoa(strings.Count(text[:offset], "\n")+1) } + emitted := map[emittedCode][]string{} + add := func(status int, code string, offset int) { + key := emittedCode{status, code} + emitted[key] = append(emitted[key], line(offset)) + } + raised := regexp.MustCompile(`DomainError\("(\w+)", (?:"(?:[^"\\]|\\.)*"|[\w.()]+)(?:, (\d{3}))?\)`) + for _, match := range raised.FindAllStringSubmatchIndex(text, -1) { + if name := enclosing(match[0]); name == "verify" || name == "execute" { + continue + } + status := 400 + if match[4] >= 0 { + status, _ = strconv.Atoi(text[match[4]:match[5]]) + } + add(status, text[match[2]:match[3]], match[0]) + } + replied := regexp.MustCompile(`self\.reply\((\d{3}), \{"error": \{"code": "(\w+)"`) + for _, match := range replied.FindAllStringSubmatchIndex(text, -1) { + status, _ := strconv.Atoi(text[match[2]:match[3]]) + add(status, text[match[4]:match[5]], match[0]) + } + // The handler's fallback maps an installer error and invalid JSON to fixed pairs. + codes := regexp.MustCompile(`"(\w+)" if isinstance\(error, oac_cli\.OacError\) else "(\w+)"`).FindStringSubmatchIndex(text) + statuses := regexp.MustCompile(`(\d{3}) if isinstance\(error, oac_cli\.OacError\) else (\d{3})`).FindStringSubmatch(text) + if codes == nil || statuses == nil { + t.Fatalf("%s: the request handler's fallback error mapping changed; update this test", source) + } + busy, _ := strconv.Atoi(statuses[1]) + invalid, _ := strconv.Atoi(statuses[2]) + add(busy, text[codes[2]:codes[3]], codes[0]) + add(invalid, text[codes[4]:codes[5]], codes[0]) + compareRegistry(t, "Installation domain setup codes", emitted) +} From f4bff655a973b2d1896eece97c939b33e679abaf Mon Sep 17 00:00:00 2001 From: Yao Date: Wed, 30 Sep 2026 09:10:43 +0800 Subject: [PATCH 07/14] docs: fold long operation descriptions at render time An operation description in the contract is usually one long paragraph. The page opened with all of it, which pushed the request and response sections below the fold, and the contract text cannot be shortened without diverging from upstream. The reference now keeps the opening sentences under the title and folds the rest into a collapsed block, regrouped into short paragraphs at sentence boundaries. The contract prose itself stays verbatim, so the projection and verify:copy are unchanged. --- apps/docs/app/global.css | 18 +++++++++ apps/docs/scripts/contracts.mjs | 42 ++++++++++++++++++++ apps/docs/scripts/contracts.test.mjs | 20 +++++++++- apps/docs/scripts/generate-api-reference.mjs | 4 +- 4 files changed, 81 insertions(+), 3 deletions(-) diff --git a/apps/docs/app/global.css b/apps/docs/app/global.css index cc12ffffa..cf3065e23 100644 --- a/apps/docs/app/global.css +++ b/apps/docs/app/global.css @@ -101,3 +101,21 @@ body { ::selection { background: color-mix(in srgb, var(--color-fd-primary) 22%, transparent); } + +/* A folded operation description: the contract's full prose stays on the page + without pushing the request and response sections below the fold. */ +.prose details.api-details { + margin: 1rem 0; + padding: 0.25rem 0.75rem; + border: 1px solid var(--color-fd-border); + border-radius: 0.5rem; + background: color-mix(in srgb, var(--color-fd-muted) 35%, transparent); +} + +.prose details.api-details > summary { + padding: 0.35rem 0; + color: var(--color-fd-muted-foreground); + font-size: 0.8125rem; + font-weight: 600; + cursor: pointer; +} diff --git a/apps/docs/scripts/contracts.mjs b/apps/docs/scripts/contracts.mjs index 789e05cdd..7fac681b3 100644 --- a/apps/docs/scripts/contracts.mjs +++ b/apps/docs/scripts/contracts.mjs @@ -38,6 +38,48 @@ export function splitDescription(text = '') { return { lead: trimmed.slice(0, end), details: trimmed.slice(end).trim() } } +// Contract prose is one long paragraph, so a page would open with a wall of +// text that pushes the request section below the fold. The site instead keeps +// the lead under the title and folds the rest into a collapsed block, regrouped +// into short paragraphs. The contract text itself stays verbatim. +export function detailsBlock(details = '') { + const text = details.trim() + if (!text) return '' + const body = mdxText(paragraphise(text)) + // A short remainder reads better in place than behind a summary. + if (text.length <= 400) return body + '\n\n' + return `
\nFull description\n\n${body}\n\n
\n\n` +} + +// Sentence boundaries are the ones splitDescription uses: a terminator followed +// by a new sentence starting with a capital, backtick or quote. Abbreviations +// and paths such as "e.g. the ID" or "/v1.x files" stay in one sentence. +function sentences(text) { + const boundary = /[.!?](?=\s+[A-Z`"(])/g + const found = [] + let start = 0 + for (let match; (match = boundary.exec(text));) { + found.push(text.slice(start, match.index + 1)) + start = match.index + 1 + } + found.push(text.slice(start)) + return found.map(sentence => sentence.trim()).filter(Boolean) +} + +// Prose a contract already laid out as list items, tables or hard-wrapped lines +// is kept exactly as written; only a single long paragraph is regrouped. +function paragraphise(text, per = 3) { + return text.split(/\n{2,}/).map(block => { + const trimmed = block.trim() + if (!trimmed) return '' + if (/[\n|]/.test(trimmed) || /^([-*+]|\d+\.)\s/.test(trimmed)) return trimmed + const parts = sentences(trimmed) + const grouped = [] + for (let i = 0; i < parts.length; i += per) grouped.push(parts.slice(i, i + per).join(' ')) + return grouped.join('\n\n') + }).filter(Boolean).join('\n\n') +} + // Markdown from a contract, made safe for MDX: braces and angle brackets stay // literal text outside code spans. // Page descriptions render as plain text, so the lead drops inline markdown. diff --git a/apps/docs/scripts/contracts.test.mjs b/apps/docs/scripts/contracts.test.mjs index cb050eba7..15eb2d83f 100644 --- a/apps/docs/scripts/contracts.test.mjs +++ b/apps/docs/scripts/contracts.test.mjs @@ -6,7 +6,7 @@ import path from 'node:path' import yaml from 'js-yaml' import { createOpenAPI } from 'fumadocs-openapi/server' import { schemaToString } from '../node_modules/fumadocs-openapi/dist/utils/schema-to-string.js' -import { appRoot, normalise, surfaces, splitDescription, mdxText, plainText, fullPath } from './contracts.mjs' +import { appRoot, normalise, surfaces, splitDescription, detailsBlock, mdxText, plainText, fullPath } from './contracts.mjs' test('overview paths carry the namespace a caller sends', () => { const [publicApi, coreApi] = surfaces @@ -25,6 +25,24 @@ test('operation descriptions split into a lead and details', () => { assert.deepEqual(splitDescription(undefined), { lead: '', details: '' }) }) +test('a long description folds into paragraphs that keep every sentence', () => { + const text = Array.from({ length: 12 }, (_, i) => `Fact number ${i + 1} is stated in this description.`).join(' ') + assert.ok(text.length > 400, 'the fixture must be long enough to fold') + const block = detailsBlock(text) + assert.match(block, /^
\nFull description<\/summary>\n\n/) + assert.match(block, /\n\n<\/details>\n\n$/) + const inner = block.replace(/^\n[^\n]*<\/summary>\n\n/, '').replace(/\n\n<\/details>\n\n$/, '') + const paragraphs = inner.split('\n\n') + assert.ok(paragraphs.length > 1, 'a folded description is regrouped into paragraphs') + assert.equal(paragraphs.join(' ').replace(/\s+/g, ' '), text.replace(/\s+/g, ' ')) +}) + +test('short details and authored structure stay in place', () => { + assert.equal(detailsBlock('Keys are never returned.'), 'Keys are never returned.\n\n') + assert.equal(detailsBlock('Saves an Agent.\n\n- Limit one.\n- Limit two.'), 'Saves an Agent.\n\n- Limit one.\n- Limit two.\n\n') + assert.equal(detailsBlock(''), '') +}) + test('a lead loses inline markdown because page descriptions are plain text', () => { assert.equal(plainText('With `stream=true`, see **[Request conventions](/request-conventions)**.'), 'With stream=true, see Request conventions.') }) diff --git a/apps/docs/scripts/generate-api-reference.mjs b/apps/docs/scripts/generate-api-reference.mjs index fb3191619..bad7f396c 100644 --- a/apps/docs/scripts/generate-api-reference.mjs +++ b/apps/docs/scripts/generate-api-reference.mjs @@ -12,7 +12,7 @@ import yaml from 'js-yaml' import fs from 'node:fs' import path from 'node:path' import crypto from 'node:crypto' -import { appRoot, repoRoot, surfaces, sourcePath, normalise, methods, splitDescription, mdxText, plainText, fullPath } from './contracts.mjs' +import { appRoot, repoRoot, surfaces, sourcePath, normalise, methods, splitDescription, detailsBlock, plainText, fullPath } from './contracts.mjs' const root = path.join(appRoot, 'content/docs/api-reference') fs.rmSync(root, { recursive: true, force: true }) fs.mkdirSync(root, { recursive: true }) @@ -41,7 +41,7 @@ function withSplitDescription(content) { const body = content.slice(match[0].length) const at = body.indexOf(' Date: Wed, 30 Sep 2026 09:10:50 +0800 Subject: [PATCH 08/14] docs: regenerate the documentation site Rebuild the API reference and guide pages from the current contracts after rebasing onto upstream main, including the folded operation descriptions and the per-operation pages. --- .../content/docs/api-reference/agents.mdx | 75 --- .../agents/create-a-reusable-agent.mdx | 53 ++ .../agents/delete-a-reusable-agent.mdx | 23 + .../docs/api-reference/agents/index.mdx | 14 + .../agents/list-reusable-agents.mdx | 23 + .../docs/api-reference/agents/meta.json | 10 + .../agents/retrieve-a-reusable-agent.mdx | 19 + .../agents/update-a-reusable-agent.mdx | 33 ++ .../content/docs/api-reference/artifacts.mdx | 33 -- .../artifacts/delete-a-published-artifact.mdx | 21 + .../download-immutable-artifact-bytes.mdx | 23 + .../docs/api-reference/artifacts/index.mdx | 13 + .../list-immutable-session-artifacts.mdx | 32 ++ .../docs/api-reference/artifacts/meta.json | 9 + .../retrieve-immutable-artifact-metadata.mdx | 16 + .../core/administrator-projects.mdx | 17 - ...ke-all-its-keys-while-retaining-assets.mdx | 16 + .../create-an-empty-independent-project.mdx | 16 + .../core/administrator-projects/index.mdx | 16 + ...ependent-secret-in-an-existing-project.mdx | 16 + .../list-projects-and-active-key-counts.mdx | 16 + .../list-safe-key-metadata-for-a-project.mdx | 16 + .../core/administrator-projects/meta.json | 12 + .../rename-a-project.mdx | 16 + ...ject-key-while-retaining-shared-assets.mdx | 16 + .../docs/api-reference/core/agents.mdx | 29 -- .../delete-a-reusable-agent-in-a-project.mdx | 21 + .../docs/api-reference/core/agents/index.mdx | 12 + .../list-reusable-agents-in-a-project.mdx | 21 + .../docs/api-reference/core/agents/meta.json | 8 + ...retrieve-a-reusable-agent-in-a-project.mdx | 21 + .../docs/api-reference/core/artifacts.mdx | 33 -- ...lete-a-published-artifact-in-a-project.mdx | 21 + ...-immutable-artifact-bytes-in-a-project.mdx | 21 + .../api-reference/core/artifacts/index.mdx | 13 + ...mutable-session-artifacts-in-a-project.mdx | 21 + .../api-reference/core/artifacts/meta.json | 9 + ...mutable-artifact-metadata-in-a-project.mdx | 21 + .../core/core-administration.mdx | 56 -- .../core/core-administration/index.mdx | 16 + ...e-observations-across-managed-projects.mdx | 23 + .../core/core-administration/meta.json | 12 + ...uery-committed-administrator-mutations.mdx | 22 + ...tion-resources-while-retaining-history.mdx | 26 + ...naged-session-s-resource-cleanup-state.mdx | 22 + .../retrieve-core-operational-metrics.mdx | 21 + ...nstallation-facts-and-process-settings.mdx | 24 + ...-usage-by-project-agent-or-creator-key.mdx | 25 + .../docs/api-reference/core/credentials.mdx | 29 -- ...delete-a-vault-credential-in-a-project.mdx | 21 + .../api-reference/core/credentials/index.mdx | 12 + ...vault-credential-metadata-in-a-project.mdx | 21 + .../api-reference/core/credentials/meta.json | 8 + ...vault-credential-metadata-in-a-project.mdx | 21 + .../core/deployment-model-providers.mdx | 43 -- .../core/deployment-model-providers/index.mdx | 13 + ...eir-deployment-default-model-providers.mdx | 26 + .../core/deployment-model-providers/meta.json | 9 + ...ss-s-deployment-default-model-provider.mdx | 22 + ...ss-s-deployment-default-model-provider.mdx | 26 + ...ss-s-deployment-default-model-provider.mdx | 26 + .../core/environment-templates.mdx | 29 -- ...e-an-environment-template-in-a-project.mdx | 21 + .../core/environment-templates/index.mdx | 12 + ...ist-environment-templates-in-a-project.mdx | 21 + .../core/environment-templates/meta.json | 8 + ...e-an-environment-template-in-a-project.mdx | 21 + .../core/execution-configuration.mdx | 27 - .../core/execution-configuration/index.mdx | 10 + .../core/execution-configuration/meta.json | 6 + ...n-execution-configuration-in-a-project.mdx | 27 + .../core/executor-credentials.mdx | 42 -- .../core/executor-credentials/index.mdx | 12 + ...hosted-environment-executor-credential.mdx | 37 ++ ...ted-environment-s-executor-credentials.mdx | 26 + .../core/executor-credentials/meta.json | 8 + ...hosted-environment-executor-credential.mdx | 25 + .../content/docs/api-reference/core/files.mdx | 29 -- .../delete-a-source-file-in-a-project.mdx | 21 + .../docs/api-reference/core/files/index.mdx | 12 + .../files/list-source-files-in-a-project.mdx | 21 + .../docs/api-reference/core/files/meta.json | 8 + ...ieve-source-file-metadata-in-a-project.mdx | 21 + .../content/docs/api-reference/core/index.mdx | 42 +- .../docs/api-reference/core/items/index.mdx | 10 + ...ersisted-execution-items-in-a-project.mdx} | 16 +- .../docs/api-reference/core/items/meta.json | 6 + .../content/docs/api-reference/core/meta.json | 1 - ...osted-session-s-installation-commands.mdx} | 17 +- .../core/native-installation/index.mdx | 10 + .../core/native-installation/meta.json | 6 + .../api-reference/core/runtime-history.mdx | 26 - .../core/runtime-history/index.mdx | 10 + .../core/runtime-history/meta.json | 6 + ...e-session-runtime-history-in-a-project.mdx | 26 + .../core/runtime-observations/index.mdx | 10 + .../core/runtime-observations/meta.json | 6 + ...sion-runtime-observation-in-a-project.mdx} | 17 +- .../api-reference/core/sandbox-manager.mdx | 79 --- .../cancel-a-sandbox-deployment-reset.mdx | 21 + ...e-the-sandbox-deployment-configuration.mdx | 33 ++ ...n-minute-one-use-node-enrollment-token.mdx | 21 + .../core/sandbox-manager/index.mdx | 22 + ...ialize-the-deployment-sandbox-provider.mdx | 37 ++ .../list-deployment-sandbox-nodes.mdx | 21 + .../list-ready-builds-for-an-e2b-template.mdx | 21 + ...retained-allocations-on-a-sandbox-node.mdx | 21 + ...templates-visible-to-an-e2b-credential.mdx | 23 + .../core/sandbox-manager/meta.json | 18 + ...andbox-node-with-no-retained-resources.mdx | 21 + .../retrieve-sandbox-deployment.mdx | 22 + ...retrieve-sandbox-node-and-host-history.mdx | 21 + ...ate-a-durable-sandbox-deployment-reset.mdx | 27 + .../update-sandbox-node-name-and-capacity.mdx | 21 + .../docs/api-reference/core/sessions.mdx | 32 -- ...lete-an-execution-session-in-a-project.mdx | 21 + .../api-reference/core/sessions/index.mdx | 13 + .../list-execution-sessions-in-a-project.mdx | 21 + .../api-reference/core/sessions/meta.json | 9 + ...ieve-an-execution-session-in-a-project.mdx | 21 + .../retrieve-root-session-diagnostics.mdx | 21 + .../docs/api-reference/core/skills.mdx | 49 -- ...-a-skill-and-its-versions-in-a-project.mdx | 21 + .../delete-a-skill-version-in-a-project.mdx | 21 + ...ble-skill-version-content-in-a-project.mdx | 21 + .../download-skill-content-in-a-project.mdx | 21 + .../docs/api-reference/core/skills/index.mdx | 17 + .../list-skill-versions-in-a-project.mdx | 21 + .../core/skills/list-skills-in-a-project.mdx | 21 + .../docs/api-reference/core/skills/meta.json | 13 + .../retrieve-skill-metadata-in-a-project.mdx | 21 + ...ve-skill-version-metadata-in-a-project.mdx | 21 + .../content/docs/api-reference/core/turns.mdx | 28 - .../docs/api-reference/core/turns/index.mdx | 12 + .../list-execution-turns-in-a-project.mdx | 21 + .../docs/api-reference/core/turns/meta.json | 8 + ...etrieve-an-execution-turn-in-a-project.mdx | 21 + .../turns/retrieve-root-turn-diagnostics.mdx | 21 + .../docs/api-reference/core/vaults.mdx | 29 -- ...t-and-all-its-credentials-in-a-project.mdx | 21 + .../docs/api-reference/core/vaults/index.mdx | 12 + .../core/vaults/list-vaults-in-a-project.mdx | 21 + .../docs/api-reference/core/vaults/meta.json | 8 + .../vaults/retrieve-a-vault-in-a-project.mdx | 21 + .../docs/api-reference/core/write-audit.mdx | 26 - .../batch-lookup-resource-creation-keys.mdx | 22 + .../api-reference/core/write-audit/index.mdx | 11 + .../api-reference/core/write-audit/meta.json | 7 + .../query-api-key-write-operations.mdx | 22 + .../docs/api-reference/credentials.mdx | 74 --- .../credentials/create-a-vault-credential.mdx | 40 ++ .../credentials/delete-a-vault-credential.mdx | 36 ++ .../docs/api-reference/credentials/index.mdx | 14 + .../list-safe-vault-credential-metadata.mdx | 35 ++ .../docs/api-reference/credentials/meta.json | 10 + ...ault-credential-authentication-secrets.mdx | 42 ++ ...etrieve-safe-vault-credential-metadata.mdx | 23 + .../api-reference/environment-templates.mdx | 58 --- .../create-an-environment-template.mdx | 38 ++ .../delete-an-environment-template.mdx | 21 + .../environment-templates/index.mdx | 14 + .../list-environment-templates.mdx | 23 + .../environment-templates/meta.json | 10 + .../retrieve-an-environment-template.mdx | 21 + .../update-an-environment-template.mdx | 40 ++ .../docs/api-reference/environments.mdx | 63 --- ...ile-from-inline-bytes-or-a-source-file.mdx | 41 ++ .../docs/api-reference/environments/index.mdx | 12 + .../list-live-environment-files.mdx | 47 ++ .../docs/api-reference/environments/meta.json | 8 + .../retrieve-an-execution-environment.mdx | 36 ++ .../content/docs/api-reference/events.mdx | 37 -- .../docs/api-reference/events/index.mdx | 10 + .../docs/api-reference/events/meta.json | 6 + .../events/stream-live-session-events.mdx | 41 ++ .../docs/content/docs/api-reference/files.mdx | 48 -- .../files/delete-a-source-file.mdx | 25 + .../files/download-source-file-bytes.mdx | 22 + .../docs/api-reference/files/index.mdx | 14 + .../api-reference/files/list-source-files.mdx | 28 + .../docs/api-reference/files/meta.json | 10 + .../files/retrieve-source-file-metadata.mdx | 22 + .../files/upload-a-source-file.mdx | 29 ++ .../docs/content/docs/api-reference/index.mdx | 28 +- .../docs/content/docs/api-reference/items.mdx | 26 - .../docs/api-reference/items/index.mdx | 10 + .../items/list-persisted-execution-items.mdx | 23 + .../docs/api-reference/items/meta.json | 6 + .../docs/api-reference/machine/index.mdx | 8 +- .../docs/api-reference/machine/meta.json | 1 - .../machine/native-installation.mdx | 26 - ...-environment-s-installation-credential.mdx | 22 + .../machine/native-installation/index.mdx | 11 + .../machine/native-installation/meta.json | 7 + ...ve-a-native-installation-authorization.mdx | 21 + .../api-reference/machine/sandbox-node.mdx | 31 -- .../sandbox-node/enroll-a-sandbox-node.mdx | 25 + .../machine/sandbox-node/index.mdx | 12 + .../machine/sandbox-node/meta.json | 8 + ...ve-configuration-for-node-installation.mdx | 24 + ...ode-identity-and-observe-its-readiness.mdx | 23 + .../docs/content/docs/api-reference/meta.json | 1 - .../content/docs/api-reference/sessions.mdx | 246 --------- .../sessions/create-an-execution-session.mdx | 185 +++++++ .../sessions/delete-an-execution-session.mdx | 34 ++ .../docs/api-reference/sessions/index.mdx | 15 + .../sessions/list-execution-sessions.mdx | 26 + .../docs/api-reference/sessions/meta.json | 11 + .../retrieve-an-execution-session.mdx | 23 + .../sessions/submit-session-input-events.mdx | 76 +++ .../update-execution-session-metadata.mdx | 33 ++ .../content/docs/api-reference/skills.mdx | 51 -- .../delete-a-skill-and-its-versions.mdx | 21 + .../skills/delete-a-skill-version.mdx | 24 + ...wnload-immutable-skill-version-content.mdx | 16 + .../skills/download-skill-content.mdx | 22 + .../docs/api-reference/skills/index.mdx | 20 + .../skills/list-skill-versions.mdx | 24 + .../docs/api-reference/skills/list-skills.mdx | 22 + .../docs/api-reference/skills/meta.json | 16 + .../skills/retrieve-skill-metadata.mdx | 21 + .../retrieve-skill-version-metadata.mdx | 16 + .../update-the-default-skill-version.mdx | 21 + .../api-reference/skills/upload-a-skill.mdx | 22 + .../upload-an-immutable-skill-version.mdx | 16 + .../content/docs/api-reference/subagents.mdx | 49 -- .../docs/api-reference/subagents/index.mdx | 15 + .../subagents/list-a-subagent-s-items.mdx | 23 + .../subagents/list-a-subagent-s-turns.mdx | 26 + .../list-a-subagent-turn-s-items.mdx | 22 + .../subagents/list-session-subagents.mdx | 23 + .../docs/api-reference/subagents/meta.json | 11 + .../subagents/retrieve-a-session-subagent.mdx | 22 + .../subagents/retrieve-a-subagent-turn.mdx | 24 + .../docs/content/docs/api-reference/turns.mdx | 28 - .../docs/api-reference/turns/index.mdx | 11 + .../turns/list-execution-turns.mdx | 25 + .../docs/api-reference/turns/meta.json | 7 + .../turns/retrieve-an-execution-turn.mdx | 21 + .../content/docs/api-reference/vaults.mdx | 50 -- .../api-reference/vaults/create-a-vault.mdx | 32 ++ ...delete-a-vault-and-all-its-credentials.mdx | 35 ++ .../docs/api-reference/vaults/index.mdx | 13 + .../docs/api-reference/vaults/list-vaults.mdx | 32 ++ .../docs/api-reference/vaults/meta.json | 9 + .../api-reference/vaults/retrieve-a-vault.mdx | 24 + apps/docs/content/docs/error-codes.mdx | 296 +++++++++++ apps/docs/content/docs/public-api.mdx | 22 +- .../docs/content/docs/request-conventions.mdx | 72 +++ apps/docs/content/guide-sources.json | 26 +- apps/docs/openapi/core-api.yaml | 328 +++++++++++- apps/docs/openapi/public-api.yaml | 492 ++++++++++++++++++ apps/docs/openapi/runtime-api.yaml | 24 + apps/docs/openapi/sources.json | 267 ++++++++-- contracts/agents-api/core.openapi.yaml | 222 +++++++- contracts/agents-api/openapi.yaml | 328 ++++++++++++ contracts/agents-api/runtime.openapi.yaml | 16 + 257 files changed, 6338 insertions(+), 1636 deletions(-) delete mode 100644 apps/docs/content/docs/api-reference/agents.mdx create mode 100644 apps/docs/content/docs/api-reference/agents/create-a-reusable-agent.mdx create mode 100644 apps/docs/content/docs/api-reference/agents/delete-a-reusable-agent.mdx create mode 100644 apps/docs/content/docs/api-reference/agents/index.mdx create mode 100644 apps/docs/content/docs/api-reference/agents/list-reusable-agents.mdx create mode 100644 apps/docs/content/docs/api-reference/agents/meta.json create mode 100644 apps/docs/content/docs/api-reference/agents/retrieve-a-reusable-agent.mdx create mode 100644 apps/docs/content/docs/api-reference/agents/update-a-reusable-agent.mdx delete mode 100644 apps/docs/content/docs/api-reference/artifacts.mdx create mode 100644 apps/docs/content/docs/api-reference/artifacts/delete-a-published-artifact.mdx create mode 100644 apps/docs/content/docs/api-reference/artifacts/download-immutable-artifact-bytes.mdx create mode 100644 apps/docs/content/docs/api-reference/artifacts/index.mdx create mode 100644 apps/docs/content/docs/api-reference/artifacts/list-immutable-session-artifacts.mdx create mode 100644 apps/docs/content/docs/api-reference/artifacts/meta.json create mode 100644 apps/docs/content/docs/api-reference/artifacts/retrieve-immutable-artifact-metadata.mdx delete mode 100644 apps/docs/content/docs/api-reference/core/administrator-projects.mdx create mode 100644 apps/docs/content/docs/api-reference/core/administrator-projects/archive-a-project-and-revoke-all-its-keys-while-retaining-assets.mdx create mode 100644 apps/docs/content/docs/api-reference/core/administrator-projects/create-an-empty-independent-project.mdx create mode 100644 apps/docs/content/docs/api-reference/core/administrator-projects/index.mdx create mode 100644 apps/docs/content/docs/api-reference/core/administrator-projects/issue-an-independent-secret-in-an-existing-project.mdx create mode 100644 apps/docs/content/docs/api-reference/core/administrator-projects/list-projects-and-active-key-counts.mdx create mode 100644 apps/docs/content/docs/api-reference/core/administrator-projects/list-safe-key-metadata-for-a-project.mdx create mode 100644 apps/docs/content/docs/api-reference/core/administrator-projects/meta.json create mode 100644 apps/docs/content/docs/api-reference/core/administrator-projects/rename-a-project.mdx create mode 100644 apps/docs/content/docs/api-reference/core/administrator-projects/revoke-one-project-key-while-retaining-shared-assets.mdx delete mode 100644 apps/docs/content/docs/api-reference/core/agents.mdx create mode 100644 apps/docs/content/docs/api-reference/core/agents/delete-a-reusable-agent-in-a-project.mdx create mode 100644 apps/docs/content/docs/api-reference/core/agents/index.mdx create mode 100644 apps/docs/content/docs/api-reference/core/agents/list-reusable-agents-in-a-project.mdx create mode 100644 apps/docs/content/docs/api-reference/core/agents/meta.json create mode 100644 apps/docs/content/docs/api-reference/core/agents/retrieve-a-reusable-agent-in-a-project.mdx delete mode 100644 apps/docs/content/docs/api-reference/core/artifacts.mdx create mode 100644 apps/docs/content/docs/api-reference/core/artifacts/delete-a-published-artifact-in-a-project.mdx create mode 100644 apps/docs/content/docs/api-reference/core/artifacts/download-immutable-artifact-bytes-in-a-project.mdx create mode 100644 apps/docs/content/docs/api-reference/core/artifacts/index.mdx create mode 100644 apps/docs/content/docs/api-reference/core/artifacts/list-immutable-session-artifacts-in-a-project.mdx create mode 100644 apps/docs/content/docs/api-reference/core/artifacts/meta.json create mode 100644 apps/docs/content/docs/api-reference/core/artifacts/retrieve-immutable-artifact-metadata-in-a-project.mdx delete mode 100644 apps/docs/content/docs/api-reference/core/core-administration.mdx create mode 100644 apps/docs/content/docs/api-reference/core/core-administration/index.mdx create mode 100644 apps/docs/content/docs/api-reference/core/core-administration/list-runtime-observations-across-managed-projects.mdx create mode 100644 apps/docs/content/docs/api-reference/core/core-administration/meta.json create mode 100644 apps/docs/content/docs/api-reference/core/core-administration/query-committed-administrator-mutations.mdx create mode 100644 apps/docs/content/docs/api-reference/core/core-administration/release-a-managed-session-s-execution-resources-while-retaining-history.mdx create mode 100644 apps/docs/content/docs/api-reference/core/core-administration/retrieve-a-managed-session-s-resource-cleanup-state.mdx create mode 100644 apps/docs/content/docs/api-reference/core/core-administration/retrieve-core-operational-metrics.mdx create mode 100644 apps/docs/content/docs/api-reference/core/core-administration/retrieve-installation-facts-and-process-settings.mdx create mode 100644 apps/docs/content/docs/api-reference/core/core-administration/summarize-resource-counts-and-session-usage-by-project-agent-or-creator-key.mdx delete mode 100644 apps/docs/content/docs/api-reference/core/credentials.mdx create mode 100644 apps/docs/content/docs/api-reference/core/credentials/delete-a-vault-credential-in-a-project.mdx create mode 100644 apps/docs/content/docs/api-reference/core/credentials/index.mdx create mode 100644 apps/docs/content/docs/api-reference/core/credentials/list-safe-vault-credential-metadata-in-a-project.mdx create mode 100644 apps/docs/content/docs/api-reference/core/credentials/meta.json create mode 100644 apps/docs/content/docs/api-reference/core/credentials/retrieve-safe-vault-credential-metadata-in-a-project.mdx delete mode 100644 apps/docs/content/docs/api-reference/core/deployment-model-providers.mdx create mode 100644 apps/docs/content/docs/api-reference/core/deployment-model-providers/index.mdx create mode 100644 apps/docs/content/docs/api-reference/core/deployment-model-providers/list-harnesses-and-their-deployment-default-model-providers.mdx create mode 100644 apps/docs/content/docs/api-reference/core/deployment-model-providers/meta.json create mode 100644 apps/docs/content/docs/api-reference/core/deployment-model-providers/remove-a-harness-s-deployment-default-model-provider.mdx create mode 100644 apps/docs/content/docs/api-reference/core/deployment-model-providers/replace-a-harness-s-deployment-default-model-provider.mdx create mode 100644 apps/docs/content/docs/api-reference/core/deployment-model-providers/retrieve-a-harness-s-deployment-default-model-provider.mdx delete mode 100644 apps/docs/content/docs/api-reference/core/environment-templates.mdx create mode 100644 apps/docs/content/docs/api-reference/core/environment-templates/delete-an-environment-template-in-a-project.mdx create mode 100644 apps/docs/content/docs/api-reference/core/environment-templates/index.mdx create mode 100644 apps/docs/content/docs/api-reference/core/environment-templates/list-environment-templates-in-a-project.mdx create mode 100644 apps/docs/content/docs/api-reference/core/environment-templates/meta.json create mode 100644 apps/docs/content/docs/api-reference/core/environment-templates/retrieve-an-environment-template-in-a-project.mdx delete mode 100644 apps/docs/content/docs/api-reference/core/execution-configuration.mdx create mode 100644 apps/docs/content/docs/api-reference/core/execution-configuration/index.mdx create mode 100644 apps/docs/content/docs/api-reference/core/execution-configuration/meta.json create mode 100644 apps/docs/content/docs/api-reference/core/execution-configuration/retrieve-a-session-s-frozen-execution-configuration-in-a-project.mdx delete mode 100644 apps/docs/content/docs/api-reference/core/executor-credentials.mdx create mode 100644 apps/docs/content/docs/api-reference/core/executor-credentials/index.mdx create mode 100644 apps/docs/content/docs/api-reference/core/executor-credentials/issue-or-explicitly-rotate-a-self-hosted-environment-executor-credential.mdx create mode 100644 apps/docs/content/docs/api-reference/core/executor-credentials/list-a-self-hosted-environment-s-executor-credentials.mdx create mode 100644 apps/docs/content/docs/api-reference/core/executor-credentials/meta.json create mode 100644 apps/docs/content/docs/api-reference/core/executor-credentials/revoke-a-self-hosted-environment-executor-credential.mdx delete mode 100644 apps/docs/content/docs/api-reference/core/files.mdx create mode 100644 apps/docs/content/docs/api-reference/core/files/delete-a-source-file-in-a-project.mdx create mode 100644 apps/docs/content/docs/api-reference/core/files/index.mdx create mode 100644 apps/docs/content/docs/api-reference/core/files/list-source-files-in-a-project.mdx create mode 100644 apps/docs/content/docs/api-reference/core/files/meta.json create mode 100644 apps/docs/content/docs/api-reference/core/files/retrieve-source-file-metadata-in-a-project.mdx create mode 100644 apps/docs/content/docs/api-reference/core/items/index.mdx rename apps/docs/content/docs/api-reference/core/{items.mdx => items/list-persisted-execution-items-in-a-project.mdx} (60%) create mode 100644 apps/docs/content/docs/api-reference/core/items/meta.json rename apps/docs/content/docs/api-reference/core/{native-installation.mdx => native-installation/get-a-self-hosted-session-s-installation-commands.mdx} (54%) create mode 100644 apps/docs/content/docs/api-reference/core/native-installation/index.mdx create mode 100644 apps/docs/content/docs/api-reference/core/native-installation/meta.json delete mode 100644 apps/docs/content/docs/api-reference/core/runtime-history.mdx create mode 100644 apps/docs/content/docs/api-reference/core/runtime-history/index.mdx create mode 100644 apps/docs/content/docs/api-reference/core/runtime-history/meta.json create mode 100644 apps/docs/content/docs/api-reference/core/runtime-history/retrieve-session-runtime-history-in-a-project.mdx create mode 100644 apps/docs/content/docs/api-reference/core/runtime-observations/index.mdx create mode 100644 apps/docs/content/docs/api-reference/core/runtime-observations/meta.json rename apps/docs/content/docs/api-reference/core/{runtime-observations.mdx => runtime-observations/retrieve-a-session-runtime-observation-in-a-project.mdx} (52%) delete mode 100644 apps/docs/content/docs/api-reference/core/sandbox-manager.mdx create mode 100644 apps/docs/content/docs/api-reference/core/sandbox-manager/cancel-a-sandbox-deployment-reset.mdx create mode 100644 apps/docs/content/docs/api-reference/core/sandbox-manager/change-the-sandbox-deployment-configuration.mdx create mode 100644 apps/docs/content/docs/api-reference/core/sandbox-manager/create-a-ten-minute-one-use-node-enrollment-token.mdx create mode 100644 apps/docs/content/docs/api-reference/core/sandbox-manager/index.mdx create mode 100644 apps/docs/content/docs/api-reference/core/sandbox-manager/initialize-the-deployment-sandbox-provider.mdx create mode 100644 apps/docs/content/docs/api-reference/core/sandbox-manager/list-deployment-sandbox-nodes.mdx create mode 100644 apps/docs/content/docs/api-reference/core/sandbox-manager/list-ready-builds-for-an-e2b-template.mdx create mode 100644 apps/docs/content/docs/api-reference/core/sandbox-manager/list-retained-allocations-on-a-sandbox-node.mdx create mode 100644 apps/docs/content/docs/api-reference/core/sandbox-manager/list-templates-visible-to-an-e2b-credential.mdx create mode 100644 apps/docs/content/docs/api-reference/core/sandbox-manager/meta.json create mode 100644 apps/docs/content/docs/api-reference/core/sandbox-manager/remove-a-sandbox-node-with-no-retained-resources.mdx create mode 100644 apps/docs/content/docs/api-reference/core/sandbox-manager/retrieve-sandbox-deployment.mdx create mode 100644 apps/docs/content/docs/api-reference/core/sandbox-manager/retrieve-sandbox-node-and-host-history.mdx create mode 100644 apps/docs/content/docs/api-reference/core/sandbox-manager/start-or-escalate-a-durable-sandbox-deployment-reset.mdx create mode 100644 apps/docs/content/docs/api-reference/core/sandbox-manager/update-sandbox-node-name-and-capacity.mdx delete mode 100644 apps/docs/content/docs/api-reference/core/sessions.mdx create mode 100644 apps/docs/content/docs/api-reference/core/sessions/delete-an-execution-session-in-a-project.mdx create mode 100644 apps/docs/content/docs/api-reference/core/sessions/index.mdx create mode 100644 apps/docs/content/docs/api-reference/core/sessions/list-execution-sessions-in-a-project.mdx create mode 100644 apps/docs/content/docs/api-reference/core/sessions/meta.json create mode 100644 apps/docs/content/docs/api-reference/core/sessions/retrieve-an-execution-session-in-a-project.mdx create mode 100644 apps/docs/content/docs/api-reference/core/sessions/retrieve-root-session-diagnostics.mdx delete mode 100644 apps/docs/content/docs/api-reference/core/skills.mdx create mode 100644 apps/docs/content/docs/api-reference/core/skills/delete-a-skill-and-its-versions-in-a-project.mdx create mode 100644 apps/docs/content/docs/api-reference/core/skills/delete-a-skill-version-in-a-project.mdx create mode 100644 apps/docs/content/docs/api-reference/core/skills/download-immutable-skill-version-content-in-a-project.mdx create mode 100644 apps/docs/content/docs/api-reference/core/skills/download-skill-content-in-a-project.mdx create mode 100644 apps/docs/content/docs/api-reference/core/skills/index.mdx create mode 100644 apps/docs/content/docs/api-reference/core/skills/list-skill-versions-in-a-project.mdx create mode 100644 apps/docs/content/docs/api-reference/core/skills/list-skills-in-a-project.mdx create mode 100644 apps/docs/content/docs/api-reference/core/skills/meta.json create mode 100644 apps/docs/content/docs/api-reference/core/skills/retrieve-skill-metadata-in-a-project.mdx create mode 100644 apps/docs/content/docs/api-reference/core/skills/retrieve-skill-version-metadata-in-a-project.mdx delete mode 100644 apps/docs/content/docs/api-reference/core/turns.mdx create mode 100644 apps/docs/content/docs/api-reference/core/turns/index.mdx create mode 100644 apps/docs/content/docs/api-reference/core/turns/list-execution-turns-in-a-project.mdx create mode 100644 apps/docs/content/docs/api-reference/core/turns/meta.json create mode 100644 apps/docs/content/docs/api-reference/core/turns/retrieve-an-execution-turn-in-a-project.mdx create mode 100644 apps/docs/content/docs/api-reference/core/turns/retrieve-root-turn-diagnostics.mdx delete mode 100644 apps/docs/content/docs/api-reference/core/vaults.mdx create mode 100644 apps/docs/content/docs/api-reference/core/vaults/delete-a-vault-and-all-its-credentials-in-a-project.mdx create mode 100644 apps/docs/content/docs/api-reference/core/vaults/index.mdx create mode 100644 apps/docs/content/docs/api-reference/core/vaults/list-vaults-in-a-project.mdx create mode 100644 apps/docs/content/docs/api-reference/core/vaults/meta.json create mode 100644 apps/docs/content/docs/api-reference/core/vaults/retrieve-a-vault-in-a-project.mdx delete mode 100644 apps/docs/content/docs/api-reference/core/write-audit.mdx create mode 100644 apps/docs/content/docs/api-reference/core/write-audit/batch-lookup-resource-creation-keys.mdx create mode 100644 apps/docs/content/docs/api-reference/core/write-audit/index.mdx create mode 100644 apps/docs/content/docs/api-reference/core/write-audit/meta.json create mode 100644 apps/docs/content/docs/api-reference/core/write-audit/query-api-key-write-operations.mdx delete mode 100644 apps/docs/content/docs/api-reference/credentials.mdx create mode 100644 apps/docs/content/docs/api-reference/credentials/create-a-vault-credential.mdx create mode 100644 apps/docs/content/docs/api-reference/credentials/delete-a-vault-credential.mdx create mode 100644 apps/docs/content/docs/api-reference/credentials/index.mdx create mode 100644 apps/docs/content/docs/api-reference/credentials/list-safe-vault-credential-metadata.mdx create mode 100644 apps/docs/content/docs/api-reference/credentials/meta.json create mode 100644 apps/docs/content/docs/api-reference/credentials/replace-vault-credential-authentication-secrets.mdx create mode 100644 apps/docs/content/docs/api-reference/credentials/retrieve-safe-vault-credential-metadata.mdx delete mode 100644 apps/docs/content/docs/api-reference/environment-templates.mdx create mode 100644 apps/docs/content/docs/api-reference/environment-templates/create-an-environment-template.mdx create mode 100644 apps/docs/content/docs/api-reference/environment-templates/delete-an-environment-template.mdx create mode 100644 apps/docs/content/docs/api-reference/environment-templates/index.mdx create mode 100644 apps/docs/content/docs/api-reference/environment-templates/list-environment-templates.mdx create mode 100644 apps/docs/content/docs/api-reference/environment-templates/meta.json create mode 100644 apps/docs/content/docs/api-reference/environment-templates/retrieve-an-environment-template.mdx create mode 100644 apps/docs/content/docs/api-reference/environment-templates/update-an-environment-template.mdx delete mode 100644 apps/docs/content/docs/api-reference/environments.mdx create mode 100644 apps/docs/content/docs/api-reference/environments/create-an-environment-file-from-inline-bytes-or-a-source-file.mdx create mode 100644 apps/docs/content/docs/api-reference/environments/index.mdx create mode 100644 apps/docs/content/docs/api-reference/environments/list-live-environment-files.mdx create mode 100644 apps/docs/content/docs/api-reference/environments/meta.json create mode 100644 apps/docs/content/docs/api-reference/environments/retrieve-an-execution-environment.mdx delete mode 100644 apps/docs/content/docs/api-reference/events.mdx create mode 100644 apps/docs/content/docs/api-reference/events/index.mdx create mode 100644 apps/docs/content/docs/api-reference/events/meta.json create mode 100644 apps/docs/content/docs/api-reference/events/stream-live-session-events.mdx delete mode 100644 apps/docs/content/docs/api-reference/files.mdx create mode 100644 apps/docs/content/docs/api-reference/files/delete-a-source-file.mdx create mode 100644 apps/docs/content/docs/api-reference/files/download-source-file-bytes.mdx create mode 100644 apps/docs/content/docs/api-reference/files/index.mdx create mode 100644 apps/docs/content/docs/api-reference/files/list-source-files.mdx create mode 100644 apps/docs/content/docs/api-reference/files/meta.json create mode 100644 apps/docs/content/docs/api-reference/files/retrieve-source-file-metadata.mdx create mode 100644 apps/docs/content/docs/api-reference/files/upload-a-source-file.mdx delete mode 100644 apps/docs/content/docs/api-reference/items.mdx create mode 100644 apps/docs/content/docs/api-reference/items/index.mdx create mode 100644 apps/docs/content/docs/api-reference/items/list-persisted-execution-items.mdx create mode 100644 apps/docs/content/docs/api-reference/items/meta.json delete mode 100644 apps/docs/content/docs/api-reference/machine/native-installation.mdx create mode 100644 apps/docs/content/docs/api-reference/machine/native-installation/claim-an-environment-s-installation-credential.mdx create mode 100644 apps/docs/content/docs/api-reference/machine/native-installation/index.mdx create mode 100644 apps/docs/content/docs/api-reference/machine/native-installation/meta.json create mode 100644 apps/docs/content/docs/api-reference/machine/native-installation/resolve-a-native-installation-authorization.mdx delete mode 100644 apps/docs/content/docs/api-reference/machine/sandbox-node.mdx create mode 100644 apps/docs/content/docs/api-reference/machine/sandbox-node/enroll-a-sandbox-node.mdx create mode 100644 apps/docs/content/docs/api-reference/machine/sandbox-node/index.mdx create mode 100644 apps/docs/content/docs/api-reference/machine/sandbox-node/meta.json create mode 100644 apps/docs/content/docs/api-reference/machine/sandbox-node/read-the-active-configuration-for-node-installation.mdx create mode 100644 apps/docs/content/docs/api-reference/machine/sandbox-node/recover-an-enrolled-sandbox-node-identity-and-observe-its-readiness.mdx delete mode 100644 apps/docs/content/docs/api-reference/sessions.mdx create mode 100644 apps/docs/content/docs/api-reference/sessions/create-an-execution-session.mdx create mode 100644 apps/docs/content/docs/api-reference/sessions/delete-an-execution-session.mdx create mode 100644 apps/docs/content/docs/api-reference/sessions/index.mdx create mode 100644 apps/docs/content/docs/api-reference/sessions/list-execution-sessions.mdx create mode 100644 apps/docs/content/docs/api-reference/sessions/meta.json create mode 100644 apps/docs/content/docs/api-reference/sessions/retrieve-an-execution-session.mdx create mode 100644 apps/docs/content/docs/api-reference/sessions/submit-session-input-events.mdx create mode 100644 apps/docs/content/docs/api-reference/sessions/update-execution-session-metadata.mdx delete mode 100644 apps/docs/content/docs/api-reference/skills.mdx create mode 100644 apps/docs/content/docs/api-reference/skills/delete-a-skill-and-its-versions.mdx create mode 100644 apps/docs/content/docs/api-reference/skills/delete-a-skill-version.mdx create mode 100644 apps/docs/content/docs/api-reference/skills/download-immutable-skill-version-content.mdx create mode 100644 apps/docs/content/docs/api-reference/skills/download-skill-content.mdx create mode 100644 apps/docs/content/docs/api-reference/skills/index.mdx create mode 100644 apps/docs/content/docs/api-reference/skills/list-skill-versions.mdx create mode 100644 apps/docs/content/docs/api-reference/skills/list-skills.mdx create mode 100644 apps/docs/content/docs/api-reference/skills/meta.json create mode 100644 apps/docs/content/docs/api-reference/skills/retrieve-skill-metadata.mdx create mode 100644 apps/docs/content/docs/api-reference/skills/retrieve-skill-version-metadata.mdx create mode 100644 apps/docs/content/docs/api-reference/skills/update-the-default-skill-version.mdx create mode 100644 apps/docs/content/docs/api-reference/skills/upload-a-skill.mdx create mode 100644 apps/docs/content/docs/api-reference/skills/upload-an-immutable-skill-version.mdx delete mode 100644 apps/docs/content/docs/api-reference/subagents.mdx create mode 100644 apps/docs/content/docs/api-reference/subagents/index.mdx create mode 100644 apps/docs/content/docs/api-reference/subagents/list-a-subagent-s-items.mdx create mode 100644 apps/docs/content/docs/api-reference/subagents/list-a-subagent-s-turns.mdx create mode 100644 apps/docs/content/docs/api-reference/subagents/list-a-subagent-turn-s-items.mdx create mode 100644 apps/docs/content/docs/api-reference/subagents/list-session-subagents.mdx create mode 100644 apps/docs/content/docs/api-reference/subagents/meta.json create mode 100644 apps/docs/content/docs/api-reference/subagents/retrieve-a-session-subagent.mdx create mode 100644 apps/docs/content/docs/api-reference/subagents/retrieve-a-subagent-turn.mdx delete mode 100644 apps/docs/content/docs/api-reference/turns.mdx create mode 100644 apps/docs/content/docs/api-reference/turns/index.mdx create mode 100644 apps/docs/content/docs/api-reference/turns/list-execution-turns.mdx create mode 100644 apps/docs/content/docs/api-reference/turns/meta.json create mode 100644 apps/docs/content/docs/api-reference/turns/retrieve-an-execution-turn.mdx delete mode 100644 apps/docs/content/docs/api-reference/vaults.mdx create mode 100644 apps/docs/content/docs/api-reference/vaults/create-a-vault.mdx create mode 100644 apps/docs/content/docs/api-reference/vaults/delete-a-vault-and-all-its-credentials.mdx create mode 100644 apps/docs/content/docs/api-reference/vaults/index.mdx create mode 100644 apps/docs/content/docs/api-reference/vaults/list-vaults.mdx create mode 100644 apps/docs/content/docs/api-reference/vaults/meta.json create mode 100644 apps/docs/content/docs/api-reference/vaults/retrieve-a-vault.mdx create mode 100644 apps/docs/content/docs/error-codes.mdx create mode 100644 apps/docs/content/docs/request-conventions.mdx diff --git a/apps/docs/content/docs/api-reference/agents.mdx b/apps/docs/content/docs/api-reference/agents.mdx deleted file mode 100644 index 25bd137d4..000000000 --- a/apps/docs/content/docs/api-reference/agents.mdx +++ /dev/null @@ -1,75 +0,0 @@ ---- -title: Agents -description: >- - Agents. Application API: Project API key. Public schema constrained by the - pinned OpenAI Agents API baseline; documented x_agents_core fields remain Core - extensions. -full: true -_openapi: - toc: [] - structuredData: - headings: [] - contents: - - content: >- - Lists only the authenticated tenant's saved Agents, independently of - Sessions. Limit 0 is treated as 1 and larger limits as 100, as - observed on the hosted service. The local default is 20; exact - upstream default/cap and empty cursor fields remain unverified. An - unknown, malformed or foreign after cursor returns not found. - - content: >- - Persists configuration independently of execution. Names over 128 - characters and metadata outside 16 string pairs with 64-character keys - and 512-character values return invalid_request_error with the - official param; U+0000 in stored strings is rejected as a local - storage limit. As on every Agents API JSON route, a non-JSON - Content-Type, invalid UTF-8, malformed JSON, a repeated key at any - depth or a non-object root returns invalid_request_error with a null - param and the official message before other checks; an empty or null - body is {}. Missing, unknown, wrongly typed or unsupported enum - members of the pinned configuration shapes (tools, text, reasoning, - service_tier, multi_agent) return invalid_request_error with the JSON - path as param; duplicate function names, repeated web_search or - tool_search and non-object schema root types return it with a null - param. Supports model/name/instructions/metadata, explicit reasoning - and service tiers, multi_agent, text/json_schema, - function/tool_search/programmatic_tool_calling/web_search and HTTP MCP - with nullable credential_id, service origin (omitted or null on HTTP - transport is saved as service) and boolean required defaulting to - false. Saving credential_id grants no access: Session admission checks - attached Vault ownership and destination. MCP allowed_tools preserves - null versus empty; saved HTTP transport includes empty headers. - Model-derived reasoning defaults, other MCP variants and public retry - conformance remain incomplete. web_search saves every pinned mode: - omitted or null mode is saved as live and omitted or null context_size - as medium; allowed_domains preserves null versus empty and a present - location, including {}, includes all four keys with null for omitted - ones, as observed officially (req_db41d2f6261b4abfb69465eafe719ab5, - req_165d53b88445490b9146d8272c54134d). Session execution accepts only - explicit disabled web_search and disabled programmatic_tool_calling - through qualified Runtime controls; saved enabled forms reject at - Session admission. Session execution admits only its supported - configuration subset. - - content: >- - Reads the saved resource owned by the authenticated tenant, - independently of execution Sessions. - - content: >- - Preserves omitted fields and replaces supplied fields using shared - saved-configuration validation. Null name/instructions clear; null or - empty metadata clears all pairs. Name, metadata and configuration - validation errors return invalid_request_error with the official - param, using the Agent create rules before the Agent lookup. Existing - Session snapshots are unchanged. Empty updates advance updated_at - without changing saved fields. Nested replacement/null defaults, - model-derived reasoning and exact hosted error behavior remain - incompletely verified. - - content: >- - Deletes only the authenticated tenant's saved configuration. Existing - Session snapshots, history and recorded creation retry identities - remain independent. Missing and repeated deletion locally return404; - exact hosted error and in-flight creation/deletion semantics remain - unverified. ---- - -{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} - - \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/agents/create-a-reusable-agent.mdx b/apps/docs/content/docs/api-reference/agents/create-a-reusable-agent.mdx new file mode 100644 index 000000000..e914e32b6 --- /dev/null +++ b/apps/docs/content/docs/api-reference/agents/create-a-reusable-agent.mdx @@ -0,0 +1,53 @@ +--- +title: Create a reusable Agent +description: Persists configuration independently of execution. +full: true +_openapi: + method: POST + route: /agents + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Persists configuration independently of execution. Names over 128 characters and metadata + outside 16 string pairs with 64-character keys and 512-character values return + invalid_request_error with the official param; U+0000 in stored strings is rejected as a + local storage limit. As on every Agents API JSON route, a non-JSON Content-Type, invalid + UTF-8, malformed JSON, a repeated key at any depth or a non-object root returns + invalid_request_error with a null param and the official message before other checks; an + empty or null body is {}. Missing, unknown, wrongly typed or unsupported enum members of + the pinned configuration shapes (tools, text, reasoning, service_tier, multi_agent) return + invalid_request_error with the JSON path as param; duplicate function names, repeated + web_search or tool_search and non-object schema root types return it with a null param. + Supports model/name/instructions/metadata, explicit reasoning and service tiers, + multi_agent, text/json_schema, function/tool_search/programmatic_tool_calling/web_search + and HTTP MCP with nullable credential_id, service origin (omitted or null on HTTP + transport is saved as service) and boolean required defaulting to false. Saving + credential_id grants no access: Session admission checks attached Vault ownership and + destination. MCP allowed_tools preserves null versus empty; saved HTTP transport includes + empty headers. Model-derived reasoning defaults, other MCP variants and public retry + conformance remain incomplete. web_search saves every pinned mode: omitted or null mode is + saved as live and omitted or null context_size as medium; allowed_domains preserves null + versus empty and a present location, including {}, includes all four keys with null for + omitted ones, as observed officially (req_db41d2f6261b4abfb69465eafe719ab5, + req_165d53b88445490b9146d8272c54134d). Session execution accepts only explicit disabled + web_search and disabled programmatic_tool_calling through qualified Runtime controls; + saved enabled forms reject at Session admission. Session execution admits only its + supported configuration subset. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +
+Full description + +Names over 128 characters and metadata outside 16 string pairs with 64-character keys and 512-character values return invalid_request_error with the official param; U+0000 in stored strings is rejected as a local storage limit. As on every Agents API JSON route, a non-JSON Content-Type, invalid UTF-8, malformed JSON, a repeated key at any depth or a non-object root returns invalid_request_error with a null param and the official message before other checks; an empty or null body is {}. Missing, unknown, wrongly typed or unsupported enum members of the pinned configuration shapes (tools, text, reasoning, service_tier, multi_agent) return invalid_request_error with the JSON path as param; duplicate function names, repeated web_search or tool_search and non-object schema root types return it with a null param. + +Supports model/name/instructions/metadata, explicit reasoning and service tiers, multi_agent, text/json_schema, function/tool_search/programmatic_tool_calling/web_search and HTTP MCP with nullable credential_id, service origin (omitted or null on HTTP transport is saved as service) and boolean required defaulting to false. Saving credential_id grants no access: Session admission checks attached Vault ownership and destination. MCP allowed_tools preserves null versus empty; saved HTTP transport includes empty headers. + +Model-derived reasoning defaults, other MCP variants and public retry conformance remain incomplete. web_search saves every pinned mode: omitted or null mode is saved as live and omitted or null context_size as medium; allowed_domains preserves null versus empty and a present location, including {}, includes all four keys with null for omitted ones, as observed officially (req_db41d2f6261b4abfb69465eafe719ab5, req_165d53b88445490b9146d8272c54134d). Session execution accepts only explicit disabled web_search and disabled programmatic_tool_calling through qualified Runtime controls; saved enabled forms reject at Session admission. Session execution admits only its supported configuration subset. + +
+ + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/agents/delete-a-reusable-agent.mdx b/apps/docs/content/docs/api-reference/agents/delete-a-reusable-agent.mdx new file mode 100644 index 000000000..8895235e5 --- /dev/null +++ b/apps/docs/content/docs/api-reference/agents/delete-a-reusable-agent.mdx @@ -0,0 +1,23 @@ +--- +title: Delete a reusable Agent +description: Deletes only the authenticated tenant's saved configuration. +full: true +_openapi: + method: DELETE + route: /agents/{agent_id} + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Deletes only the authenticated tenant's saved configuration. Existing Session snapshots, + history and recorded creation retry identities remain independent. Missing and repeated + deletion locally return404; exact hosted error and in-flight creation/deletion semantics + remain unverified. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Existing Session snapshots, history and recorded creation retry identities remain independent. Missing and repeated deletion locally return404; exact hosted error and in-flight creation/deletion semantics remain unverified. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/agents/index.mdx b/apps/docs/content/docs/api-reference/agents/index.mdx new file mode 100644 index 000000000..5037ad008 --- /dev/null +++ b/apps/docs/content/docs/api-reference/agents/index.mdx @@ -0,0 +1,14 @@ +--- +title: "Agents" +description: "Agents. Application API: Project API key." +--- + +Public schema constrained by the pinned OpenAI Agents API baseline; documented x_agents_core fields remain Core extensions. + +| Operation | Method | Path | +| --- | --- | --- | +| [List reusable Agents](/api-reference/agents/list-reusable-agents) | `GET` | `/v1/agents` | +| [Create a reusable Agent](/api-reference/agents/create-a-reusable-agent) | `POST` | `/v1/agents` | +| [Retrieve a reusable Agent](/api-reference/agents/retrieve-a-reusable-agent) | `GET` | `/v1/agents/{agent_id}` | +| [Update a reusable Agent](/api-reference/agents/update-a-reusable-agent) | `POST` | `/v1/agents/{agent_id}` | +| [Delete a reusable Agent](/api-reference/agents/delete-a-reusable-agent) | `DELETE` | `/v1/agents/{agent_id}` | diff --git a/apps/docs/content/docs/api-reference/agents/list-reusable-agents.mdx b/apps/docs/content/docs/api-reference/agents/list-reusable-agents.mdx new file mode 100644 index 000000000..28d1748d1 --- /dev/null +++ b/apps/docs/content/docs/api-reference/agents/list-reusable-agents.mdx @@ -0,0 +1,23 @@ +--- +title: List reusable Agents +description: Lists only the authenticated tenant's saved Agents, independently of Sessions. +full: true +_openapi: + method: GET + route: /agents + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Lists only the authenticated tenant's saved Agents, independently of Sessions. Limit 0 is + treated as 1 and larger limits as 100, as observed on the hosted service. The local + default is 20; exact upstream default/cap and empty cursor fields remain unverified. An + unknown, malformed or foreign after cursor returns not found. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Limit 0 is treated as 1 and larger limits as 100, as observed on the hosted service. The local default is 20; exact upstream default/cap and empty cursor fields remain unverified. An unknown, malformed or foreign after cursor returns not found. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/agents/meta.json b/apps/docs/content/docs/api-reference/agents/meta.json new file mode 100644 index 000000000..2c156db2b --- /dev/null +++ b/apps/docs/content/docs/api-reference/agents/meta.json @@ -0,0 +1,10 @@ +{ + "title": "Agents", + "pages": [ + "list-reusable-agents", + "create-a-reusable-agent", + "retrieve-a-reusable-agent", + "update-a-reusable-agent", + "delete-a-reusable-agent" + ] +} diff --git a/apps/docs/content/docs/api-reference/agents/retrieve-a-reusable-agent.mdx b/apps/docs/content/docs/api-reference/agents/retrieve-a-reusable-agent.mdx new file mode 100644 index 000000000..1608a3dfc --- /dev/null +++ b/apps/docs/content/docs/api-reference/agents/retrieve-a-reusable-agent.mdx @@ -0,0 +1,19 @@ +--- +title: Retrieve a reusable Agent +description: Reads the saved resource owned by the authenticated tenant, independently of execution Sessions. +full: true +_openapi: + method: GET + route: /agents/{agent_id} + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Reads the saved resource owned by the authenticated tenant, independently of execution + Sessions. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/agents/update-a-reusable-agent.mdx b/apps/docs/content/docs/api-reference/agents/update-a-reusable-agent.mdx new file mode 100644 index 000000000..37e2003bf --- /dev/null +++ b/apps/docs/content/docs/api-reference/agents/update-a-reusable-agent.mdx @@ -0,0 +1,33 @@ +--- +title: Update a reusable Agent +description: Preserves omitted fields and replaces supplied fields using shared saved-configuration validation. +full: true +_openapi: + method: POST + route: /agents/{agent_id} + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Preserves omitted fields and replaces supplied fields using shared saved-configuration + validation. Null name/instructions clear; null or empty metadata clears all pairs. Name, + metadata and configuration validation errors return invalid_request_error with the + official param, using the Agent create rules before the Agent lookup. Existing Session + snapshots are unchanged. Empty updates advance updated_at without changing saved fields. + Nested replacement/null defaults, model-derived reasoning and exact hosted error behavior + remain incompletely verified. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +
+Full description + +Null name/instructions clear; null or empty metadata clears all pairs. Name, metadata and configuration validation errors return invalid_request_error with the official param, using the Agent create rules before the Agent lookup. Existing Session snapshots are unchanged. + +Empty updates advance updated_at without changing saved fields. Nested replacement/null defaults, model-derived reasoning and exact hosted error behavior remain incompletely verified. + +
+ + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/artifacts.mdx b/apps/docs/content/docs/api-reference/artifacts.mdx deleted file mode 100644 index 012154e5f..000000000 --- a/apps/docs/content/docs/api-reference/artifacts.mdx +++ /dev/null @@ -1,33 +0,0 @@ ---- -title: Artifacts -description: >- - Artifacts. Application API: Project API key. Public schema constrained by the - pinned OpenAI Agents API baseline; documented x_agents_core fields remain Core - extensions. -full: true -_openapi: - toc: [] - structuredData: - headings: [] - contents: - - content: >- - Lists published outputs independently of Environment availability. - Sorting uses publication time and ID. A later Turn publishes a path - again only when it is new, its bytes changed, or no Artifact remains - for it. A malformed environment_id matches nothing. An after value - that is not an Artifact of this Session, including a malformed one, - returns 400 invalid_request_error with the message "after is not a - valid artifact ID". The local default page size is 20; exact upstream - defaults remain unverified. - - content: >- - Deletes the published copy without modifying its original workspace - file. Already admitted content reads may finish; later reads reject. - - content: >- - Streams stored bytes after tenant and Session authorization, including - after Environment expiration. Exact upstream headers and Range - behavior remain unverified. ---- - -{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} - - \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/artifacts/delete-a-published-artifact.mdx b/apps/docs/content/docs/api-reference/artifacts/delete-a-published-artifact.mdx new file mode 100644 index 000000000..febeb679e --- /dev/null +++ b/apps/docs/content/docs/api-reference/artifacts/delete-a-published-artifact.mdx @@ -0,0 +1,21 @@ +--- +title: Delete a published artifact +description: Deletes the published copy without modifying its original workspace file. +full: true +_openapi: + method: DELETE + route: /agents/sessions/{session_id}/artifacts/{artifact_id} + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Deletes the published copy without modifying its original workspace file. Already admitted + content reads may finish; later reads reject. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Already admitted content reads may finish; later reads reject. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/artifacts/download-immutable-artifact-bytes.mdx b/apps/docs/content/docs/api-reference/artifacts/download-immutable-artifact-bytes.mdx new file mode 100644 index 000000000..82d95661d --- /dev/null +++ b/apps/docs/content/docs/api-reference/artifacts/download-immutable-artifact-bytes.mdx @@ -0,0 +1,23 @@ +--- +title: Download immutable artifact bytes +description: >- + Streams stored bytes after tenant and Session authorization, including after Environment + expiration. +full: true +_openapi: + method: GET + route: /agents/sessions/{session_id}/artifacts/{artifact_id}/content + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Streams stored bytes after tenant and Session authorization, including after Environment + expiration. Exact upstream headers and Range behavior remain unverified. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Exact upstream headers and Range behavior remain unverified. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/artifacts/index.mdx b/apps/docs/content/docs/api-reference/artifacts/index.mdx new file mode 100644 index 000000000..66ed693f6 --- /dev/null +++ b/apps/docs/content/docs/api-reference/artifacts/index.mdx @@ -0,0 +1,13 @@ +--- +title: "Artifacts" +description: "Artifacts. Application API: Project API key." +--- + +Public schema constrained by the pinned OpenAI Agents API baseline; documented x_agents_core fields remain Core extensions. + +| Operation | Method | Path | +| --- | --- | --- | +| [List immutable Session artifacts](/api-reference/artifacts/list-immutable-session-artifacts) | `GET` | `/v1/agents/sessions/{session_id}/artifacts` | +| [Retrieve immutable artifact metadata](/api-reference/artifacts/retrieve-immutable-artifact-metadata) | `GET` | `/v1/agents/sessions/{session_id}/artifacts/{artifact_id}` | +| [Delete a published artifact](/api-reference/artifacts/delete-a-published-artifact) | `DELETE` | `/v1/agents/sessions/{session_id}/artifacts/{artifact_id}` | +| [Download immutable artifact bytes](/api-reference/artifacts/download-immutable-artifact-bytes) | `GET` | `/v1/agents/sessions/{session_id}/artifacts/{artifact_id}/content` | diff --git a/apps/docs/content/docs/api-reference/artifacts/list-immutable-session-artifacts.mdx b/apps/docs/content/docs/api-reference/artifacts/list-immutable-session-artifacts.mdx new file mode 100644 index 000000000..21da7a353 --- /dev/null +++ b/apps/docs/content/docs/api-reference/artifacts/list-immutable-session-artifacts.mdx @@ -0,0 +1,32 @@ +--- +title: List immutable Session artifacts +description: Lists published outputs independently of Environment availability. +full: true +_openapi: + method: GET + route: /agents/sessions/{session_id}/artifacts + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Lists published outputs independently of Environment availability. Sorting uses + publication time and ID. A later Turn publishes a path again only when it is new, its + bytes changed, or no Artifact remains for it. A malformed environment_id matches nothing. + An after value that is not an Artifact of this Session, including a malformed one, returns + 400 invalid_request_error with the message "after is not a valid artifact ID". The local + default page size is 20; exact upstream defaults remain unverified. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +
+Full description + +Sorting uses publication time and ID. A later Turn publishes a path again only when it is new, its bytes changed, or no Artifact remains for it. A malformed environment_id matches nothing. + +An after value that is not an Artifact of this Session, including a malformed one, returns 400 invalid_request_error with the message "after is not a valid artifact ID". The local default page size is 20; exact upstream defaults remain unverified. + +
+ + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/artifacts/meta.json b/apps/docs/content/docs/api-reference/artifacts/meta.json new file mode 100644 index 000000000..1e61c0a2c --- /dev/null +++ b/apps/docs/content/docs/api-reference/artifacts/meta.json @@ -0,0 +1,9 @@ +{ + "title": "Artifacts", + "pages": [ + "list-immutable-session-artifacts", + "retrieve-immutable-artifact-metadata", + "delete-a-published-artifact", + "download-immutable-artifact-bytes" + ] +} diff --git a/apps/docs/content/docs/api-reference/artifacts/retrieve-immutable-artifact-metadata.mdx b/apps/docs/content/docs/api-reference/artifacts/retrieve-immutable-artifact-metadata.mdx new file mode 100644 index 000000000..3e68b5b4b --- /dev/null +++ b/apps/docs/content/docs/api-reference/artifacts/retrieve-immutable-artifact-metadata.mdx @@ -0,0 +1,16 @@ +--- +title: Retrieve immutable artifact metadata +full: true +_openapi: + method: GET + route: /agents/sessions/{session_id}/artifacts/{artifact_id} + toc: [] + structuredData: + headings: [] + contents: [] +description: '' +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/administrator-projects.mdx b/apps/docs/content/docs/api-reference/core/administrator-projects.mdx deleted file mode 100644 index 81b0dd3ca..000000000 --- a/apps/docs/content/docs/api-reference/core/administrator-projects.mdx +++ /dev/null @@ -1,17 +0,0 @@ ---- -title: Administrator Projects -description: >- - Administrator Projects. Core administration API: Core key held by Web’s server - or an operator script. Generated local management contract. This is not part - of the public OpenAI API. -full: true -_openapi: - toc: [] - structuredData: - headings: [] - contents: [] ---- - -{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} - - \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/administrator-projects/archive-a-project-and-revoke-all-its-keys-while-retaining-assets.mdx b/apps/docs/content/docs/api-reference/core/administrator-projects/archive-a-project-and-revoke-all-its-keys-while-retaining-assets.mdx new file mode 100644 index 000000000..c94d5c1dc --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/administrator-projects/archive-a-project-and-revoke-all-its-keys-while-retaining-assets.mdx @@ -0,0 +1,16 @@ +--- +title: Archive a Project and revoke all its keys while retaining assets +full: true +_openapi: + method: POST + route: /core/v1/projects/{project_id}/archive + toc: [] + structuredData: + headings: [] + contents: [] +description: '' +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/administrator-projects/create-an-empty-independent-project.mdx b/apps/docs/content/docs/api-reference/core/administrator-projects/create-an-empty-independent-project.mdx new file mode 100644 index 000000000..6a477fa94 --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/administrator-projects/create-an-empty-independent-project.mdx @@ -0,0 +1,16 @@ +--- +title: Create an empty independent Project +full: true +_openapi: + method: POST + route: /core/v1/projects + toc: [] + structuredData: + headings: [] + contents: [] +description: '' +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/administrator-projects/index.mdx b/apps/docs/content/docs/api-reference/core/administrator-projects/index.mdx new file mode 100644 index 000000000..df7f03ace --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/administrator-projects/index.mdx @@ -0,0 +1,16 @@ +--- +title: "Administrator Projects" +description: "Administrator Projects. Core administration API: Core key held by Web’s server or an operator script." +--- + +Generated local management contract. This is not part of the public OpenAI API. + +| Operation | Method | Path | +| --- | --- | --- | +| [List Projects and active key counts](/api-reference/core/administrator-projects/list-projects-and-active-key-counts) | `GET` | `/core/v1/projects` | +| [Create an empty independent Project](/api-reference/core/administrator-projects/create-an-empty-independent-project) | `POST` | `/core/v1/projects` | +| [Rename a Project](/api-reference/core/administrator-projects/rename-a-project) | `POST` | `/core/v1/projects/{project_id}` | +| [Archive a Project and revoke all its keys while retaining assets](/api-reference/core/administrator-projects/archive-a-project-and-revoke-all-its-keys-while-retaining-assets) | `POST` | `/core/v1/projects/{project_id}/archive` | +| [List safe key metadata for a Project](/api-reference/core/administrator-projects/list-safe-key-metadata-for-a-project) | `GET` | `/core/v1/projects/{project_id}/keys` | +| [Issue an independent secret in an existing Project](/api-reference/core/administrator-projects/issue-an-independent-secret-in-an-existing-project) | `POST` | `/core/v1/projects/{project_id}/keys` | +| [Revoke one Project key while retaining shared assets](/api-reference/core/administrator-projects/revoke-one-project-key-while-retaining-shared-assets) | `DELETE` | `/core/v1/projects/{project_id}/keys/{key_id}` | diff --git a/apps/docs/content/docs/api-reference/core/administrator-projects/issue-an-independent-secret-in-an-existing-project.mdx b/apps/docs/content/docs/api-reference/core/administrator-projects/issue-an-independent-secret-in-an-existing-project.mdx new file mode 100644 index 000000000..587d44cd8 --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/administrator-projects/issue-an-independent-secret-in-an-existing-project.mdx @@ -0,0 +1,16 @@ +--- +title: Issue an independent secret in an existing Project +full: true +_openapi: + method: POST + route: /core/v1/projects/{project_id}/keys + toc: [] + structuredData: + headings: [] + contents: [] +description: '' +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/administrator-projects/list-projects-and-active-key-counts.mdx b/apps/docs/content/docs/api-reference/core/administrator-projects/list-projects-and-active-key-counts.mdx new file mode 100644 index 000000000..14599e8f7 --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/administrator-projects/list-projects-and-active-key-counts.mdx @@ -0,0 +1,16 @@ +--- +title: List Projects and active key counts +full: true +_openapi: + method: GET + route: /core/v1/projects + toc: [] + structuredData: + headings: [] + contents: [] +description: '' +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/administrator-projects/list-safe-key-metadata-for-a-project.mdx b/apps/docs/content/docs/api-reference/core/administrator-projects/list-safe-key-metadata-for-a-project.mdx new file mode 100644 index 000000000..7e826912f --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/administrator-projects/list-safe-key-metadata-for-a-project.mdx @@ -0,0 +1,16 @@ +--- +title: List safe key metadata for a Project +full: true +_openapi: + method: GET + route: /core/v1/projects/{project_id}/keys + toc: [] + structuredData: + headings: [] + contents: [] +description: '' +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/administrator-projects/meta.json b/apps/docs/content/docs/api-reference/core/administrator-projects/meta.json new file mode 100644 index 000000000..7f115f309 --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/administrator-projects/meta.json @@ -0,0 +1,12 @@ +{ + "title": "Administrator Projects", + "pages": [ + "list-projects-and-active-key-counts", + "create-an-empty-independent-project", + "rename-a-project", + "archive-a-project-and-revoke-all-its-keys-while-retaining-assets", + "list-safe-key-metadata-for-a-project", + "issue-an-independent-secret-in-an-existing-project", + "revoke-one-project-key-while-retaining-shared-assets" + ] +} diff --git a/apps/docs/content/docs/api-reference/core/administrator-projects/rename-a-project.mdx b/apps/docs/content/docs/api-reference/core/administrator-projects/rename-a-project.mdx new file mode 100644 index 000000000..a4f4dc1d5 --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/administrator-projects/rename-a-project.mdx @@ -0,0 +1,16 @@ +--- +title: Rename a Project +full: true +_openapi: + method: POST + route: /core/v1/projects/{project_id} + toc: [] + structuredData: + headings: [] + contents: [] +description: '' +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/administrator-projects/revoke-one-project-key-while-retaining-shared-assets.mdx b/apps/docs/content/docs/api-reference/core/administrator-projects/revoke-one-project-key-while-retaining-shared-assets.mdx new file mode 100644 index 000000000..b1b7ed4c9 --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/administrator-projects/revoke-one-project-key-while-retaining-shared-assets.mdx @@ -0,0 +1,16 @@ +--- +title: Revoke one Project key while retaining shared assets +full: true +_openapi: + method: DELETE + route: /core/v1/projects/{project_id}/keys/{key_id} + toc: [] + structuredData: + headings: [] + contents: [] +description: '' +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/agents.mdx b/apps/docs/content/docs/api-reference/core/agents.mdx deleted file mode 100644 index 3efbe8afb..000000000 --- a/apps/docs/content/docs/api-reference/core/agents.mdx +++ /dev/null @@ -1,29 +0,0 @@ ---- -title: Agents -description: >- - Agents. Core administration API: Core key held by Web’s server or an operator - script. Generated local management contract. This is not part of the public - OpenAI API. -full: true -_openapi: - toc: [] - structuredData: - headings: [] - contents: - - content: >- - Core key only. Reuses the public resource projection and operation - rules; the Project ID selects the target space and does not - authenticate. - - content: >- - Core key only. Reuses the public resource projection and operation - rules; the Project ID selects the target space and does not - authenticate. - - content: >- - Core key only. Reuses the public resource projection and operation - rules; the Project ID selects the target space and does not - authenticate. ---- - -{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} - - \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/agents/delete-a-reusable-agent-in-a-project.mdx b/apps/docs/content/docs/api-reference/core/agents/delete-a-reusable-agent-in-a-project.mdx new file mode 100644 index 000000000..656f30e42 --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/agents/delete-a-reusable-agent-in-a-project.mdx @@ -0,0 +1,21 @@ +--- +title: Delete a reusable Agent in a Project +description: Core key only. +full: true +_openapi: + method: DELETE + route: /core/v1/projects/{project_id}/agents/{agent_id} + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Core key only. Reuses the public resource projection and operation rules; the Project ID + selects the target space and does not authenticate. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Reuses the public resource projection and operation rules; the Project ID selects the target space and does not authenticate. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/agents/index.mdx b/apps/docs/content/docs/api-reference/core/agents/index.mdx new file mode 100644 index 000000000..365337b23 --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/agents/index.mdx @@ -0,0 +1,12 @@ +--- +title: "Agents" +description: "Agents. Core administration API: Core key held by Web’s server or an operator script." +--- + +Generated local management contract. This is not part of the public OpenAI API. + +| Operation | Method | Path | +| --- | --- | --- | +| [List reusable Agents in a Project](/api-reference/core/agents/list-reusable-agents-in-a-project) | `GET` | `/core/v1/projects/{project_id}/agents` | +| [Retrieve a reusable Agent in a Project](/api-reference/core/agents/retrieve-a-reusable-agent-in-a-project) | `GET` | `/core/v1/projects/{project_id}/agents/{agent_id}` | +| [Delete a reusable Agent in a Project](/api-reference/core/agents/delete-a-reusable-agent-in-a-project) | `DELETE` | `/core/v1/projects/{project_id}/agents/{agent_id}` | diff --git a/apps/docs/content/docs/api-reference/core/agents/list-reusable-agents-in-a-project.mdx b/apps/docs/content/docs/api-reference/core/agents/list-reusable-agents-in-a-project.mdx new file mode 100644 index 000000000..b9d153ec7 --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/agents/list-reusable-agents-in-a-project.mdx @@ -0,0 +1,21 @@ +--- +title: List reusable Agents in a Project +description: Core key only. +full: true +_openapi: + method: GET + route: /core/v1/projects/{project_id}/agents + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Core key only. Reuses the public resource projection and operation rules; the Project ID + selects the target space and does not authenticate. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Reuses the public resource projection and operation rules; the Project ID selects the target space and does not authenticate. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/agents/meta.json b/apps/docs/content/docs/api-reference/core/agents/meta.json new file mode 100644 index 000000000..79754b5f3 --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/agents/meta.json @@ -0,0 +1,8 @@ +{ + "title": "Agents", + "pages": [ + "list-reusable-agents-in-a-project", + "retrieve-a-reusable-agent-in-a-project", + "delete-a-reusable-agent-in-a-project" + ] +} diff --git a/apps/docs/content/docs/api-reference/core/agents/retrieve-a-reusable-agent-in-a-project.mdx b/apps/docs/content/docs/api-reference/core/agents/retrieve-a-reusable-agent-in-a-project.mdx new file mode 100644 index 000000000..f51a52c67 --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/agents/retrieve-a-reusable-agent-in-a-project.mdx @@ -0,0 +1,21 @@ +--- +title: Retrieve a reusable Agent in a Project +description: Core key only. +full: true +_openapi: + method: GET + route: /core/v1/projects/{project_id}/agents/{agent_id} + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Core key only. Reuses the public resource projection and operation rules; the Project ID + selects the target space and does not authenticate. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Reuses the public resource projection and operation rules; the Project ID selects the target space and does not authenticate. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/artifacts.mdx b/apps/docs/content/docs/api-reference/core/artifacts.mdx deleted file mode 100644 index 94f4020b7..000000000 --- a/apps/docs/content/docs/api-reference/core/artifacts.mdx +++ /dev/null @@ -1,33 +0,0 @@ ---- -title: Artifacts -description: >- - Artifacts. Core administration API: Core key held by Web’s server or an - operator script. Generated local management contract. This is not part of the - public OpenAI API. -full: true -_openapi: - toc: [] - structuredData: - headings: [] - contents: - - content: >- - Core key only. Reuses the public resource projection and operation - rules; the Project ID selects the target space and does not - authenticate. - - content: >- - Core key only. Reuses the public resource projection and operation - rules; the Project ID selects the target space and does not - authenticate. - - content: >- - Core key only. Reuses the public resource projection and operation - rules; the Project ID selects the target space and does not - authenticate. - - content: >- - Core key only. Reuses the public resource projection and operation - rules; the Project ID selects the target space and does not - authenticate. ---- - -{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} - - \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/artifacts/delete-a-published-artifact-in-a-project.mdx b/apps/docs/content/docs/api-reference/core/artifacts/delete-a-published-artifact-in-a-project.mdx new file mode 100644 index 000000000..772418363 --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/artifacts/delete-a-published-artifact-in-a-project.mdx @@ -0,0 +1,21 @@ +--- +title: Delete a published artifact in a Project +description: Core key only. +full: true +_openapi: + method: DELETE + route: /core/v1/projects/{project_id}/sessions/{session_id}/artifacts/{artifact_id} + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Core key only. Reuses the public resource projection and operation rules; the Project ID + selects the target space and does not authenticate. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Reuses the public resource projection and operation rules; the Project ID selects the target space and does not authenticate. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/artifacts/download-immutable-artifact-bytes-in-a-project.mdx b/apps/docs/content/docs/api-reference/core/artifacts/download-immutable-artifact-bytes-in-a-project.mdx new file mode 100644 index 000000000..796e20316 --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/artifacts/download-immutable-artifact-bytes-in-a-project.mdx @@ -0,0 +1,21 @@ +--- +title: Download immutable artifact bytes in a Project +description: Core key only. +full: true +_openapi: + method: GET + route: /core/v1/projects/{project_id}/sessions/{session_id}/artifacts/{artifact_id}/content + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Core key only. Reuses the public resource projection and operation rules; the Project ID + selects the target space and does not authenticate. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Reuses the public resource projection and operation rules; the Project ID selects the target space and does not authenticate. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/artifacts/index.mdx b/apps/docs/content/docs/api-reference/core/artifacts/index.mdx new file mode 100644 index 000000000..a1e0d4840 --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/artifacts/index.mdx @@ -0,0 +1,13 @@ +--- +title: "Artifacts" +description: "Artifacts. Core administration API: Core key held by Web’s server or an operator script." +--- + +Generated local management contract. This is not part of the public OpenAI API. + +| Operation | Method | Path | +| --- | --- | --- | +| [List immutable Session artifacts in a Project](/api-reference/core/artifacts/list-immutable-session-artifacts-in-a-project) | `GET` | `/core/v1/projects/{project_id}/sessions/{session_id}/artifacts` | +| [Retrieve immutable artifact metadata in a Project](/api-reference/core/artifacts/retrieve-immutable-artifact-metadata-in-a-project) | `GET` | `/core/v1/projects/{project_id}/sessions/{session_id}/artifacts/{artifact_id}` | +| [Delete a published artifact in a Project](/api-reference/core/artifacts/delete-a-published-artifact-in-a-project) | `DELETE` | `/core/v1/projects/{project_id}/sessions/{session_id}/artifacts/{artifact_id}` | +| [Download immutable artifact bytes in a Project](/api-reference/core/artifacts/download-immutable-artifact-bytes-in-a-project) | `GET` | `/core/v1/projects/{project_id}/sessions/{session_id}/artifacts/{artifact_id}/content` | diff --git a/apps/docs/content/docs/api-reference/core/artifacts/list-immutable-session-artifacts-in-a-project.mdx b/apps/docs/content/docs/api-reference/core/artifacts/list-immutable-session-artifacts-in-a-project.mdx new file mode 100644 index 000000000..9856f86e4 --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/artifacts/list-immutable-session-artifacts-in-a-project.mdx @@ -0,0 +1,21 @@ +--- +title: List immutable Session artifacts in a Project +description: Core key only. +full: true +_openapi: + method: GET + route: /core/v1/projects/{project_id}/sessions/{session_id}/artifacts + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Core key only. Reuses the public resource projection and operation rules; the Project ID + selects the target space and does not authenticate. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Reuses the public resource projection and operation rules; the Project ID selects the target space and does not authenticate. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/artifacts/meta.json b/apps/docs/content/docs/api-reference/core/artifacts/meta.json new file mode 100644 index 000000000..69f22ced7 --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/artifacts/meta.json @@ -0,0 +1,9 @@ +{ + "title": "Artifacts", + "pages": [ + "list-immutable-session-artifacts-in-a-project", + "retrieve-immutable-artifact-metadata-in-a-project", + "delete-a-published-artifact-in-a-project", + "download-immutable-artifact-bytes-in-a-project" + ] +} diff --git a/apps/docs/content/docs/api-reference/core/artifacts/retrieve-immutable-artifact-metadata-in-a-project.mdx b/apps/docs/content/docs/api-reference/core/artifacts/retrieve-immutable-artifact-metadata-in-a-project.mdx new file mode 100644 index 000000000..23e95718e --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/artifacts/retrieve-immutable-artifact-metadata-in-a-project.mdx @@ -0,0 +1,21 @@ +--- +title: Retrieve immutable artifact metadata in a Project +description: Core key only. +full: true +_openapi: + method: GET + route: /core/v1/projects/{project_id}/sessions/{session_id}/artifacts/{artifact_id} + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Core key only. Reuses the public resource projection and operation rules; the Project ID + selects the target space and does not authenticate. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Reuses the public resource projection and operation rules; the Project ID selects the target space and does not authenticate. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/core-administration.mdx b/apps/docs/content/docs/api-reference/core/core-administration.mdx deleted file mode 100644 index 0ed580f68..000000000 --- a/apps/docs/content/docs/api-reference/core/core-administration.mdx +++ /dev/null @@ -1,56 +0,0 @@ ---- -title: Core Administration -description: >- - Core Administration. Core administration API: Core key held by Web’s server or - an operator script. Generated local management contract. This is not part of - the public OpenAI API. -full: true -_openapi: - toc: [] - structuredData: - headings: [] - contents: - - content: >- - Core key only. Newest-first cursor pagination of safe metadata. Actor - labels are unverified console labels, not authorization identities. - Request bodies and secrets are never recorded. - - content: >- - Core key only; available before any sandbox deployment exists. Reports - the public URL that applications, nodes, sandboxes and self-hosted - executors use, the API base URL, Core's source commit and installation - ID, the installer's settings snapshot with where to change it, and - what is bound to the current public URL. Sensitive settings report - only whether they are configured. - - content: >- - Core key only. Complete UTC buckets; unknown measurements are null. - Samples are process-local and are not backfilled after a restart. - - content: >- - Core key only. Reports actual resource disposition, including expiry - and failure cleanup. This is not archive provenance and does not - assert active Turn settlement. Read this after an uncertain archive - response; never infer released from a missing sandbox alone. - - content: >- - Core key only. Requires the current deployment generation; no - maintenance mode is required. Permanently closes execution, requests - cancellation and releases sandbox/snapshots through existing cleanup. - Session history and persisted files/artifacts remain; unpersisted - workspace contents are lost. A cleanup_pending response is not proof - of resource release. Does not affect caller-managed Runtime. - - content: >- - Core key only. Each observation is labelled with its owning Project - ID. Uses the existing read-only Runtime sampler, with bounded - concurrency and no execution or provisioning. A provider with a batch - metrics read, such as E2B, samples the page's running sandboxes in one - bounded request. - - content: >- - Core key only. after/limit/order paginate Projects. Agent grouping - returns groups within those spaces. Date bounds filter Session - creation, not current asset counts. Usage sums only non-null public - Session usage; coverage includes every selected Session. Each Project - is read in a consistent database snapshot. Totals are not billing - records. ---- - -{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} - - \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/core-administration/index.mdx b/apps/docs/content/docs/api-reference/core/core-administration/index.mdx new file mode 100644 index 000000000..6d335f9ac --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/core-administration/index.mdx @@ -0,0 +1,16 @@ +--- +title: "Core Administration" +description: "Core Administration. Core administration API: Core key held by Web’s server or an operator script." +--- + +Generated local management contract. This is not part of the public OpenAI API. + +| Operation | Method | Path | +| --- | --- | --- | +| [Query committed administrator mutations](/api-reference/core/core-administration/query-committed-administrator-mutations) | `GET` | `/core/v1/audit-log` | +| [Retrieve installation facts and process settings](/api-reference/core/core-administration/retrieve-installation-facts-and-process-settings) | `GET` | `/core/v1/installation` | +| [Retrieve Core operational metrics](/api-reference/core/core-administration/retrieve-core-operational-metrics) | `GET` | `/core/v1/metrics` | +| [Retrieve a managed Session's resource cleanup state](/api-reference/core/core-administration/retrieve-a-managed-session-s-resource-cleanup-state) | `GET` | `/core/v1/projects/{project_id}/sessions/{session_id}/archive` | +| [Release a managed Session's execution resources while retaining history](/api-reference/core/core-administration/release-a-managed-session-s-execution-resources-while-retaining-history) | `POST` | `/core/v1/projects/{project_id}/sessions/{session_id}/archive` | +| [List Runtime observations across managed Projects](/api-reference/core/core-administration/list-runtime-observations-across-managed-projects) | `GET` | `/core/v1/sandbox/runtime-observations` | +| [Summarize resource counts and Session usage by Project, Agent or creator key](/api-reference/core/core-administration/summarize-resource-counts-and-session-usage-by-project-agent-or-creator-key) | `GET` | `/core/v1/summary` | diff --git a/apps/docs/content/docs/api-reference/core/core-administration/list-runtime-observations-across-managed-projects.mdx b/apps/docs/content/docs/api-reference/core/core-administration/list-runtime-observations-across-managed-projects.mdx new file mode 100644 index 000000000..a47a15493 --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/core-administration/list-runtime-observations-across-managed-projects.mdx @@ -0,0 +1,23 @@ +--- +title: List Runtime observations across managed Projects +description: Core key only. Each observation is labelled with its owning Project ID. +full: true +_openapi: + method: GET + route: /core/v1/sandbox/runtime-observations + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Core key only. Each observation is labelled with its owning Project ID. Uses the existing + read-only Runtime sampler, with bounded concurrency and no execution or provisioning. A + provider with a batch metrics read, such as E2B, samples the page's running sandboxes in + one bounded request. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Uses the existing read-only Runtime sampler, with bounded concurrency and no execution or provisioning. A provider with a batch metrics read, such as E2B, samples the page's running sandboxes in one bounded request. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/core-administration/meta.json b/apps/docs/content/docs/api-reference/core/core-administration/meta.json new file mode 100644 index 000000000..aea6a88cd --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/core-administration/meta.json @@ -0,0 +1,12 @@ +{ + "title": "Core Administration", + "pages": [ + "query-committed-administrator-mutations", + "retrieve-installation-facts-and-process-settings", + "retrieve-core-operational-metrics", + "retrieve-a-managed-session-s-resource-cleanup-state", + "release-a-managed-session-s-execution-resources-while-retaining-history", + "list-runtime-observations-across-managed-projects", + "summarize-resource-counts-and-session-usage-by-project-agent-or-creator-key" + ] +} diff --git a/apps/docs/content/docs/api-reference/core/core-administration/query-committed-administrator-mutations.mdx b/apps/docs/content/docs/api-reference/core/core-administration/query-committed-administrator-mutations.mdx new file mode 100644 index 000000000..b5fe25feb --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/core-administration/query-committed-administrator-mutations.mdx @@ -0,0 +1,22 @@ +--- +title: Query committed administrator mutations +description: Core key only. Newest-first cursor pagination of safe metadata. +full: true +_openapi: + method: GET + route: /core/v1/audit-log + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Core key only. Newest-first cursor pagination of safe metadata. Actor labels are + unverified console labels, not authorization identities. Request bodies and secrets are + never recorded. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Actor labels are unverified console labels, not authorization identities. Request bodies and secrets are never recorded. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/core-administration/release-a-managed-session-s-execution-resources-while-retaining-history.mdx b/apps/docs/content/docs/api-reference/core/core-administration/release-a-managed-session-s-execution-resources-while-retaining-history.mdx new file mode 100644 index 000000000..39ec2c3c4 --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/core-administration/release-a-managed-session-s-execution-resources-while-retaining-history.mdx @@ -0,0 +1,26 @@ +--- +title: Release a managed Session's execution resources while retaining history +description: Core key only. Requires the current deployment generation; no maintenance mode is required. +full: true +_openapi: + method: POST + route: /core/v1/projects/{project_id}/sessions/{session_id}/archive + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Core key only. Requires the current deployment generation; no maintenance mode is + required. Permanently closes execution, requests cancellation and releases + sandbox/snapshots through existing cleanup. Session history and persisted files/artifacts + remain; unpersisted workspace contents are lost. A cleanup_pending response is not proof + of resource release. Does not affect caller-managed Runtime. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Permanently closes execution, requests cancellation and releases sandbox/snapshots through existing cleanup. Session history and persisted files/artifacts remain; unpersisted workspace contents are lost. A cleanup_pending response is not proof of resource release. + +Does not affect caller-managed Runtime. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/core-administration/retrieve-a-managed-session-s-resource-cleanup-state.mdx b/apps/docs/content/docs/api-reference/core/core-administration/retrieve-a-managed-session-s-resource-cleanup-state.mdx new file mode 100644 index 000000000..ebbc1b0f3 --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/core-administration/retrieve-a-managed-session-s-resource-cleanup-state.mdx @@ -0,0 +1,22 @@ +--- +title: Retrieve a managed Session's resource cleanup state +description: Core key only. Reports actual resource disposition, including expiry and failure cleanup. +full: true +_openapi: + method: GET + route: /core/v1/projects/{project_id}/sessions/{session_id}/archive + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Core key only. Reports actual resource disposition, including expiry and failure cleanup. + This is not archive provenance and does not assert active Turn settlement. Read this after + an uncertain archive response; never infer released from a missing sandbox alone. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +This is not archive provenance and does not assert active Turn settlement. Read this after an uncertain archive response; never infer released from a missing sandbox alone. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/core-administration/retrieve-core-operational-metrics.mdx b/apps/docs/content/docs/api-reference/core/core-administration/retrieve-core-operational-metrics.mdx new file mode 100644 index 000000000..97df1304a --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/core-administration/retrieve-core-operational-metrics.mdx @@ -0,0 +1,21 @@ +--- +title: Retrieve Core operational metrics +description: Core key only. Complete UTC buckets; unknown measurements are null. +full: true +_openapi: + method: GET + route: /core/v1/metrics + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Core key only. Complete UTC buckets; unknown measurements are null. Samples are + process-local and are not backfilled after a restart. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Samples are process-local and are not backfilled after a restart. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/core-administration/retrieve-installation-facts-and-process-settings.mdx b/apps/docs/content/docs/api-reference/core/core-administration/retrieve-installation-facts-and-process-settings.mdx new file mode 100644 index 000000000..875f61961 --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/core-administration/retrieve-installation-facts-and-process-settings.mdx @@ -0,0 +1,24 @@ +--- +title: Retrieve installation facts and process settings +description: Core key only; available before any sandbox deployment exists. +full: true +_openapi: + method: GET + route: /core/v1/installation + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Core key only; available before any sandbox deployment exists. Reports the public URL that + applications, nodes, sandboxes and self-hosted executors use, the API base URL, Core's + source commit and installation ID, the installer's settings snapshot with where to change + it, and what is bound to the current public URL. Sensitive settings report only whether + they are configured. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Reports the public URL that applications, nodes, sandboxes and self-hosted executors use, the API base URL, Core's source commit and installation ID, the installer's settings snapshot with where to change it, and what is bound to the current public URL. Sensitive settings report only whether they are configured. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/core-administration/summarize-resource-counts-and-session-usage-by-project-agent-or-creator-key.mdx b/apps/docs/content/docs/api-reference/core/core-administration/summarize-resource-counts-and-session-usage-by-project-agent-or-creator-key.mdx new file mode 100644 index 000000000..15cd4992d --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/core-administration/summarize-resource-counts-and-session-usage-by-project-agent-or-creator-key.mdx @@ -0,0 +1,25 @@ +--- +title: Summarize resource counts and Session usage by Project, Agent or creator key +description: Core key only. after/limit/order paginate Projects. +full: true +_openapi: + method: GET + route: /core/v1/summary + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Core key only. after/limit/order paginate Projects. Agent grouping returns groups within + those spaces. Date bounds filter Session creation, not current asset counts. Usage sums + only non-null public Session usage; coverage includes every selected Session. Each Project + is read in a consistent database snapshot. Totals are not billing records. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Agent grouping returns groups within those spaces. Date bounds filter Session creation, not current asset counts. Usage sums only non-null public Session usage; coverage includes every selected Session. + +Each Project is read in a consistent database snapshot. Totals are not billing records. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/credentials.mdx b/apps/docs/content/docs/api-reference/core/credentials.mdx deleted file mode 100644 index f28389c4e..000000000 --- a/apps/docs/content/docs/api-reference/core/credentials.mdx +++ /dev/null @@ -1,29 +0,0 @@ ---- -title: Credentials -description: >- - Credentials. Core administration API: Core key held by Web’s server or an - operator script. Generated local management contract. This is not part of the - public OpenAI API. -full: true -_openapi: - toc: [] - structuredData: - headings: [] - contents: - - content: >- - Core key only. Reuses the public resource projection and operation - rules; the Project ID selects the target space and does not - authenticate. - - content: >- - Core key only. Reuses the public resource projection and operation - rules; the Project ID selects the target space and does not - authenticate. - - content: >- - Core key only. Reuses the public resource projection and operation - rules; the Project ID selects the target space and does not - authenticate. ---- - -{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} - - \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/credentials/delete-a-vault-credential-in-a-project.mdx b/apps/docs/content/docs/api-reference/core/credentials/delete-a-vault-credential-in-a-project.mdx new file mode 100644 index 000000000..26377ff7f --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/credentials/delete-a-vault-credential-in-a-project.mdx @@ -0,0 +1,21 @@ +--- +title: Delete a Vault Credential in a Project +description: Core key only. +full: true +_openapi: + method: DELETE + route: /core/v1/projects/{project_id}/vaults/{vault_id}/credentials/{credential_id} + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Core key only. Reuses the public resource projection and operation rules; the Project ID + selects the target space and does not authenticate. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Reuses the public resource projection and operation rules; the Project ID selects the target space and does not authenticate. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/credentials/index.mdx b/apps/docs/content/docs/api-reference/core/credentials/index.mdx new file mode 100644 index 000000000..ff7903022 --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/credentials/index.mdx @@ -0,0 +1,12 @@ +--- +title: "Credentials" +description: "Credentials. Core administration API: Core key held by Web’s server or an operator script." +--- + +Generated local management contract. This is not part of the public OpenAI API. + +| Operation | Method | Path | +| --- | --- | --- | +| [List safe Vault Credential metadata in a Project](/api-reference/core/credentials/list-safe-vault-credential-metadata-in-a-project) | `GET` | `/core/v1/projects/{project_id}/vaults/{vault_id}/credentials` | +| [Retrieve safe Vault Credential metadata in a Project](/api-reference/core/credentials/retrieve-safe-vault-credential-metadata-in-a-project) | `GET` | `/core/v1/projects/{project_id}/vaults/{vault_id}/credentials/{credential_id}` | +| [Delete a Vault Credential in a Project](/api-reference/core/credentials/delete-a-vault-credential-in-a-project) | `DELETE` | `/core/v1/projects/{project_id}/vaults/{vault_id}/credentials/{credential_id}` | diff --git a/apps/docs/content/docs/api-reference/core/credentials/list-safe-vault-credential-metadata-in-a-project.mdx b/apps/docs/content/docs/api-reference/core/credentials/list-safe-vault-credential-metadata-in-a-project.mdx new file mode 100644 index 000000000..f9649ed64 --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/credentials/list-safe-vault-credential-metadata-in-a-project.mdx @@ -0,0 +1,21 @@ +--- +title: List safe Vault Credential metadata in a Project +description: Core key only. +full: true +_openapi: + method: GET + route: /core/v1/projects/{project_id}/vaults/{vault_id}/credentials + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Core key only. Reuses the public resource projection and operation rules; the Project ID + selects the target space and does not authenticate. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Reuses the public resource projection and operation rules; the Project ID selects the target space and does not authenticate. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/credentials/meta.json b/apps/docs/content/docs/api-reference/core/credentials/meta.json new file mode 100644 index 000000000..5fe537ae7 --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/credentials/meta.json @@ -0,0 +1,8 @@ +{ + "title": "Credentials", + "pages": [ + "list-safe-vault-credential-metadata-in-a-project", + "retrieve-safe-vault-credential-metadata-in-a-project", + "delete-a-vault-credential-in-a-project" + ] +} diff --git a/apps/docs/content/docs/api-reference/core/credentials/retrieve-safe-vault-credential-metadata-in-a-project.mdx b/apps/docs/content/docs/api-reference/core/credentials/retrieve-safe-vault-credential-metadata-in-a-project.mdx new file mode 100644 index 000000000..9df1a2a4c --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/credentials/retrieve-safe-vault-credential-metadata-in-a-project.mdx @@ -0,0 +1,21 @@ +--- +title: Retrieve safe Vault Credential metadata in a Project +description: Core key only. +full: true +_openapi: + method: GET + route: /core/v1/projects/{project_id}/vaults/{vault_id}/credentials/{credential_id} + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Core key only. Reuses the public resource projection and operation rules; the Project ID + selects the target space and does not authenticate. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Reuses the public resource projection and operation rules; the Project ID selects the target space and does not authenticate. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/deployment-model-providers.mdx b/apps/docs/content/docs/api-reference/core/deployment-model-providers.mdx deleted file mode 100644 index 0ead2b602..000000000 --- a/apps/docs/content/docs/api-reference/core/deployment-model-providers.mdx +++ /dev/null @@ -1,43 +0,0 @@ ---- -title: Deployment Model Providers -description: >- - Deployment Model Providers. Core administration API: Core key held by Web’s - server or an operator script. Generated local management contract. This is not - part of the public OpenAI API. -full: true -_openapi: - toc: [] - structuredData: - headings: [] - contents: - - content: >- - Core key only. Returns every harness this build supports, in name - order. enabled and default are read-only views of the process - configuration (OAC_DEFAULT_HARNESS and OAC_HARNESSES). - model_configuration is the harness's deployment default, stored in - Core, or null. Keys are never returned; api_key_configured reports - that one is set. - - content: >- - Core key only. Returns the safe view; the key is never returned. 404 - when the harness does not exist or has no deployment default. Nullable - last_used_at, last_error_code and last_error_at are best-effort - observations of committed root Turns using this exact default - revision; they do not establish current readiness and may remain stale - indefinitely. - - content: >- - Core key only. Idempotent; each successful request is audited. - Sessions that already froze the default keep it. Afterwards new - openai_hosted Sessions for this harness need a Session or Agent - bundle. - - content: >- - Core key only. Replaces one complete deployment model configuration, - including its write-only provider key. Validates through the selected - Harness declaration and freezes the resolved configuration for new - Sessions; existing Sessions are unchanged. See - contracts/agents-api/model-execution.md#deployment-defaults for - fields, source precedence and observation rules. ---- - -{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} - - \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/deployment-model-providers/index.mdx b/apps/docs/content/docs/api-reference/core/deployment-model-providers/index.mdx new file mode 100644 index 000000000..71db24cf0 --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/deployment-model-providers/index.mdx @@ -0,0 +1,13 @@ +--- +title: "Deployment Model Providers" +description: "Deployment Model Providers. Core administration API: Core key held by Web’s server or an operator script." +--- + +Generated local management contract. This is not part of the public OpenAI API. + +| Operation | Method | Path | +| --- | --- | --- | +| [List harnesses and their deployment default model providers](/api-reference/core/deployment-model-providers/list-harnesses-and-their-deployment-default-model-providers) | `GET` | `/core/v1/harnesses` | +| [Retrieve a harness's deployment default model provider](/api-reference/core/deployment-model-providers/retrieve-a-harness-s-deployment-default-model-provider) | `GET` | `/core/v1/harnesses/{harness}/model-configuration` | +| [Replace a harness's deployment default model provider](/api-reference/core/deployment-model-providers/replace-a-harness-s-deployment-default-model-provider) | `PUT` | `/core/v1/harnesses/{harness}/model-configuration` | +| [Remove a harness's deployment default model provider](/api-reference/core/deployment-model-providers/remove-a-harness-s-deployment-default-model-provider) | `DELETE` | `/core/v1/harnesses/{harness}/model-configuration` | diff --git a/apps/docs/content/docs/api-reference/core/deployment-model-providers/list-harnesses-and-their-deployment-default-model-providers.mdx b/apps/docs/content/docs/api-reference/core/deployment-model-providers/list-harnesses-and-their-deployment-default-model-providers.mdx new file mode 100644 index 000000000..d0619046b --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/deployment-model-providers/list-harnesses-and-their-deployment-default-model-providers.mdx @@ -0,0 +1,26 @@ +--- +title: List harnesses and their deployment default model providers +description: >- + Core key only. Returns every harness this build supports, in name order. enabled and default are + read-only views of the process configuration (OAC_DEFAULT_HARNESS and OAC_HARNESSES). + model_configuration is the harness's deployment default, stored in Core, or null. +full: true +_openapi: + method: GET + route: /core/v1/harnesses + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Core key only. Returns every harness this build supports, in name order. enabled and + default are read-only views of the process configuration (OAC_DEFAULT_HARNESS and + OAC_HARNESSES). model_configuration is the harness's deployment default, stored in Core, + or null. Keys are never returned; api_key_configured reports that one is set. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Keys are never returned; api_key_configured reports that one is set. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/deployment-model-providers/meta.json b/apps/docs/content/docs/api-reference/core/deployment-model-providers/meta.json new file mode 100644 index 000000000..4c66dd121 --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/deployment-model-providers/meta.json @@ -0,0 +1,9 @@ +{ + "title": "Deployment Model Providers", + "pages": [ + "list-harnesses-and-their-deployment-default-model-providers", + "retrieve-a-harness-s-deployment-default-model-provider", + "replace-a-harness-s-deployment-default-model-provider", + "remove-a-harness-s-deployment-default-model-provider" + ] +} diff --git a/apps/docs/content/docs/api-reference/core/deployment-model-providers/remove-a-harness-s-deployment-default-model-provider.mdx b/apps/docs/content/docs/api-reference/core/deployment-model-providers/remove-a-harness-s-deployment-default-model-provider.mdx new file mode 100644 index 000000000..3d038bf48 --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/deployment-model-providers/remove-a-harness-s-deployment-default-model-provider.mdx @@ -0,0 +1,22 @@ +--- +title: Remove a harness's deployment default model provider +description: Core key only. Idempotent; each successful request is audited. +full: true +_openapi: + method: DELETE + route: /core/v1/harnesses/{harness}/model-configuration + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Core key only. Idempotent; each successful request is audited. Sessions that already froze + the default keep it. Afterwards new openai_hosted Sessions for this harness need a Session + or Agent bundle. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Sessions that already froze the default keep it. Afterwards new openai_hosted Sessions for this harness need a Session or Agent bundle. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/deployment-model-providers/replace-a-harness-s-deployment-default-model-provider.mdx b/apps/docs/content/docs/api-reference/core/deployment-model-providers/replace-a-harness-s-deployment-default-model-provider.mdx new file mode 100644 index 000000000..cfbfe50f2 --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/deployment-model-providers/replace-a-harness-s-deployment-default-model-provider.mdx @@ -0,0 +1,26 @@ +--- +title: Replace a harness's deployment default model provider +description: >- + Core key only. Replaces one complete deployment model configuration, including its write-only + provider key. +full: true +_openapi: + method: PUT + route: /core/v1/harnesses/{harness}/model-configuration + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Core key only. Replaces one complete deployment model configuration, including its + write-only provider key. Validates through the selected Harness declaration and freezes + the resolved configuration for new Sessions; existing Sessions are unchanged. See + contracts/agents-api/model-execution.md#deployment-defaults for fields, source precedence + and observation rules. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Validates through the selected Harness declaration and freezes the resolved configuration for new Sessions; existing Sessions are unchanged. See contracts/agents-api/model-execution.md#deployment-defaults for fields, source precedence and observation rules. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/deployment-model-providers/retrieve-a-harness-s-deployment-default-model-provider.mdx b/apps/docs/content/docs/api-reference/core/deployment-model-providers/retrieve-a-harness-s-deployment-default-model-provider.mdx new file mode 100644 index 000000000..d9477d1e1 --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/deployment-model-providers/retrieve-a-harness-s-deployment-default-model-provider.mdx @@ -0,0 +1,26 @@ +--- +title: Retrieve a harness's deployment default model provider +description: >- + Core key only. Returns the safe view; the key is never returned. 404 when the harness does not + exist or has no deployment default. +full: true +_openapi: + method: GET + route: /core/v1/harnesses/{harness}/model-configuration + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Core key only. Returns the safe view; the key is never returned. 404 when the harness does + not exist or has no deployment default. Nullable last_used_at, last_error_code and + last_error_at are best-effort observations of committed root Turns using this exact + default revision; they do not establish current readiness and may remain stale + indefinitely. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Nullable last_used_at, last_error_code and last_error_at are best-effort observations of committed root Turns using this exact default revision; they do not establish current readiness and may remain stale indefinitely. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/environment-templates.mdx b/apps/docs/content/docs/api-reference/core/environment-templates.mdx deleted file mode 100644 index 1f2754d5f..000000000 --- a/apps/docs/content/docs/api-reference/core/environment-templates.mdx +++ /dev/null @@ -1,29 +0,0 @@ ---- -title: Environment Templates -description: >- - Environment Templates. Core administration API: Core key held by Web’s server - or an operator script. Generated local management contract. This is not part - of the public OpenAI API. -full: true -_openapi: - toc: [] - structuredData: - headings: [] - contents: - - content: >- - Core key only. Reuses the public resource projection and operation - rules; the Project ID selects the target space and does not - authenticate. - - content: >- - Core key only. Reuses the public resource projection and operation - rules; the Project ID selects the target space and does not - authenticate. - - content: >- - Core key only. Reuses the public resource projection and operation - rules; the Project ID selects the target space and does not - authenticate. ---- - -{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} - - \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/environment-templates/delete-an-environment-template-in-a-project.mdx b/apps/docs/content/docs/api-reference/core/environment-templates/delete-an-environment-template-in-a-project.mdx new file mode 100644 index 000000000..d7984e045 --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/environment-templates/delete-an-environment-template-in-a-project.mdx @@ -0,0 +1,21 @@ +--- +title: Delete an Environment Template in a Project +description: Core key only. +full: true +_openapi: + method: DELETE + route: /core/v1/projects/{project_id}/environment-templates/{environment_template_id} + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Core key only. Reuses the public resource projection and operation rules; the Project ID + selects the target space and does not authenticate. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Reuses the public resource projection and operation rules; the Project ID selects the target space and does not authenticate. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/environment-templates/index.mdx b/apps/docs/content/docs/api-reference/core/environment-templates/index.mdx new file mode 100644 index 000000000..9c191a9e0 --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/environment-templates/index.mdx @@ -0,0 +1,12 @@ +--- +title: "Environment Templates" +description: "Environment Templates. Core administration API: Core key held by Web’s server or an operator script." +--- + +Generated local management contract. This is not part of the public OpenAI API. + +| Operation | Method | Path | +| --- | --- | --- | +| [List Environment Templates in a Project](/api-reference/core/environment-templates/list-environment-templates-in-a-project) | `GET` | `/core/v1/projects/{project_id}/environment-templates` | +| [Retrieve an Environment Template in a Project](/api-reference/core/environment-templates/retrieve-an-environment-template-in-a-project) | `GET` | `/core/v1/projects/{project_id}/environment-templates/{environment_template_id}` | +| [Delete an Environment Template in a Project](/api-reference/core/environment-templates/delete-an-environment-template-in-a-project) | `DELETE` | `/core/v1/projects/{project_id}/environment-templates/{environment_template_id}` | diff --git a/apps/docs/content/docs/api-reference/core/environment-templates/list-environment-templates-in-a-project.mdx b/apps/docs/content/docs/api-reference/core/environment-templates/list-environment-templates-in-a-project.mdx new file mode 100644 index 000000000..763fc5393 --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/environment-templates/list-environment-templates-in-a-project.mdx @@ -0,0 +1,21 @@ +--- +title: List Environment Templates in a Project +description: Core key only. +full: true +_openapi: + method: GET + route: /core/v1/projects/{project_id}/environment-templates + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Core key only. Reuses the public resource projection and operation rules; the Project ID + selects the target space and does not authenticate. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Reuses the public resource projection and operation rules; the Project ID selects the target space and does not authenticate. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/environment-templates/meta.json b/apps/docs/content/docs/api-reference/core/environment-templates/meta.json new file mode 100644 index 000000000..4543fc6be --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/environment-templates/meta.json @@ -0,0 +1,8 @@ +{ + "title": "Environment Templates", + "pages": [ + "list-environment-templates-in-a-project", + "retrieve-an-environment-template-in-a-project", + "delete-an-environment-template-in-a-project" + ] +} diff --git a/apps/docs/content/docs/api-reference/core/environment-templates/retrieve-an-environment-template-in-a-project.mdx b/apps/docs/content/docs/api-reference/core/environment-templates/retrieve-an-environment-template-in-a-project.mdx new file mode 100644 index 000000000..021e0fc92 --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/environment-templates/retrieve-an-environment-template-in-a-project.mdx @@ -0,0 +1,21 @@ +--- +title: Retrieve an Environment Template in a Project +description: Core key only. +full: true +_openapi: + method: GET + route: /core/v1/projects/{project_id}/environment-templates/{environment_template_id} + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Core key only. Reuses the public resource projection and operation rules; the Project ID + selects the target space and does not authenticate. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Reuses the public resource projection and operation rules; the Project ID selects the target space and does not authenticate. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/execution-configuration.mdx b/apps/docs/content/docs/api-reference/core/execution-configuration.mdx deleted file mode 100644 index 207d504b0..000000000 --- a/apps/docs/content/docs/api-reference/core/execution-configuration.mdx +++ /dev/null @@ -1,27 +0,0 @@ ---- -title: Execution configuration -description: >- - Execution configuration. Core administration API: Core key held by Web’s - server or an operator script. Generated local management contract. This is not - part of the public OpenAI API. -full: true -_openapi: - method: GET - route: /core/v1/projects/{project_id}/sessions/{session_id}/execution-configuration - toc: [] - structuredData: - headings: [] - contents: - - content: >- - Core key only; the Project ID selects the target space and does not - authenticate. Returns the committed model, harness and safe provider - selection with recorded sources. This read never decrypts credentials, - resolves current defaults or probes execution health. Deployment - defaults frozen after they moved into Core show their safe view; older - deployment selections remain redacted. Historical provenance and - missing provider projections are explicitly unknown/unavailable. ---- - -{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} - - \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/execution-configuration/index.mdx b/apps/docs/content/docs/api-reference/core/execution-configuration/index.mdx new file mode 100644 index 000000000..3c7a41f7c --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/execution-configuration/index.mdx @@ -0,0 +1,10 @@ +--- +title: "Execution configuration" +description: "Execution configuration. Core administration API: Core key held by Web’s server or an operator script." +--- + +Generated local management contract. This is not part of the public OpenAI API. + +| Operation | Method | Path | +| --- | --- | --- | +| [Retrieve a Session's frozen execution configuration in a Project](/api-reference/core/execution-configuration/retrieve-a-session-s-frozen-execution-configuration-in-a-project) | `GET` | `/core/v1/projects/{project_id}/sessions/{session_id}/execution-configuration` | diff --git a/apps/docs/content/docs/api-reference/core/execution-configuration/meta.json b/apps/docs/content/docs/api-reference/core/execution-configuration/meta.json new file mode 100644 index 000000000..3c004dc05 --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/execution-configuration/meta.json @@ -0,0 +1,6 @@ +{ + "title": "Execution configuration", + "pages": [ + "retrieve-a-session-s-frozen-execution-configuration-in-a-project" + ] +} diff --git a/apps/docs/content/docs/api-reference/core/execution-configuration/retrieve-a-session-s-frozen-execution-configuration-in-a-project.mdx b/apps/docs/content/docs/api-reference/core/execution-configuration/retrieve-a-session-s-frozen-execution-configuration-in-a-project.mdx new file mode 100644 index 000000000..22a327d5d --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/execution-configuration/retrieve-a-session-s-frozen-execution-configuration-in-a-project.mdx @@ -0,0 +1,27 @@ +--- +title: Retrieve a Session's frozen execution configuration in a Project +description: Core key only; the Project ID selects the target space and does not authenticate. +full: true +_openapi: + method: GET + route: /core/v1/projects/{project_id}/sessions/{session_id}/execution-configuration + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Core key only; the Project ID selects the target space and does not authenticate. Returns + the committed model, harness and safe provider selection with recorded sources. This read + never decrypts credentials, resolves current defaults or probes execution health. + Deployment defaults frozen after they moved into Core show their safe view; older + deployment selections remain redacted. Historical provenance and missing provider + projections are explicitly unknown/unavailable. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Returns the committed model, harness and safe provider selection with recorded sources. This read never decrypts credentials, resolves current defaults or probes execution health. Deployment defaults frozen after they moved into Core show their safe view; older deployment selections remain redacted. + +Historical provenance and missing provider projections are explicitly unknown/unavailable. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/executor-credentials.mdx b/apps/docs/content/docs/api-reference/core/executor-credentials.mdx deleted file mode 100644 index 2ef8db657..000000000 --- a/apps/docs/content/docs/api-reference/core/executor-credentials.mdx +++ /dev/null @@ -1,42 +0,0 @@ ---- -title: Executor Credentials -description: >- - Executor Credentials. Core administration API: Core key held by Web’s server - or an operator script. Generated local management contract. This is not part - of the public OpenAI API. -full: true -_openapi: - toc: [] - structuredData: - headings: [] - contents: - - content: >- - Core key only. Returns metadata of the credentials restricted to this - Environment, oldest first; secrets are never listed. Connection - combines current credential authority and an open matching gateway - peer; timestamps are historical observations, not readiness. Without a - gateway it is never connected. The Environment must be a self_hosted - Environment of the Project whose Session exists; otherwise 404. - - content: >- - Core key only. Returns a connect-only secret once, restricted to - daemon enrollment and connection for this Environment, with the - Project's principal as its execution principal. Repeating an issuance - key_id returns 409 executor_credential_exists; after an uncertain - response, list the credentials and rotate that key_id explicitly. - Rotation keeps the key's Environment, invalidates the old secret and - restores a revoked key; rotating an unknown key_id returns 404. In an - archived Project, issuance and rotation return 409 project_archived. - The Environment must be a self_hosted Environment of the Project whose - Session exists; otherwise 404. Each write records an administrator - audit entry without the secret. - - content: >- - Core key only. Revokes one credential restricted to this Environment; - repeated revocation is safe and it also works in an archived Project. - Revocation denies future enrollment and connection but does not stop - executor-owned compute. The Environment must be a self_hosted - Environment of the Project whose Session exists; otherwise 404. ---- - -{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} - - \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/executor-credentials/index.mdx b/apps/docs/content/docs/api-reference/core/executor-credentials/index.mdx new file mode 100644 index 000000000..7e5fe80bd --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/executor-credentials/index.mdx @@ -0,0 +1,12 @@ +--- +title: "Executor Credentials" +description: "Executor Credentials. Core administration API: Core key held by Web’s server or an operator script." +--- + +Generated local management contract. This is not part of the public OpenAI API. + +| Operation | Method | Path | +| --- | --- | --- | +| [List a self_hosted Environment's executor credentials](/api-reference/core/executor-credentials/list-a-self-hosted-environment-s-executor-credentials) | `GET` | `/core/v1/projects/{project_id}/environments/{environment_id}/executor-credentials` | +| [Issue or explicitly rotate a self_hosted Environment executor credential](/api-reference/core/executor-credentials/issue-or-explicitly-rotate-a-self-hosted-environment-executor-credential) | `POST` | `/core/v1/projects/{project_id}/environments/{environment_id}/executor-credentials` | +| [Revoke a self_hosted Environment executor credential](/api-reference/core/executor-credentials/revoke-a-self-hosted-environment-executor-credential) | `DELETE` | `/core/v1/projects/{project_id}/environments/{environment_id}/executor-credentials/{key_id}` | diff --git a/apps/docs/content/docs/api-reference/core/executor-credentials/issue-or-explicitly-rotate-a-self-hosted-environment-executor-credential.mdx b/apps/docs/content/docs/api-reference/core/executor-credentials/issue-or-explicitly-rotate-a-self-hosted-environment-executor-credential.mdx new file mode 100644 index 000000000..d9d2c8848 --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/executor-credentials/issue-or-explicitly-rotate-a-self-hosted-environment-executor-credential.mdx @@ -0,0 +1,37 @@ +--- +title: Issue or explicitly rotate a self_hosted Environment executor credential +description: >- + Core key only. Returns a connect-only secret once, restricted to daemon enrollment and connection + for this Environment, with the Project's principal as its execution principal. +full: true +_openapi: + method: POST + route: /core/v1/projects/{project_id}/environments/{environment_id}/executor-credentials + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Core key only. Returns a connect-only secret once, restricted to daemon enrollment and + connection for this Environment, with the Project's principal as its execution principal. + Repeating an issuance key_id returns 409 executor_credential_exists; after an uncertain + response, list the credentials and rotate that key_id explicitly. Rotation keeps the key's + Environment, invalidates the old secret and restores a revoked key; rotating an unknown + key_id returns 404. In an archived Project, issuance and rotation return 409 + project_archived. The Environment must be a self_hosted Environment of the Project whose + Session exists; otherwise 404. Each write records an administrator audit entry without the + secret. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +
+Full description + +Repeating an issuance key_id returns 409 executor_credential_exists; after an uncertain response, list the credentials and rotate that key_id explicitly. Rotation keeps the key's Environment, invalidates the old secret and restores a revoked key; rotating an unknown key_id returns 404. In an archived Project, issuance and rotation return 409 project_archived. + +The Environment must be a self_hosted Environment of the Project whose Session exists; otherwise 404. Each write records an administrator audit entry without the secret. + +
+ + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/executor-credentials/list-a-self-hosted-environment-s-executor-credentials.mdx b/apps/docs/content/docs/api-reference/core/executor-credentials/list-a-self-hosted-environment-s-executor-credentials.mdx new file mode 100644 index 000000000..7eefad258 --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/executor-credentials/list-a-self-hosted-environment-s-executor-credentials.mdx @@ -0,0 +1,26 @@ +--- +title: List a self_hosted Environment's executor credentials +description: >- + Core key only. Returns metadata of the credentials restricted to this Environment, oldest first; + secrets are never listed. +full: true +_openapi: + method: GET + route: /core/v1/projects/{project_id}/environments/{environment_id}/executor-credentials + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Core key only. Returns metadata of the credentials restricted to this Environment, oldest + first; secrets are never listed. Connection combines current credential authority and an + open matching gateway peer; timestamps are historical observations, not readiness. Without + a gateway it is never connected. The Environment must be a self_hosted Environment of the + Project whose Session exists; otherwise 404. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Connection combines current credential authority and an open matching gateway peer; timestamps are historical observations, not readiness. Without a gateway it is never connected. The Environment must be a self_hosted Environment of the Project whose Session exists; otherwise 404. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/executor-credentials/meta.json b/apps/docs/content/docs/api-reference/core/executor-credentials/meta.json new file mode 100644 index 000000000..252af8712 --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/executor-credentials/meta.json @@ -0,0 +1,8 @@ +{ + "title": "Executor Credentials", + "pages": [ + "list-a-self-hosted-environment-s-executor-credentials", + "issue-or-explicitly-rotate-a-self-hosted-environment-executor-credential", + "revoke-a-self-hosted-environment-executor-credential" + ] +} diff --git a/apps/docs/content/docs/api-reference/core/executor-credentials/revoke-a-self-hosted-environment-executor-credential.mdx b/apps/docs/content/docs/api-reference/core/executor-credentials/revoke-a-self-hosted-environment-executor-credential.mdx new file mode 100644 index 000000000..eaa52e339 --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/executor-credentials/revoke-a-self-hosted-environment-executor-credential.mdx @@ -0,0 +1,25 @@ +--- +title: Revoke a self_hosted Environment executor credential +description: >- + Core key only. Revokes one credential restricted to this Environment; repeated revocation is safe + and it also works in an archived Project. +full: true +_openapi: + method: DELETE + route: /core/v1/projects/{project_id}/environments/{environment_id}/executor-credentials/{key_id} + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Core key only. Revokes one credential restricted to this Environment; repeated revocation + is safe and it also works in an archived Project. Revocation denies future enrollment and + connection but does not stop executor-owned compute. The Environment must be a self_hosted + Environment of the Project whose Session exists; otherwise 404. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Revocation denies future enrollment and connection but does not stop executor-owned compute. The Environment must be a self_hosted Environment of the Project whose Session exists; otherwise 404. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/files.mdx b/apps/docs/content/docs/api-reference/core/files.mdx deleted file mode 100644 index 186f103bb..000000000 --- a/apps/docs/content/docs/api-reference/core/files.mdx +++ /dev/null @@ -1,29 +0,0 @@ ---- -title: Files -description: >- - Files. Core administration API: Core key held by Web’s server or an operator - script. Generated local management contract. This is not part of the public - OpenAI API. -full: true -_openapi: - toc: [] - structuredData: - headings: [] - contents: - - content: >- - Core key only. Reuses the public resource projection and operation - rules; the Project ID selects the target space and does not - authenticate. - - content: >- - Core key only. Reuses the public resource projection and operation - rules; the Project ID selects the target space and does not - authenticate. - - content: >- - Core key only. Reuses the public resource projection and operation - rules; the Project ID selects the target space and does not - authenticate. ---- - -{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} - - \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/files/delete-a-source-file-in-a-project.mdx b/apps/docs/content/docs/api-reference/core/files/delete-a-source-file-in-a-project.mdx new file mode 100644 index 000000000..6b67864ca --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/files/delete-a-source-file-in-a-project.mdx @@ -0,0 +1,21 @@ +--- +title: Delete a source file in a Project +description: Core key only. +full: true +_openapi: + method: DELETE + route: /core/v1/projects/{project_id}/files/{file_id} + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Core key only. Reuses the public resource projection and operation rules; the Project ID + selects the target space and does not authenticate. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Reuses the public resource projection and operation rules; the Project ID selects the target space and does not authenticate. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/files/index.mdx b/apps/docs/content/docs/api-reference/core/files/index.mdx new file mode 100644 index 000000000..ca208a7f5 --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/files/index.mdx @@ -0,0 +1,12 @@ +--- +title: "Files" +description: "Files. Core administration API: Core key held by Web’s server or an operator script." +--- + +Generated local management contract. This is not part of the public OpenAI API. + +| Operation | Method | Path | +| --- | --- | --- | +| [List source files in a Project](/api-reference/core/files/list-source-files-in-a-project) | `GET` | `/core/v1/projects/{project_id}/files` | +| [Retrieve source file metadata in a Project](/api-reference/core/files/retrieve-source-file-metadata-in-a-project) | `GET` | `/core/v1/projects/{project_id}/files/{file_id}` | +| [Delete a source file in a Project](/api-reference/core/files/delete-a-source-file-in-a-project) | `DELETE` | `/core/v1/projects/{project_id}/files/{file_id}` | diff --git a/apps/docs/content/docs/api-reference/core/files/list-source-files-in-a-project.mdx b/apps/docs/content/docs/api-reference/core/files/list-source-files-in-a-project.mdx new file mode 100644 index 000000000..152e5748f --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/files/list-source-files-in-a-project.mdx @@ -0,0 +1,21 @@ +--- +title: List source files in a Project +description: Core key only. +full: true +_openapi: + method: GET + route: /core/v1/projects/{project_id}/files + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Core key only. Reuses the public resource projection and operation rules; the Project ID + selects the target space and does not authenticate. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Reuses the public resource projection and operation rules; the Project ID selects the target space and does not authenticate. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/files/meta.json b/apps/docs/content/docs/api-reference/core/files/meta.json new file mode 100644 index 000000000..9d9b9c8b0 --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/files/meta.json @@ -0,0 +1,8 @@ +{ + "title": "Files", + "pages": [ + "list-source-files-in-a-project", + "retrieve-source-file-metadata-in-a-project", + "delete-a-source-file-in-a-project" + ] +} diff --git a/apps/docs/content/docs/api-reference/core/files/retrieve-source-file-metadata-in-a-project.mdx b/apps/docs/content/docs/api-reference/core/files/retrieve-source-file-metadata-in-a-project.mdx new file mode 100644 index 000000000..1fe8e0957 --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/files/retrieve-source-file-metadata-in-a-project.mdx @@ -0,0 +1,21 @@ +--- +title: Retrieve source file metadata in a Project +description: Core key only. +full: true +_openapi: + method: GET + route: /core/v1/projects/{project_id}/files/{file_id} + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Core key only. Reuses the public resource projection and operation rules; the Project ID + selects the target space and does not authenticate. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Reuses the public resource projection and operation rules; the Project ID selects the target space and does not authenticate. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/index.mdx b/apps/docs/content/docs/api-reference/core/index.mdx index ad2fc6c57..57d0a0c30 100644 --- a/apps/docs/content/docs/api-reference/core/index.mdx +++ b/apps/docs/content/docs/api-reference/core/index.mdx @@ -9,25 +9,25 @@ Generated local management contract. This is not part of the public OpenAI API. Operator scripts use Core’s loopback port. The public entry routes management through Web, which requires its signed-in session and supplies the Core key on the server. -[API namespaces and credentials](/public-api) · [Application reference](/api-reference) · [Administration reference](/api-reference/core) · [Machine reference](/api-reference/machine) +[API namespaces and credentials](/public-api) · [Application reference](/api-reference) · [Administration reference](/api-reference/core) · [Machine reference](/api-reference/machine) · [Error codes](/error-codes) -- [core-administration](/api-reference/core/core-administration) -- [deployment-model-providers](/api-reference/core/deployment-model-providers) -- [administrator-projects](/api-reference/core/administrator-projects) -- [agents](/api-reference/core/agents) -- [environment-templates](/api-reference/core/environment-templates) -- [executor-credentials](/api-reference/core/executor-credentials) -- [native-installation](/api-reference/core/native-installation) -- [files](/api-reference/core/files) -- [write-audit](/api-reference/core/write-audit) -- [sessions](/api-reference/core/sessions) -- [artifacts](/api-reference/core/artifacts) -- [execution-configuration](/api-reference/core/execution-configuration) -- [items](/api-reference/core/items) -- [runtime-history](/api-reference/core/runtime-history) -- [runtime-observations](/api-reference/core/runtime-observations) -- [turns](/api-reference/core/turns) -- [skills](/api-reference/core/skills) -- [vaults](/api-reference/core/vaults) -- [credentials](/api-reference/core/credentials) -- [sandbox-manager](/api-reference/core/sandbox-manager) +- [Core Administration](/api-reference/core/core-administration) · 7 operations +- [Deployment Model Providers](/api-reference/core/deployment-model-providers) · 4 operations +- [Administrator Projects](/api-reference/core/administrator-projects) · 7 operations +- [Agents](/api-reference/core/agents) · 3 operations +- [Environment Templates](/api-reference/core/environment-templates) · 3 operations +- [Executor Credentials](/api-reference/core/executor-credentials) · 3 operations +- [Native Installation](/api-reference/core/native-installation) · 1 operation +- [Files](/api-reference/core/files) · 3 operations +- [Write Audit](/api-reference/core/write-audit) · 2 operations +- [Sessions](/api-reference/core/sessions) · 4 operations +- [Artifacts](/api-reference/core/artifacts) · 4 operations +- [Execution configuration](/api-reference/core/execution-configuration) · 1 operation +- [Items](/api-reference/core/items) · 1 operation +- [Runtime history](/api-reference/core/runtime-history) · 1 operation +- [Runtime observations](/api-reference/core/runtime-observations) · 1 operation +- [Turns](/api-reference/core/turns) · 3 operations +- [Skills](/api-reference/core/skills) · 8 operations +- [Vaults](/api-reference/core/vaults) · 3 operations +- [Credentials](/api-reference/core/credentials) · 3 operations +- [Sandbox Manager](/api-reference/core/sandbox-manager) · 13 operations diff --git a/apps/docs/content/docs/api-reference/core/items/index.mdx b/apps/docs/content/docs/api-reference/core/items/index.mdx new file mode 100644 index 000000000..c9a025ddc --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/items/index.mdx @@ -0,0 +1,10 @@ +--- +title: "Items" +description: "Items. Core administration API: Core key held by Web’s server or an operator script." +--- + +Generated local management contract. This is not part of the public OpenAI API. + +| Operation | Method | Path | +| --- | --- | --- | +| [List persisted execution Items in a Project](/api-reference/core/items/list-persisted-execution-items-in-a-project) | `GET` | `/core/v1/projects/{project_id}/sessions/{session_id}/items` | diff --git a/apps/docs/content/docs/api-reference/core/items.mdx b/apps/docs/content/docs/api-reference/core/items/list-persisted-execution-items-in-a-project.mdx similarity index 60% rename from apps/docs/content/docs/api-reference/core/items.mdx rename to apps/docs/content/docs/api-reference/core/items/list-persisted-execution-items-in-a-project.mdx index 7589bc49b..ffd3957fd 100644 --- a/apps/docs/content/docs/api-reference/core/items.mdx +++ b/apps/docs/content/docs/api-reference/core/items/list-persisted-execution-items-in-a-project.mdx @@ -1,9 +1,6 @@ --- -title: Items -description: >- - Items. Core administration API: Core key held by Web’s server or an operator - script. Generated local management contract. This is not part of the public - OpenAI API. +title: List persisted execution Items in a Project +description: Core key only. full: true _openapi: method: GET @@ -13,11 +10,12 @@ _openapi: headings: [] contents: - content: >- - Core key only. Reuses the public resource projection and operation - rules; the Project ID selects the target space and does not - authenticate. + Core key only. Reuses the public resource projection and operation rules; the Project ID + selects the target space and does not authenticate. --- {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} - \ No newline at end of file +Reuses the public resource projection and operation rules; the Project ID selects the target space and does not authenticate. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/items/meta.json b/apps/docs/content/docs/api-reference/core/items/meta.json new file mode 100644 index 000000000..28b2e109e --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/items/meta.json @@ -0,0 +1,6 @@ +{ + "title": "Items", + "pages": [ + "list-persisted-execution-items-in-a-project" + ] +} diff --git a/apps/docs/content/docs/api-reference/core/meta.json b/apps/docs/content/docs/api-reference/core/meta.json index fb07e650d..c0ea65d04 100644 --- a/apps/docs/content/docs/api-reference/core/meta.json +++ b/apps/docs/content/docs/api-reference/core/meta.json @@ -1,7 +1,6 @@ { "title": "Core administration API", "pages": [ - "index", "core-administration", "deployment-model-providers", "administrator-projects", diff --git a/apps/docs/content/docs/api-reference/core/native-installation.mdx b/apps/docs/content/docs/api-reference/core/native-installation/get-a-self-hosted-session-s-installation-commands.mdx similarity index 54% rename from apps/docs/content/docs/api-reference/core/native-installation.mdx rename to apps/docs/content/docs/api-reference/core/native-installation/get-a-self-hosted-session-s-installation-commands.mdx index a03fdfca8..937d1153a 100644 --- a/apps/docs/content/docs/api-reference/core/native-installation.mdx +++ b/apps/docs/content/docs/api-reference/core/native-installation/get-a-self-hosted-session-s-installation-commands.mdx @@ -1,9 +1,8 @@ --- -title: Native Installation +title: Get a self_hosted Session's installation commands description: >- - Native Installation. Core administration API: Core key held by Web’s server or - an operator script. Generated local management contract. This is not part of - the public OpenAI API. + Core key only. The commands contain a 30-minute installation authorization, never an executor + secret. full: true _openapi: method: GET @@ -13,11 +12,13 @@ _openapi: headings: [] contents: - content: >- - Core key only. The commands contain a 30-minute installation - authorization, never an executor secret. Web displays these same - commands provided in public Session creation and detail responses. + Core key only. The commands contain a 30-minute installation authorization, never an + executor secret. Web displays these same commands provided in public Session creation and + detail responses. --- {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} - \ No newline at end of file +Web displays these same commands provided in public Session creation and detail responses. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/native-installation/index.mdx b/apps/docs/content/docs/api-reference/core/native-installation/index.mdx new file mode 100644 index 000000000..446cd767e --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/native-installation/index.mdx @@ -0,0 +1,10 @@ +--- +title: "Native Installation" +description: "Native Installation. Core administration API: Core key held by Web’s server or an operator script." +--- + +Generated local management contract. This is not part of the public OpenAI API. + +| Operation | Method | Path | +| --- | --- | --- | +| [Get a self_hosted Session's installation commands](/api-reference/core/native-installation/get-a-self-hosted-session-s-installation-commands) | `GET` | `/core/v1/projects/{project_id}/environments/{environment_id}/installation` | diff --git a/apps/docs/content/docs/api-reference/core/native-installation/meta.json b/apps/docs/content/docs/api-reference/core/native-installation/meta.json new file mode 100644 index 000000000..2b230b174 --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/native-installation/meta.json @@ -0,0 +1,6 @@ +{ + "title": "Native Installation", + "pages": [ + "get-a-self-hosted-session-s-installation-commands" + ] +} diff --git a/apps/docs/content/docs/api-reference/core/runtime-history.mdx b/apps/docs/content/docs/api-reference/core/runtime-history.mdx deleted file mode 100644 index 5b7e2da6f..000000000 --- a/apps/docs/content/docs/api-reference/core/runtime-history.mdx +++ /dev/null @@ -1,26 +0,0 @@ ---- -title: Runtime history -description: >- - Runtime history. Core administration API: Core key held by Web’s server or an - operator script. Generated local management contract. This is not part of the - public OpenAI API. -full: true -_openapi: - method: GET - route: /core/v1/projects/{project_id}/sessions/{session_id}/runtime-history - toc: [] - structuredData: - headings: [] - contents: - - content: >- - Core key only; the Project ID selects the target space and does not - authenticate. Returns stored Runtime observations for one Session. End - is exclusive; the server selects a bounded resolution. Responses - contain at most 1,000 series, 10,000 points per coverage/series array, - and 100,000 total coverage plus series points. It never reads or - changes live compute. ---- - -{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} - - \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/runtime-history/index.mdx b/apps/docs/content/docs/api-reference/core/runtime-history/index.mdx new file mode 100644 index 000000000..7f38d3a59 --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/runtime-history/index.mdx @@ -0,0 +1,10 @@ +--- +title: "Runtime history" +description: "Runtime history. Core administration API: Core key held by Web’s server or an operator script." +--- + +Generated local management contract. This is not part of the public OpenAI API. + +| Operation | Method | Path | +| --- | --- | --- | +| [Retrieve Session Runtime history in a Project](/api-reference/core/runtime-history/retrieve-session-runtime-history-in-a-project) | `GET` | `/core/v1/projects/{project_id}/sessions/{session_id}/runtime-history` | diff --git a/apps/docs/content/docs/api-reference/core/runtime-history/meta.json b/apps/docs/content/docs/api-reference/core/runtime-history/meta.json new file mode 100644 index 000000000..e2be69235 --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/runtime-history/meta.json @@ -0,0 +1,6 @@ +{ + "title": "Runtime history", + "pages": [ + "retrieve-session-runtime-history-in-a-project" + ] +} diff --git a/apps/docs/content/docs/api-reference/core/runtime-history/retrieve-session-runtime-history-in-a-project.mdx b/apps/docs/content/docs/api-reference/core/runtime-history/retrieve-session-runtime-history-in-a-project.mdx new file mode 100644 index 000000000..5f1284ddb --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/runtime-history/retrieve-session-runtime-history-in-a-project.mdx @@ -0,0 +1,26 @@ +--- +title: Retrieve Session Runtime history in a Project +description: Core key only; the Project ID selects the target space and does not authenticate. +full: true +_openapi: + method: GET + route: /core/v1/projects/{project_id}/sessions/{session_id}/runtime-history + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Core key only; the Project ID selects the target space and does not authenticate. Returns + stored Runtime observations for one Session. End is exclusive; the server selects a + bounded resolution. Responses contain at most 1,000 series, 10,000 points per + coverage/series array, and 100,000 total coverage plus series points. It never reads or + changes live compute. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Returns stored Runtime observations for one Session. End is exclusive; the server selects a bounded resolution. Responses contain at most 1,000 series, 10,000 points per coverage/series array, and 100,000 total coverage plus series points. + +It never reads or changes live compute. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/runtime-observations/index.mdx b/apps/docs/content/docs/api-reference/core/runtime-observations/index.mdx new file mode 100644 index 000000000..0595320d7 --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/runtime-observations/index.mdx @@ -0,0 +1,10 @@ +--- +title: "Runtime observations" +description: "Runtime observations. Core administration API: Core key held by Web’s server or an operator script." +--- + +Generated local management contract. This is not part of the public OpenAI API. + +| Operation | Method | Path | +| --- | --- | --- | +| [Retrieve a Session Runtime observation in a Project](/api-reference/core/runtime-observations/retrieve-a-session-runtime-observation-in-a-project) | `GET` | `/core/v1/projects/{project_id}/sessions/{session_id}/runtime-observation` | diff --git a/apps/docs/content/docs/api-reference/core/runtime-observations/meta.json b/apps/docs/content/docs/api-reference/core/runtime-observations/meta.json new file mode 100644 index 000000000..583d7ca40 --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/runtime-observations/meta.json @@ -0,0 +1,6 @@ +{ + "title": "Runtime observations", + "pages": [ + "retrieve-a-session-runtime-observation-in-a-project" + ] +} diff --git a/apps/docs/content/docs/api-reference/core/runtime-observations.mdx b/apps/docs/content/docs/api-reference/core/runtime-observations/retrieve-a-session-runtime-observation-in-a-project.mdx similarity index 52% rename from apps/docs/content/docs/api-reference/core/runtime-observations.mdx rename to apps/docs/content/docs/api-reference/core/runtime-observations/retrieve-a-session-runtime-observation-in-a-project.mdx index b9a2917ae..8db562e17 100644 --- a/apps/docs/content/docs/api-reference/core/runtime-observations.mdx +++ b/apps/docs/content/docs/api-reference/core/runtime-observations/retrieve-a-session-runtime-observation-in-a-project.mdx @@ -1,9 +1,6 @@ --- -title: Runtime observations -description: >- - Runtime observations. Core administration API: Core key held by Web’s server - or an operator script. Generated local management contract. This is not part - of the public OpenAI API. +title: Retrieve a Session Runtime observation in a Project +description: Core key only; the Project ID selects the target space and does not authenticate. full: true _openapi: method: GET @@ -13,11 +10,13 @@ _openapi: headings: [] contents: - content: >- - Core key only; the Project ID selects the target space and does not - authenticate. Returns one read-only current Runtime observation. It - never provisions, renews, restarts, pauses or stops compute. + Core key only; the Project ID selects the target space and does not authenticate. Returns + one read-only current Runtime observation. It never provisions, renews, restarts, pauses + or stops compute. --- {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} - \ No newline at end of file +Returns one read-only current Runtime observation. It never provisions, renews, restarts, pauses or stops compute. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/sandbox-manager.mdx b/apps/docs/content/docs/api-reference/core/sandbox-manager.mdx deleted file mode 100644 index de80e6d5a..000000000 --- a/apps/docs/content/docs/api-reference/core/sandbox-manager.mdx +++ /dev/null @@ -1,79 +0,0 @@ ---- -title: Sandbox Manager -description: >- - Sandbox Manager. Core administration API: Core key held by Web’s server or an - operator script. Generated local management contract. This is not part of the - public OpenAI API. -full: true -_openapi: - toc: [] - structuredData: - headings: [] - contents: - - content: >- - Core key only. Does not grant project resource access. Responses - contain only explicit safe fields. E2B template_build values are those - Core read when the selection was saved; this read does not call E2B. - - content: >- - Selects a provider, enforced resource limits and pinned Runtime - release. Core derives the deployment's core_url from the installation - public URL and rejects a core_url member with 400. E2B returns 409 - sandbox_configuration_error while the public URL is loopback. E2B - credentials are write-only. E2B may omit resources to adopt the - validated template build's CPU and memory, returned in - specification.resources. Requires explicit expected_generation, - including zero at first setup. Stale retries reject before provider - validation. An identical selection at the current generation is a - no-op; differing selections and file-managed deployments reject. This - does not create compute or execute work. - - content: >- - Requires the observed generation, the same backend type and no active - reset. E2B same-team changes apply online: allocations retain - immutable generation and current credentials; omitted api_key - preserves it, explicit submission including the same key verifies and - advances generation. Other teams require explicit reset. Node - providers retain the zero-resource guard and retire old nodes/tokens - on change. Core rejects core_url input. Never automatically replay an - uncertain write; rollout.state is the authoritative preparation - polling signal. - - content: >- - Archives hosted Sessions and waits for confirmed provider cleanup, - preserving history and Files/Artifacts. Auto waits for started or - waiting Turns and file writes until the durable deadline; force - cancels them. The same clear is idempotent; force escalates auto. - Requires the current generation. Self-hosted Sessions are unchanged. - - content: >- - Restores admission but never restores Sessions already archived. With - no reset running this is an idempotent read, provided the generation - still matches. - - content: >- - Core key only. Uses a transient E2B credential and endpoint through - the pinned SDK helper; returns safe template metadata. Does not save - the credential or allocate compute. - - content: >- - Core key only. Reads one template through the pinned SDK helper with a - transient E2B credential. Returns ready builds only, without - allocating compute. - - content: >- - Core key only. Does not grant project resource access. Responses - contain only explicit safe fields. - - content: >- - Core key only. Does not grant project resource access. Responses - contain only explicit safe fields. - - content: >- - Core key only. Complete UTC buckets. Missing host measurements and - offline history are null; reads never sample or backfill. - - content: >- - Core key only. Does not grant project resource access. Responses - contain only explicit safe fields. - - content: >- - Core key only. Does not grant project resource access. Responses - contain only explicit safe fields. - - content: >- - Core key only. Does not grant project resource access. Responses - contain only explicit safe fields. ---- - -{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} - - \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/sandbox-manager/cancel-a-sandbox-deployment-reset.mdx b/apps/docs/content/docs/api-reference/core/sandbox-manager/cancel-a-sandbox-deployment-reset.mdx new file mode 100644 index 000000000..0e6bc14ce --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/sandbox-manager/cancel-a-sandbox-deployment-reset.mdx @@ -0,0 +1,21 @@ +--- +title: Cancel a sandbox deployment reset +description: Restores admission but never restores Sessions already archived. +full: true +_openapi: + method: DELETE + route: /core/v1/sandbox/deployment/reset + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Restores admission but never restores Sessions already archived. With no reset running + this is an idempotent read, provided the generation still matches. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +With no reset running this is an idempotent read, provided the generation still matches. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/sandbox-manager/change-the-sandbox-deployment-configuration.mdx b/apps/docs/content/docs/api-reference/core/sandbox-manager/change-the-sandbox-deployment-configuration.mdx new file mode 100644 index 000000000..bc7fc2720 --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/sandbox-manager/change-the-sandbox-deployment-configuration.mdx @@ -0,0 +1,33 @@ +--- +title: Change the sandbox deployment configuration +description: Requires the observed generation, the same backend type and no active reset. +full: true +_openapi: + method: PUT + route: /core/v1/sandbox/deployment + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Requires the observed generation, the same backend type and no active reset. E2B same-team + changes apply online: allocations retain immutable generation and current credentials; + omitted api_key preserves it, explicit submission including the same key verifies and + advances generation. Other teams require explicit reset. Node providers retain the + zero-resource guard and retire old nodes/tokens on change. Core rejects core_url input. + Never automatically replay an uncertain write; rollout.state is the authoritative + preparation polling signal. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +
+Full description + +E2B same-team changes apply online: allocations retain immutable generation and current credentials; omitted api_key preserves it, explicit submission including the same key verifies and advances generation. Other teams require explicit reset. Node providers retain the zero-resource guard and retire old nodes/tokens on change. + +Core rejects core_url input. Never automatically replay an uncertain write; rollout.state is the authoritative preparation polling signal. + +
+ + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/sandbox-manager/create-a-ten-minute-one-use-node-enrollment-token.mdx b/apps/docs/content/docs/api-reference/core/sandbox-manager/create-a-ten-minute-one-use-node-enrollment-token.mdx new file mode 100644 index 000000000..f0a665d12 --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/sandbox-manager/create-a-ten-minute-one-use-node-enrollment-token.mdx @@ -0,0 +1,21 @@ +--- +title: Create a ten-minute one-use node enrollment token +description: Core key only. Does not grant project resource access. +full: true +_openapi: + method: POST + route: /core/v1/sandbox/enrollment-tokens + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Core key only. Does not grant project resource access. Responses contain only explicit + safe fields. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Responses contain only explicit safe fields. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/sandbox-manager/index.mdx b/apps/docs/content/docs/api-reference/core/sandbox-manager/index.mdx new file mode 100644 index 000000000..28a2f4f6c --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/sandbox-manager/index.mdx @@ -0,0 +1,22 @@ +--- +title: "Sandbox Manager" +description: "Sandbox Manager. Core administration API: Core key held by Web’s server or an operator script." +--- + +Generated local management contract. This is not part of the public OpenAI API. + +| Operation | Method | Path | +| --- | --- | --- | +| [Retrieve sandbox deployment](/api-reference/core/sandbox-manager/retrieve-sandbox-deployment) | `GET` | `/core/v1/sandbox/deployment` | +| [Initialize the deployment sandbox provider](/api-reference/core/sandbox-manager/initialize-the-deployment-sandbox-provider) | `POST` | `/core/v1/sandbox/deployment` | +| [Change the sandbox deployment configuration](/api-reference/core/sandbox-manager/change-the-sandbox-deployment-configuration) | `PUT` | `/core/v1/sandbox/deployment` | +| [Start or escalate a durable sandbox deployment reset](/api-reference/core/sandbox-manager/start-or-escalate-a-durable-sandbox-deployment-reset) | `POST` | `/core/v1/sandbox/deployment/reset` | +| [Cancel a sandbox deployment reset](/api-reference/core/sandbox-manager/cancel-a-sandbox-deployment-reset) | `DELETE` | `/core/v1/sandbox/deployment/reset` | +| [List templates visible to an E2B credential](/api-reference/core/sandbox-manager/list-templates-visible-to-an-e2b-credential) | `POST` | `/core/v1/sandbox/e2b/templates` | +| [List ready builds for an E2B template](/api-reference/core/sandbox-manager/list-ready-builds-for-an-e2b-template) | `POST` | `/core/v1/sandbox/e2b/templates/{template_id}/builds` | +| [Create a ten-minute one-use node enrollment token](/api-reference/core/sandbox-manager/create-a-ten-minute-one-use-node-enrollment-token) | `POST` | `/core/v1/sandbox/enrollment-tokens` | +| [List deployment sandbox nodes](/api-reference/core/sandbox-manager/list-deployment-sandbox-nodes) | `GET` | `/core/v1/sandbox/nodes` | +| [Retrieve sandbox node and host history](/api-reference/core/sandbox-manager/retrieve-sandbox-node-and-host-history) | `GET` | `/core/v1/sandbox/nodes/{node_id}` | +| [Update sandbox node name and capacity](/api-reference/core/sandbox-manager/update-sandbox-node-name-and-capacity) | `PATCH` | `/core/v1/sandbox/nodes/{node_id}` | +| [Remove a sandbox node with no retained resources](/api-reference/core/sandbox-manager/remove-a-sandbox-node-with-no-retained-resources) | `DELETE` | `/core/v1/sandbox/nodes/{node_id}` | +| [List retained allocations on a sandbox node](/api-reference/core/sandbox-manager/list-retained-allocations-on-a-sandbox-node) | `GET` | `/core/v1/sandbox/nodes/{node_id}/allocations` | diff --git a/apps/docs/content/docs/api-reference/core/sandbox-manager/initialize-the-deployment-sandbox-provider.mdx b/apps/docs/content/docs/api-reference/core/sandbox-manager/initialize-the-deployment-sandbox-provider.mdx new file mode 100644 index 000000000..1c81a814c --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/sandbox-manager/initialize-the-deployment-sandbox-provider.mdx @@ -0,0 +1,37 @@ +--- +title: Initialize the deployment sandbox provider +description: Selects a provider, enforced resource limits and pinned Runtime release. +full: true +_openapi: + method: POST + route: /core/v1/sandbox/deployment + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Selects a provider, enforced resource limits and pinned Runtime release. Core derives the + deployment's core_url from the installation public URL and rejects a core_url member with + 400. E2B returns 409 sandbox_configuration_error while the public URL is loopback. E2B + credentials are write-only. E2B may omit resources to adopt the validated template build's + CPU and memory, returned in specification.resources. Requires explicit + expected_generation, including zero at first setup. Stale retries reject before provider + validation. An identical selection at the current generation is a no-op; differing + selections and file-managed deployments reject. This does not create compute or execute + work. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +
+Full description + +Core derives the deployment's core_url from the installation public URL and rejects a core_url member with 400. E2B returns 409 sandbox_configuration_error while the public URL is loopback. E2B credentials are write-only. + +E2B may omit resources to adopt the validated template build's CPU and memory, returned in specification.resources. Requires explicit expected_generation, including zero at first setup. Stale retries reject before provider validation. + +An identical selection at the current generation is a no-op; differing selections and file-managed deployments reject. This does not create compute or execute work. + +
+ + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/sandbox-manager/list-deployment-sandbox-nodes.mdx b/apps/docs/content/docs/api-reference/core/sandbox-manager/list-deployment-sandbox-nodes.mdx new file mode 100644 index 000000000..ac316bdfb --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/sandbox-manager/list-deployment-sandbox-nodes.mdx @@ -0,0 +1,21 @@ +--- +title: List deployment sandbox nodes +description: Core key only. Does not grant project resource access. +full: true +_openapi: + method: GET + route: /core/v1/sandbox/nodes + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Core key only. Does not grant project resource access. Responses contain only explicit + safe fields. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Responses contain only explicit safe fields. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/sandbox-manager/list-ready-builds-for-an-e2b-template.mdx b/apps/docs/content/docs/api-reference/core/sandbox-manager/list-ready-builds-for-an-e2b-template.mdx new file mode 100644 index 000000000..6662c36c4 --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/sandbox-manager/list-ready-builds-for-an-e2b-template.mdx @@ -0,0 +1,21 @@ +--- +title: List ready builds for an E2B template +description: Core key only. Reads one template through the pinned SDK helper with a transient E2B credential. +full: true +_openapi: + method: POST + route: /core/v1/sandbox/e2b/templates/{template_id}/builds + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Core key only. Reads one template through the pinned SDK helper with a transient E2B + credential. Returns ready builds only, without allocating compute. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Returns ready builds only, without allocating compute. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/sandbox-manager/list-retained-allocations-on-a-sandbox-node.mdx b/apps/docs/content/docs/api-reference/core/sandbox-manager/list-retained-allocations-on-a-sandbox-node.mdx new file mode 100644 index 000000000..9c24fc3be --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/sandbox-manager/list-retained-allocations-on-a-sandbox-node.mdx @@ -0,0 +1,21 @@ +--- +title: List retained allocations on a sandbox node +description: Core key only. Does not grant project resource access. +full: true +_openapi: + method: GET + route: /core/v1/sandbox/nodes/{node_id}/allocations + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Core key only. Does not grant project resource access. Responses contain only explicit + safe fields. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Responses contain only explicit safe fields. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/sandbox-manager/list-templates-visible-to-an-e2b-credential.mdx b/apps/docs/content/docs/api-reference/core/sandbox-manager/list-templates-visible-to-an-e2b-credential.mdx new file mode 100644 index 000000000..13a7e8134 --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/sandbox-manager/list-templates-visible-to-an-e2b-credential.mdx @@ -0,0 +1,23 @@ +--- +title: List templates visible to an E2B credential +description: >- + Core key only. Uses a transient E2B credential and endpoint through the pinned SDK helper; returns + safe template metadata. +full: true +_openapi: + method: POST + route: /core/v1/sandbox/e2b/templates + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Core key only. Uses a transient E2B credential and endpoint through the pinned SDK helper; + returns safe template metadata. Does not save the credential or allocate compute. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Does not save the credential or allocate compute. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/sandbox-manager/meta.json b/apps/docs/content/docs/api-reference/core/sandbox-manager/meta.json new file mode 100644 index 000000000..31404c82e --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/sandbox-manager/meta.json @@ -0,0 +1,18 @@ +{ + "title": "Sandbox Manager", + "pages": [ + "retrieve-sandbox-deployment", + "initialize-the-deployment-sandbox-provider", + "change-the-sandbox-deployment-configuration", + "start-or-escalate-a-durable-sandbox-deployment-reset", + "cancel-a-sandbox-deployment-reset", + "list-templates-visible-to-an-e2b-credential", + "list-ready-builds-for-an-e2b-template", + "create-a-ten-minute-one-use-node-enrollment-token", + "list-deployment-sandbox-nodes", + "retrieve-sandbox-node-and-host-history", + "update-sandbox-node-name-and-capacity", + "remove-a-sandbox-node-with-no-retained-resources", + "list-retained-allocations-on-a-sandbox-node" + ] +} diff --git a/apps/docs/content/docs/api-reference/core/sandbox-manager/remove-a-sandbox-node-with-no-retained-resources.mdx b/apps/docs/content/docs/api-reference/core/sandbox-manager/remove-a-sandbox-node-with-no-retained-resources.mdx new file mode 100644 index 000000000..1a9670037 --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/sandbox-manager/remove-a-sandbox-node-with-no-retained-resources.mdx @@ -0,0 +1,21 @@ +--- +title: Remove a sandbox node with no retained resources +description: Core key only. Does not grant project resource access. +full: true +_openapi: + method: DELETE + route: /core/v1/sandbox/nodes/{node_id} + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Core key only. Does not grant project resource access. Responses contain only explicit + safe fields. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Responses contain only explicit safe fields. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/sandbox-manager/retrieve-sandbox-deployment.mdx b/apps/docs/content/docs/api-reference/core/sandbox-manager/retrieve-sandbox-deployment.mdx new file mode 100644 index 000000000..a01e492eb --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/sandbox-manager/retrieve-sandbox-deployment.mdx @@ -0,0 +1,22 @@ +--- +title: Retrieve sandbox deployment +description: Core key only. Does not grant project resource access. +full: true +_openapi: + method: GET + route: /core/v1/sandbox/deployment + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Core key only. Does not grant project resource access. Responses contain only explicit + safe fields. E2B template_build values are those Core read when the selection was saved; + this read does not call E2B. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Responses contain only explicit safe fields. E2B template_build values are those Core read when the selection was saved; this read does not call E2B. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/sandbox-manager/retrieve-sandbox-node-and-host-history.mdx b/apps/docs/content/docs/api-reference/core/sandbox-manager/retrieve-sandbox-node-and-host-history.mdx new file mode 100644 index 000000000..0f7dcdc4e --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/sandbox-manager/retrieve-sandbox-node-and-host-history.mdx @@ -0,0 +1,21 @@ +--- +title: Retrieve sandbox node and host history +description: Core key only. Complete UTC buckets. +full: true +_openapi: + method: GET + route: /core/v1/sandbox/nodes/{node_id} + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Core key only. Complete UTC buckets. Missing host measurements and offline history are + null; reads never sample or backfill. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Missing host measurements and offline history are null; reads never sample or backfill. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/sandbox-manager/start-or-escalate-a-durable-sandbox-deployment-reset.mdx b/apps/docs/content/docs/api-reference/core/sandbox-manager/start-or-escalate-a-durable-sandbox-deployment-reset.mdx new file mode 100644 index 000000000..684237cf6 --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/sandbox-manager/start-or-escalate-a-durable-sandbox-deployment-reset.mdx @@ -0,0 +1,27 @@ +--- +title: Start or escalate a durable sandbox deployment reset +description: >- + Archives hosted Sessions and waits for confirmed provider cleanup, preserving history and + Files/Artifacts. +full: true +_openapi: + method: POST + route: /core/v1/sandbox/deployment/reset + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Archives hosted Sessions and waits for confirmed provider cleanup, preserving history and + Files/Artifacts. Auto waits for started or waiting Turns and file writes until the durable + deadline; force cancels them. The same clear is idempotent; force escalates auto. Requires + the current generation. Self-hosted Sessions are unchanged. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Auto waits for started or waiting Turns and file writes until the durable deadline; force cancels them. The same clear is idempotent; force escalates auto. Requires the current generation. + +Self-hosted Sessions are unchanged. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/sandbox-manager/update-sandbox-node-name-and-capacity.mdx b/apps/docs/content/docs/api-reference/core/sandbox-manager/update-sandbox-node-name-and-capacity.mdx new file mode 100644 index 000000000..750408292 --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/sandbox-manager/update-sandbox-node-name-and-capacity.mdx @@ -0,0 +1,21 @@ +--- +title: Update sandbox node name and capacity +description: Core key only. Does not grant project resource access. +full: true +_openapi: + method: PATCH + route: /core/v1/sandbox/nodes/{node_id} + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Core key only. Does not grant project resource access. Responses contain only explicit + safe fields. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Responses contain only explicit safe fields. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/sessions.mdx b/apps/docs/content/docs/api-reference/core/sessions.mdx deleted file mode 100644 index a266de5f0..000000000 --- a/apps/docs/content/docs/api-reference/core/sessions.mdx +++ /dev/null @@ -1,32 +0,0 @@ ---- -title: Sessions -description: >- - Sessions. Core administration API: Core key held by Web’s server or an - operator script. Generated local management contract. This is not part of the - public OpenAI API. -full: true -_openapi: - toc: [] - structuredData: - headings: [] - contents: - - content: >- - Core key only. Reuses the public resource projection and operation - rules; the Project ID selects the target space and does not - authenticate. - - content: >- - Core key only. Reuses the public resource projection and operation - rules; the Project ID selects the target space and does not - authenticate. - - content: >- - Core key only. Reuses the public resource projection and operation - rules; the Project ID selects the target space and does not - authenticate. - - content: >- - Core key only. Safe failure categories from one committed snapshot; no - native text or historical inference. ---- - -{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} - - \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/sessions/delete-an-execution-session-in-a-project.mdx b/apps/docs/content/docs/api-reference/core/sessions/delete-an-execution-session-in-a-project.mdx new file mode 100644 index 000000000..ffbe14363 --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/sessions/delete-an-execution-session-in-a-project.mdx @@ -0,0 +1,21 @@ +--- +title: Delete an execution Session in a Project +description: Core key only. +full: true +_openapi: + method: DELETE + route: /core/v1/projects/{project_id}/sessions/{session_id} + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Core key only. Reuses the public resource projection and operation rules; the Project ID + selects the target space and does not authenticate. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Reuses the public resource projection and operation rules; the Project ID selects the target space and does not authenticate. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/sessions/index.mdx b/apps/docs/content/docs/api-reference/core/sessions/index.mdx new file mode 100644 index 000000000..a4777b09c --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/sessions/index.mdx @@ -0,0 +1,13 @@ +--- +title: "Sessions" +description: "Sessions. Core administration API: Core key held by Web’s server or an operator script." +--- + +Generated local management contract. This is not part of the public OpenAI API. + +| Operation | Method | Path | +| --- | --- | --- | +| [List execution Sessions in a Project](/api-reference/core/sessions/list-execution-sessions-in-a-project) | `GET` | `/core/v1/projects/{project_id}/sessions` | +| [Retrieve an execution Session in a Project](/api-reference/core/sessions/retrieve-an-execution-session-in-a-project) | `GET` | `/core/v1/projects/{project_id}/sessions/{session_id}` | +| [Delete an execution Session in a Project](/api-reference/core/sessions/delete-an-execution-session-in-a-project) | `DELETE` | `/core/v1/projects/{project_id}/sessions/{session_id}` | +| [Retrieve root Session diagnostics](/api-reference/core/sessions/retrieve-root-session-diagnostics) | `GET` | `/core/v1/projects/{project_id}/sessions/{session_id}/diagnostics` | diff --git a/apps/docs/content/docs/api-reference/core/sessions/list-execution-sessions-in-a-project.mdx b/apps/docs/content/docs/api-reference/core/sessions/list-execution-sessions-in-a-project.mdx new file mode 100644 index 000000000..13fa099f0 --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/sessions/list-execution-sessions-in-a-project.mdx @@ -0,0 +1,21 @@ +--- +title: List execution Sessions in a Project +description: Core key only. +full: true +_openapi: + method: GET + route: /core/v1/projects/{project_id}/sessions + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Core key only. Reuses the public resource projection and operation rules; the Project ID + selects the target space and does not authenticate. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Reuses the public resource projection and operation rules; the Project ID selects the target space and does not authenticate. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/sessions/meta.json b/apps/docs/content/docs/api-reference/core/sessions/meta.json new file mode 100644 index 000000000..964f00992 --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/sessions/meta.json @@ -0,0 +1,9 @@ +{ + "title": "Sessions", + "pages": [ + "list-execution-sessions-in-a-project", + "retrieve-an-execution-session-in-a-project", + "delete-an-execution-session-in-a-project", + "retrieve-root-session-diagnostics" + ] +} diff --git a/apps/docs/content/docs/api-reference/core/sessions/retrieve-an-execution-session-in-a-project.mdx b/apps/docs/content/docs/api-reference/core/sessions/retrieve-an-execution-session-in-a-project.mdx new file mode 100644 index 000000000..7c5423196 --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/sessions/retrieve-an-execution-session-in-a-project.mdx @@ -0,0 +1,21 @@ +--- +title: Retrieve an execution Session in a Project +description: Core key only. +full: true +_openapi: + method: GET + route: /core/v1/projects/{project_id}/sessions/{session_id} + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Core key only. Reuses the public resource projection and operation rules; the Project ID + selects the target space and does not authenticate. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Reuses the public resource projection and operation rules; the Project ID selects the target space and does not authenticate. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/sessions/retrieve-root-session-diagnostics.mdx b/apps/docs/content/docs/api-reference/core/sessions/retrieve-root-session-diagnostics.mdx new file mode 100644 index 000000000..1a2675b23 --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/sessions/retrieve-root-session-diagnostics.mdx @@ -0,0 +1,21 @@ +--- +title: Retrieve root Session diagnostics +description: Core key only. +full: true +_openapi: + method: GET + route: /core/v1/projects/{project_id}/sessions/{session_id}/diagnostics + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Core key only. Safe failure categories from one committed snapshot; no native text or + historical inference. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Safe failure categories from one committed snapshot; no native text or historical inference. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/skills.mdx b/apps/docs/content/docs/api-reference/core/skills.mdx deleted file mode 100644 index 1521c7fb9..000000000 --- a/apps/docs/content/docs/api-reference/core/skills.mdx +++ /dev/null @@ -1,49 +0,0 @@ ---- -title: Skills -description: >- - Skills. Core administration API: Core key held by Web’s server or an operator - script. Generated local management contract. This is not part of the public - OpenAI API. -full: true -_openapi: - toc: [] - structuredData: - headings: [] - contents: - - content: >- - Core key only. Reuses the public resource projection and operation - rules; the Project ID selects the target space and does not - authenticate. - - content: >- - Core key only. Reuses the public resource projection and operation - rules; the Project ID selects the target space and does not - authenticate. - - content: >- - Core key only. Reuses the public resource projection and operation - rules; the Project ID selects the target space and does not - authenticate. - - content: >- - Core key only. Reuses the public resource projection and operation - rules; the Project ID selects the target space and does not - authenticate. - - content: >- - Core key only. Reuses the public resource projection and operation - rules; the Project ID selects the target space and does not - authenticate. - - content: >- - Core key only. Reuses the public resource projection and operation - rules; the Project ID selects the target space and does not - authenticate. - - content: >- - Core key only. Reuses the public resource projection and operation - rules; the Project ID selects the target space and does not - authenticate. - - content: >- - Core key only. Reuses the public resource projection and operation - rules; the Project ID selects the target space and does not - authenticate. ---- - -{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} - - \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/skills/delete-a-skill-and-its-versions-in-a-project.mdx b/apps/docs/content/docs/api-reference/core/skills/delete-a-skill-and-its-versions-in-a-project.mdx new file mode 100644 index 000000000..b6bc2f0c1 --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/skills/delete-a-skill-and-its-versions-in-a-project.mdx @@ -0,0 +1,21 @@ +--- +title: Delete a Skill and its versions in a Project +description: Core key only. +full: true +_openapi: + method: DELETE + route: /core/v1/projects/{project_id}/skills/{skill_id} + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Core key only. Reuses the public resource projection and operation rules; the Project ID + selects the target space and does not authenticate. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Reuses the public resource projection and operation rules; the Project ID selects the target space and does not authenticate. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/skills/delete-a-skill-version-in-a-project.mdx b/apps/docs/content/docs/api-reference/core/skills/delete-a-skill-version-in-a-project.mdx new file mode 100644 index 000000000..4c2c336a3 --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/skills/delete-a-skill-version-in-a-project.mdx @@ -0,0 +1,21 @@ +--- +title: Delete a Skill version in a Project +description: Core key only. +full: true +_openapi: + method: DELETE + route: /core/v1/projects/{project_id}/skills/{skill_id}/versions/{version} + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Core key only. Reuses the public resource projection and operation rules; the Project ID + selects the target space and does not authenticate. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Reuses the public resource projection and operation rules; the Project ID selects the target space and does not authenticate. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/skills/download-immutable-skill-version-content-in-a-project.mdx b/apps/docs/content/docs/api-reference/core/skills/download-immutable-skill-version-content-in-a-project.mdx new file mode 100644 index 000000000..4ead64999 --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/skills/download-immutable-skill-version-content-in-a-project.mdx @@ -0,0 +1,21 @@ +--- +title: Download immutable Skill version content in a Project +description: Core key only. +full: true +_openapi: + method: GET + route: /core/v1/projects/{project_id}/skills/{skill_id}/versions/{version}/content + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Core key only. Reuses the public resource projection and operation rules; the Project ID + selects the target space and does not authenticate. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Reuses the public resource projection and operation rules; the Project ID selects the target space and does not authenticate. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/skills/download-skill-content-in-a-project.mdx b/apps/docs/content/docs/api-reference/core/skills/download-skill-content-in-a-project.mdx new file mode 100644 index 000000000..c131a9691 --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/skills/download-skill-content-in-a-project.mdx @@ -0,0 +1,21 @@ +--- +title: Download Skill content in a Project +description: Core key only. +full: true +_openapi: + method: GET + route: /core/v1/projects/{project_id}/skills/{skill_id}/content + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Core key only. Reuses the public resource projection and operation rules; the Project ID + selects the target space and does not authenticate. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Reuses the public resource projection and operation rules; the Project ID selects the target space and does not authenticate. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/skills/index.mdx b/apps/docs/content/docs/api-reference/core/skills/index.mdx new file mode 100644 index 000000000..a5af14962 --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/skills/index.mdx @@ -0,0 +1,17 @@ +--- +title: "Skills" +description: "Skills. Core administration API: Core key held by Web’s server or an operator script." +--- + +Generated local management contract. This is not part of the public OpenAI API. + +| Operation | Method | Path | +| --- | --- | --- | +| [List Skills in a Project](/api-reference/core/skills/list-skills-in-a-project) | `GET` | `/core/v1/projects/{project_id}/skills` | +| [Retrieve Skill metadata in a Project](/api-reference/core/skills/retrieve-skill-metadata-in-a-project) | `GET` | `/core/v1/projects/{project_id}/skills/{skill_id}` | +| [Delete a Skill and its versions in a Project](/api-reference/core/skills/delete-a-skill-and-its-versions-in-a-project) | `DELETE` | `/core/v1/projects/{project_id}/skills/{skill_id}` | +| [Download Skill content in a Project](/api-reference/core/skills/download-skill-content-in-a-project) | `GET` | `/core/v1/projects/{project_id}/skills/{skill_id}/content` | +| [List Skill versions in a Project](/api-reference/core/skills/list-skill-versions-in-a-project) | `GET` | `/core/v1/projects/{project_id}/skills/{skill_id}/versions` | +| [Retrieve Skill version metadata in a Project](/api-reference/core/skills/retrieve-skill-version-metadata-in-a-project) | `GET` | `/core/v1/projects/{project_id}/skills/{skill_id}/versions/{version}` | +| [Delete a Skill version in a Project](/api-reference/core/skills/delete-a-skill-version-in-a-project) | `DELETE` | `/core/v1/projects/{project_id}/skills/{skill_id}/versions/{version}` | +| [Download immutable Skill version content in a Project](/api-reference/core/skills/download-immutable-skill-version-content-in-a-project) | `GET` | `/core/v1/projects/{project_id}/skills/{skill_id}/versions/{version}/content` | diff --git a/apps/docs/content/docs/api-reference/core/skills/list-skill-versions-in-a-project.mdx b/apps/docs/content/docs/api-reference/core/skills/list-skill-versions-in-a-project.mdx new file mode 100644 index 000000000..7bbef52f8 --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/skills/list-skill-versions-in-a-project.mdx @@ -0,0 +1,21 @@ +--- +title: List Skill versions in a Project +description: Core key only. +full: true +_openapi: + method: GET + route: /core/v1/projects/{project_id}/skills/{skill_id}/versions + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Core key only. Reuses the public resource projection and operation rules; the Project ID + selects the target space and does not authenticate. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Reuses the public resource projection and operation rules; the Project ID selects the target space and does not authenticate. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/skills/list-skills-in-a-project.mdx b/apps/docs/content/docs/api-reference/core/skills/list-skills-in-a-project.mdx new file mode 100644 index 000000000..de7b2fdbc --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/skills/list-skills-in-a-project.mdx @@ -0,0 +1,21 @@ +--- +title: List Skills in a Project +description: Core key only. +full: true +_openapi: + method: GET + route: /core/v1/projects/{project_id}/skills + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Core key only. Reuses the public resource projection and operation rules; the Project ID + selects the target space and does not authenticate. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Reuses the public resource projection and operation rules; the Project ID selects the target space and does not authenticate. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/skills/meta.json b/apps/docs/content/docs/api-reference/core/skills/meta.json new file mode 100644 index 000000000..f7a65be69 --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/skills/meta.json @@ -0,0 +1,13 @@ +{ + "title": "Skills", + "pages": [ + "list-skills-in-a-project", + "retrieve-skill-metadata-in-a-project", + "delete-a-skill-and-its-versions-in-a-project", + "download-skill-content-in-a-project", + "list-skill-versions-in-a-project", + "retrieve-skill-version-metadata-in-a-project", + "delete-a-skill-version-in-a-project", + "download-immutable-skill-version-content-in-a-project" + ] +} diff --git a/apps/docs/content/docs/api-reference/core/skills/retrieve-skill-metadata-in-a-project.mdx b/apps/docs/content/docs/api-reference/core/skills/retrieve-skill-metadata-in-a-project.mdx new file mode 100644 index 000000000..70b3fd6a3 --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/skills/retrieve-skill-metadata-in-a-project.mdx @@ -0,0 +1,21 @@ +--- +title: Retrieve Skill metadata in a Project +description: Core key only. +full: true +_openapi: + method: GET + route: /core/v1/projects/{project_id}/skills/{skill_id} + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Core key only. Reuses the public resource projection and operation rules; the Project ID + selects the target space and does not authenticate. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Reuses the public resource projection and operation rules; the Project ID selects the target space and does not authenticate. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/skills/retrieve-skill-version-metadata-in-a-project.mdx b/apps/docs/content/docs/api-reference/core/skills/retrieve-skill-version-metadata-in-a-project.mdx new file mode 100644 index 000000000..f061089aa --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/skills/retrieve-skill-version-metadata-in-a-project.mdx @@ -0,0 +1,21 @@ +--- +title: Retrieve Skill version metadata in a Project +description: Core key only. +full: true +_openapi: + method: GET + route: /core/v1/projects/{project_id}/skills/{skill_id}/versions/{version} + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Core key only. Reuses the public resource projection and operation rules; the Project ID + selects the target space and does not authenticate. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Reuses the public resource projection and operation rules; the Project ID selects the target space and does not authenticate. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/turns.mdx b/apps/docs/content/docs/api-reference/core/turns.mdx deleted file mode 100644 index d21b08bb2..000000000 --- a/apps/docs/content/docs/api-reference/core/turns.mdx +++ /dev/null @@ -1,28 +0,0 @@ ---- -title: Turns -description: >- - Turns. Core administration API: Core key held by Web’s server or an operator - script. Generated local management contract. This is not part of the public - OpenAI API. -full: true -_openapi: - toc: [] - structuredData: - headings: [] - contents: - - content: >- - Core key only. Reuses the public resource projection and operation - rules; the Project ID selects the target space and does not - authenticate. - - content: >- - Core key only. Reuses the public resource projection and operation - rules; the Project ID selects the target space and does not - authenticate. - - content: >- - Core key only. At most 1000 root Item receipt timings in public Item - order. Receipt intervals are not native execution durations. ---- - -{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} - - \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/turns/index.mdx b/apps/docs/content/docs/api-reference/core/turns/index.mdx new file mode 100644 index 000000000..23b1d8f4c --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/turns/index.mdx @@ -0,0 +1,12 @@ +--- +title: "Turns" +description: "Turns. Core administration API: Core key held by Web’s server or an operator script." +--- + +Generated local management contract. This is not part of the public OpenAI API. + +| Operation | Method | Path | +| --- | --- | --- | +| [List execution Turns in a Project](/api-reference/core/turns/list-execution-turns-in-a-project) | `GET` | `/core/v1/projects/{project_id}/sessions/{session_id}/turns` | +| [Retrieve an execution Turn in a Project](/api-reference/core/turns/retrieve-an-execution-turn-in-a-project) | `GET` | `/core/v1/projects/{project_id}/sessions/{session_id}/turns/{turn_id}` | +| [Retrieve root Turn diagnostics](/api-reference/core/turns/retrieve-root-turn-diagnostics) | `GET` | `/core/v1/projects/{project_id}/sessions/{session_id}/turns/{turn_id}/diagnostics` | diff --git a/apps/docs/content/docs/api-reference/core/turns/list-execution-turns-in-a-project.mdx b/apps/docs/content/docs/api-reference/core/turns/list-execution-turns-in-a-project.mdx new file mode 100644 index 000000000..456456a4c --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/turns/list-execution-turns-in-a-project.mdx @@ -0,0 +1,21 @@ +--- +title: List execution Turns in a Project +description: Core key only. +full: true +_openapi: + method: GET + route: /core/v1/projects/{project_id}/sessions/{session_id}/turns + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Core key only. Reuses the public resource projection and operation rules; the Project ID + selects the target space and does not authenticate. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Reuses the public resource projection and operation rules; the Project ID selects the target space and does not authenticate. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/turns/meta.json b/apps/docs/content/docs/api-reference/core/turns/meta.json new file mode 100644 index 000000000..30e2291cb --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/turns/meta.json @@ -0,0 +1,8 @@ +{ + "title": "Turns", + "pages": [ + "list-execution-turns-in-a-project", + "retrieve-an-execution-turn-in-a-project", + "retrieve-root-turn-diagnostics" + ] +} diff --git a/apps/docs/content/docs/api-reference/core/turns/retrieve-an-execution-turn-in-a-project.mdx b/apps/docs/content/docs/api-reference/core/turns/retrieve-an-execution-turn-in-a-project.mdx new file mode 100644 index 000000000..890c57760 --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/turns/retrieve-an-execution-turn-in-a-project.mdx @@ -0,0 +1,21 @@ +--- +title: Retrieve an execution Turn in a Project +description: Core key only. +full: true +_openapi: + method: GET + route: /core/v1/projects/{project_id}/sessions/{session_id}/turns/{turn_id} + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Core key only. Reuses the public resource projection and operation rules; the Project ID + selects the target space and does not authenticate. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Reuses the public resource projection and operation rules; the Project ID selects the target space and does not authenticate. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/turns/retrieve-root-turn-diagnostics.mdx b/apps/docs/content/docs/api-reference/core/turns/retrieve-root-turn-diagnostics.mdx new file mode 100644 index 000000000..7870c4f03 --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/turns/retrieve-root-turn-diagnostics.mdx @@ -0,0 +1,21 @@ +--- +title: Retrieve root Turn diagnostics +description: Core key only. At most 1000 root Item receipt timings in public Item order. +full: true +_openapi: + method: GET + route: /core/v1/projects/{project_id}/sessions/{session_id}/turns/{turn_id}/diagnostics + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Core key only. At most 1000 root Item receipt timings in public Item order. Receipt + intervals are not native execution durations. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Receipt intervals are not native execution durations. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/vaults.mdx b/apps/docs/content/docs/api-reference/core/vaults.mdx deleted file mode 100644 index 552e8e9de..000000000 --- a/apps/docs/content/docs/api-reference/core/vaults.mdx +++ /dev/null @@ -1,29 +0,0 @@ ---- -title: Vaults -description: >- - Vaults. Core administration API: Core key held by Web’s server or an operator - script. Generated local management contract. This is not part of the public - OpenAI API. -full: true -_openapi: - toc: [] - structuredData: - headings: [] - contents: - - content: >- - Core key only. Reuses the public resource projection and operation - rules; the Project ID selects the target space and does not - authenticate. - - content: >- - Core key only. Reuses the public resource projection and operation - rules; the Project ID selects the target space and does not - authenticate. - - content: >- - Core key only. Reuses the public resource projection and operation - rules; the Project ID selects the target space and does not - authenticate. ---- - -{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} - - \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/vaults/delete-a-vault-and-all-its-credentials-in-a-project.mdx b/apps/docs/content/docs/api-reference/core/vaults/delete-a-vault-and-all-its-credentials-in-a-project.mdx new file mode 100644 index 000000000..47764157a --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/vaults/delete-a-vault-and-all-its-credentials-in-a-project.mdx @@ -0,0 +1,21 @@ +--- +title: Delete a Vault and all its Credentials in a Project +description: Core key only. +full: true +_openapi: + method: DELETE + route: /core/v1/projects/{project_id}/vaults/{vault_id} + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Core key only. Reuses the public resource projection and operation rules; the Project ID + selects the target space and does not authenticate. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Reuses the public resource projection and operation rules; the Project ID selects the target space and does not authenticate. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/vaults/index.mdx b/apps/docs/content/docs/api-reference/core/vaults/index.mdx new file mode 100644 index 000000000..99fd072e8 --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/vaults/index.mdx @@ -0,0 +1,12 @@ +--- +title: "Vaults" +description: "Vaults. Core administration API: Core key held by Web’s server or an operator script." +--- + +Generated local management contract. This is not part of the public OpenAI API. + +| Operation | Method | Path | +| --- | --- | --- | +| [List Vaults in a Project](/api-reference/core/vaults/list-vaults-in-a-project) | `GET` | `/core/v1/projects/{project_id}/vaults` | +| [Retrieve a Vault in a Project](/api-reference/core/vaults/retrieve-a-vault-in-a-project) | `GET` | `/core/v1/projects/{project_id}/vaults/{vault_id}` | +| [Delete a Vault and all its Credentials in a Project](/api-reference/core/vaults/delete-a-vault-and-all-its-credentials-in-a-project) | `DELETE` | `/core/v1/projects/{project_id}/vaults/{vault_id}` | diff --git a/apps/docs/content/docs/api-reference/core/vaults/list-vaults-in-a-project.mdx b/apps/docs/content/docs/api-reference/core/vaults/list-vaults-in-a-project.mdx new file mode 100644 index 000000000..b55b804b3 --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/vaults/list-vaults-in-a-project.mdx @@ -0,0 +1,21 @@ +--- +title: List Vaults in a Project +description: Core key only. +full: true +_openapi: + method: GET + route: /core/v1/projects/{project_id}/vaults + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Core key only. Reuses the public resource projection and operation rules; the Project ID + selects the target space and does not authenticate. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Reuses the public resource projection and operation rules; the Project ID selects the target space and does not authenticate. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/vaults/meta.json b/apps/docs/content/docs/api-reference/core/vaults/meta.json new file mode 100644 index 000000000..68aaa7e7f --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/vaults/meta.json @@ -0,0 +1,8 @@ +{ + "title": "Vaults", + "pages": [ + "list-vaults-in-a-project", + "retrieve-a-vault-in-a-project", + "delete-a-vault-and-all-its-credentials-in-a-project" + ] +} diff --git a/apps/docs/content/docs/api-reference/core/vaults/retrieve-a-vault-in-a-project.mdx b/apps/docs/content/docs/api-reference/core/vaults/retrieve-a-vault-in-a-project.mdx new file mode 100644 index 000000000..c9899f053 --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/vaults/retrieve-a-vault-in-a-project.mdx @@ -0,0 +1,21 @@ +--- +title: Retrieve a Vault in a Project +description: Core key only. +full: true +_openapi: + method: GET + route: /core/v1/projects/{project_id}/vaults/{vault_id} + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Core key only. Reuses the public resource projection and operation rules; the Project ID + selects the target space and does not authenticate. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Reuses the public resource projection and operation rules; the Project ID selects the target space and does not authenticate. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/write-audit.mdx b/apps/docs/content/docs/api-reference/core/write-audit.mdx deleted file mode 100644 index 70eed9da8..000000000 --- a/apps/docs/content/docs/api-reference/core/write-audit.mdx +++ /dev/null @@ -1,26 +0,0 @@ ---- -title: Write Audit -description: >- - Write Audit. Core administration API: Core key held by Web’s server or an - operator script. Generated local management contract. This is not part of the - public OpenAI API. -full: true -_openapi: - toc: [] - structuredData: - headings: [] - contents: - - content: >- - Core key only. The Project ID path selects its space. Returns null for - resources without recorded creation provenance, including historical - and foreign resources. No key secret is returned. - - content: >- - Core key only. Reverse chronological keyset pagination over committed - writes. Creation records remain; other records follow configured - retention. The key path selects its independent space, never a - caller-supplied tenant. ---- - -{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} - - \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/write-audit/batch-lookup-resource-creation-keys.mdx b/apps/docs/content/docs/api-reference/core/write-audit/batch-lookup-resource-creation-keys.mdx new file mode 100644 index 000000000..845db170e --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/write-audit/batch-lookup-resource-creation-keys.mdx @@ -0,0 +1,22 @@ +--- +title: Batch lookup resource creation keys +description: Core key only. The Project ID path selects its space. +full: true +_openapi: + method: GET + route: /core/v1/projects/{project_id}/resource-owners + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Core key only. The Project ID path selects its space. Returns null for resources without + recorded creation provenance, including historical and foreign resources. No key secret is + returned. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Returns null for resources without recorded creation provenance, including historical and foreign resources. No key secret is returned. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/core/write-audit/index.mdx b/apps/docs/content/docs/api-reference/core/write-audit/index.mdx new file mode 100644 index 000000000..282e7909a --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/write-audit/index.mdx @@ -0,0 +1,11 @@ +--- +title: "Write Audit" +description: "Write Audit. Core administration API: Core key held by Web’s server or an operator script." +--- + +Generated local management contract. This is not part of the public OpenAI API. + +| Operation | Method | Path | +| --- | --- | --- | +| [Batch lookup resource creation keys](/api-reference/core/write-audit/batch-lookup-resource-creation-keys) | `GET` | `/core/v1/projects/{project_id}/resource-owners` | +| [Query API-key write operations](/api-reference/core/write-audit/query-api-key-write-operations) | `GET` | `/core/v1/projects/{project_id}/write-operations` | diff --git a/apps/docs/content/docs/api-reference/core/write-audit/meta.json b/apps/docs/content/docs/api-reference/core/write-audit/meta.json new file mode 100644 index 000000000..464f496e5 --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/write-audit/meta.json @@ -0,0 +1,7 @@ +{ + "title": "Write Audit", + "pages": [ + "batch-lookup-resource-creation-keys", + "query-api-key-write-operations" + ] +} diff --git a/apps/docs/content/docs/api-reference/core/write-audit/query-api-key-write-operations.mdx b/apps/docs/content/docs/api-reference/core/write-audit/query-api-key-write-operations.mdx new file mode 100644 index 000000000..ef7d360d8 --- /dev/null +++ b/apps/docs/content/docs/api-reference/core/write-audit/query-api-key-write-operations.mdx @@ -0,0 +1,22 @@ +--- +title: Query API-key write operations +description: Core key only. Reverse chronological keyset pagination over committed writes. +full: true +_openapi: + method: GET + route: /core/v1/projects/{project_id}/write-operations + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Core key only. Reverse chronological keyset pagination over committed writes. Creation + records remain; other records follow configured retention. The key path selects its + independent space, never a caller-supplied tenant. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Creation records remain; other records follow configured retention. The key path selects its independent space, never a caller-supplied tenant. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/credentials.mdx b/apps/docs/content/docs/api-reference/credentials.mdx deleted file mode 100644 index b75f46360..000000000 --- a/apps/docs/content/docs/api-reference/credentials.mdx +++ /dev/null @@ -1,74 +0,0 @@ ---- -title: Credentials -description: >- - Credentials. Application API: Project API key. Public schema constrained by - the pinned OpenAI Agents API baseline; documented x_agents_core fields remain - Core extensions. -full: true -_openapi: - toc: [] - structuredData: - headings: [] - contents: - - content: >- - Lists only metadata from the authenticated project's requested Vault, - without decryption or execution. An unknown, malformed or foreign - after cursor, including another Vault's Credential, returns not found. - Includes active and archived Credentials by default, independently of - Vault status. Status accepts a scalar, the SDK status[] array or both, - filtering by their union; a repeated scalar is rejected. Limits - default to 20 and clamp to 1–100. Equal creation times use ID - ordering. Hosted errors, concurrent-page behavior and archive/delete - lifecycle remain unverified or unimplemented. - - content: >- - Stores static_bearer or mcp_oauth secrets as execution-owned - authenticated ciphertext without contacting any endpoint. Static - bearer and OAuth access tokens must be nonempty strings; their bytes - are preserved. OAuth accepts a required access token, nullable RFC3339 - expiry and optional refresh configuration with none, - client_secret_basic or client_secret_post authentication. Required - name is trimmed to 1–256 UTF-8 bytes. Credential and token endpoints - require HTTPS without userinfo or fragments. Responses contain safe - metadata only, including explicit nullable OAuth expiry, refresh, - resource and scope. Missing encryption configuration returns local - 503. External authorization and provider revocation remain caller - responsibilities; exact hosted error/default semantics remain - unverified. - - content: >- - Reads only non-secret metadata scoped to the authenticated project and - owning Vault. No token decryption, network request or execution is - performed. Unknown, foreign, wrong-Vault and malformed IDs use the - same local not-found response; hosted error parity remains unverified. - - content: >- - Explicitly empty static bearer or OAuth access tokens and OAuth - patches without a mutable field are rejected before storage. Omitted - OAuth access tokens preserve the existing grant when expiry or refresh - fields change. Updates the existing static_bearer or mcp_oauth - authentication method without network requests. OAuth access_token - omission/null retains the token; a new token clears omitted expiry, - explicit null clears expiry, and other omitted fields remain - unchanged. OAuth refresh patches cannot add configuration or change - client, endpoint, resource or authentication method; nullable - token/client-secret values retain stored secrets while explicit null - scope clears scope. Whole-null refresh and token_endpoint_auth retain - existing configuration under local policy. Identity, destination, - creation time and Session bindings remain unchanged. Responses expose - safe metadata only. Already-dispatched work is not revoked; provider - revocation, storage-key rotation and exact hosted - concurrent-update/error semantics remain separate. - - content: >- - Removes one Credential and its encrypted token within the - authenticated project and owning Vault, without an encryption key or - secret decryption. Subsequent metadata reads, updates and dispatch - lookups cannot use it. Existing Session snapshots and history retain - their frozen identities; already-resolved tokens and running Sessions - are not revoked or cancelled. This local policy removes the row rather - than defining archived lifecycle; missing/repeated deletion returns - 404. Exact hosted archive, post-delete visibility and retry/error - semantics remain unverified. Provider revocation and physical erasure - from native history, WAL or backups are separate concerns. ---- - -{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} - - \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/credentials/create-a-vault-credential.mdx b/apps/docs/content/docs/api-reference/credentials/create-a-vault-credential.mdx new file mode 100644 index 000000000..3a8091784 --- /dev/null +++ b/apps/docs/content/docs/api-reference/credentials/create-a-vault-credential.mdx @@ -0,0 +1,40 @@ +--- +title: Create a Vault Credential +description: >- + Stores static_bearer or mcp_oauth secrets as execution-owned authenticated ciphertext without + contacting any endpoint. +full: true +_openapi: + method: POST + route: /vaults/{vault_id}/credentials + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Stores static_bearer or mcp_oauth secrets as execution-owned authenticated ciphertext + without contacting any endpoint. Static bearer and OAuth access tokens must be nonempty + strings; their bytes are preserved. OAuth accepts a required access token, nullable + RFC3339 expiry and optional refresh configuration with none, client_secret_basic or + client_secret_post authentication. Required name is trimmed to 1–256 UTF-8 bytes. + Credential and token endpoints require HTTPS without userinfo or fragments. Responses + contain safe metadata only, including explicit nullable OAuth expiry, refresh, resource + and scope. Missing encryption configuration returns local 503. External authorization and + provider revocation remain caller responsibilities; exact hosted error/default semantics + remain unverified. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +
+Full description + +Static bearer and OAuth access tokens must be nonempty strings; their bytes are preserved. OAuth accepts a required access token, nullable RFC3339 expiry and optional refresh configuration with none, client_secret_basic or client_secret_post authentication. Required name is trimmed to 1–256 UTF-8 bytes. + +Credential and token endpoints require HTTPS without userinfo or fragments. Responses contain safe metadata only, including explicit nullable OAuth expiry, refresh, resource and scope. Missing encryption configuration returns local 503. + +External authorization and provider revocation remain caller responsibilities; exact hosted error/default semantics remain unverified. + +
+ + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/credentials/delete-a-vault-credential.mdx b/apps/docs/content/docs/api-reference/credentials/delete-a-vault-credential.mdx new file mode 100644 index 000000000..0961872e0 --- /dev/null +++ b/apps/docs/content/docs/api-reference/credentials/delete-a-vault-credential.mdx @@ -0,0 +1,36 @@ +--- +title: Delete a Vault Credential +description: >- + Removes one Credential and its encrypted token within the authenticated project and owning Vault, + without an encryption key or secret decryption. +full: true +_openapi: + method: DELETE + route: /vaults/{vault_id}/credentials/{credential_id} + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Removes one Credential and its encrypted token within the authenticated project and owning + Vault, without an encryption key or secret decryption. Subsequent metadata reads, updates + and dispatch lookups cannot use it. Existing Session snapshots and history retain their + frozen identities; already-resolved tokens and running Sessions are not revoked or + cancelled. This local policy removes the row rather than defining archived lifecycle; + missing/repeated deletion returns 404. Exact hosted archive, post-delete visibility and + retry/error semantics remain unverified. Provider revocation and physical erasure from + native history, WAL or backups are separate concerns. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +
+Full description + +Subsequent metadata reads, updates and dispatch lookups cannot use it. Existing Session snapshots and history retain their frozen identities; already-resolved tokens and running Sessions are not revoked or cancelled. This local policy removes the row rather than defining archived lifecycle; missing/repeated deletion returns 404. + +Exact hosted archive, post-delete visibility and retry/error semantics remain unverified. Provider revocation and physical erasure from native history, WAL or backups are separate concerns. + +
+ + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/credentials/index.mdx b/apps/docs/content/docs/api-reference/credentials/index.mdx new file mode 100644 index 000000000..e566b001f --- /dev/null +++ b/apps/docs/content/docs/api-reference/credentials/index.mdx @@ -0,0 +1,14 @@ +--- +title: "Credentials" +description: "Credentials. Application API: Project API key." +--- + +Public schema constrained by the pinned OpenAI Agents API baseline; documented x_agents_core fields remain Core extensions. + +| Operation | Method | Path | +| --- | --- | --- | +| [List safe Vault Credential metadata](/api-reference/credentials/list-safe-vault-credential-metadata) | `GET` | `/v1/vaults/{vault_id}/credentials` | +| [Create a Vault Credential](/api-reference/credentials/create-a-vault-credential) | `POST` | `/v1/vaults/{vault_id}/credentials` | +| [Retrieve safe Vault Credential metadata](/api-reference/credentials/retrieve-safe-vault-credential-metadata) | `GET` | `/v1/vaults/{vault_id}/credentials/{credential_id}` | +| [Replace Vault Credential authentication secrets](/api-reference/credentials/replace-vault-credential-authentication-secrets) | `POST` | `/v1/vaults/{vault_id}/credentials/{credential_id}` | +| [Delete a Vault Credential](/api-reference/credentials/delete-a-vault-credential) | `DELETE` | `/v1/vaults/{vault_id}/credentials/{credential_id}` | diff --git a/apps/docs/content/docs/api-reference/credentials/list-safe-vault-credential-metadata.mdx b/apps/docs/content/docs/api-reference/credentials/list-safe-vault-credential-metadata.mdx new file mode 100644 index 000000000..5460890eb --- /dev/null +++ b/apps/docs/content/docs/api-reference/credentials/list-safe-vault-credential-metadata.mdx @@ -0,0 +1,35 @@ +--- +title: List safe Vault Credential metadata +description: >- + Lists only metadata from the authenticated project's requested Vault, without decryption or + execution. +full: true +_openapi: + method: GET + route: /vaults/{vault_id}/credentials + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Lists only metadata from the authenticated project's requested Vault, without decryption + or execution. An unknown, malformed or foreign after cursor, including another Vault's + Credential, returns not found. Includes active and archived Credentials by default, + independently of Vault status. Status accepts a scalar, the SDK status[] array or both, + filtering by their union; a repeated scalar is rejected. Limits default to 20 and clamp to + 1–100. Equal creation times use ID ordering. Hosted errors, concurrent-page behavior and + archive/delete lifecycle remain unverified or unimplemented. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +
+Full description + +An unknown, malformed or foreign after cursor, including another Vault's Credential, returns not found. Includes active and archived Credentials by default, independently of Vault status. Status accepts a scalar, the SDK status[] array or both, filtering by their union; a repeated scalar is rejected. + +Limits default to 20 and clamp to 1–100. Equal creation times use ID ordering. Hosted errors, concurrent-page behavior and archive/delete lifecycle remain unverified or unimplemented. + +
+ + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/credentials/meta.json b/apps/docs/content/docs/api-reference/credentials/meta.json new file mode 100644 index 000000000..7382aa9c8 --- /dev/null +++ b/apps/docs/content/docs/api-reference/credentials/meta.json @@ -0,0 +1,10 @@ +{ + "title": "Credentials", + "pages": [ + "list-safe-vault-credential-metadata", + "create-a-vault-credential", + "retrieve-safe-vault-credential-metadata", + "replace-vault-credential-authentication-secrets", + "delete-a-vault-credential" + ] +} diff --git a/apps/docs/content/docs/api-reference/credentials/replace-vault-credential-authentication-secrets.mdx b/apps/docs/content/docs/api-reference/credentials/replace-vault-credential-authentication-secrets.mdx new file mode 100644 index 000000000..1f0b890e9 --- /dev/null +++ b/apps/docs/content/docs/api-reference/credentials/replace-vault-credential-authentication-secrets.mdx @@ -0,0 +1,42 @@ +--- +title: Replace Vault Credential authentication secrets +description: >- + Explicitly empty static bearer or OAuth access tokens and OAuth patches without a mutable field + are rejected before storage. +full: true +_openapi: + method: POST + route: /vaults/{vault_id}/credentials/{credential_id} + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Explicitly empty static bearer or OAuth access tokens and OAuth patches without a mutable + field are rejected before storage. Omitted OAuth access tokens preserve the existing grant + when expiry or refresh fields change. Updates the existing static_bearer or mcp_oauth + authentication method without network requests. OAuth access_token omission/null retains + the token; a new token clears omitted expiry, explicit null clears expiry, and other + omitted fields remain unchanged. OAuth refresh patches cannot add configuration or change + client, endpoint, resource or authentication method; nullable token/client-secret values + retain stored secrets while explicit null scope clears scope. Whole-null refresh and + token_endpoint_auth retain existing configuration under local policy. Identity, + destination, creation time and Session bindings remain unchanged. Responses expose safe + metadata only. Already-dispatched work is not revoked; provider revocation, storage-key + rotation and exact hosted concurrent-update/error semantics remain separate. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +
+Full description + +Omitted OAuth access tokens preserve the existing grant when expiry or refresh fields change. Updates the existing static_bearer or mcp_oauth authentication method without network requests. OAuth access_token omission/null retains the token; a new token clears omitted expiry, explicit null clears expiry, and other omitted fields remain unchanged. + +OAuth refresh patches cannot add configuration or change client, endpoint, resource or authentication method; nullable token/client-secret values retain stored secrets while explicit null scope clears scope. Whole-null refresh and token_endpoint_auth retain existing configuration under local policy. Identity, destination, creation time and Session bindings remain unchanged. + +Responses expose safe metadata only. Already-dispatched work is not revoked; provider revocation, storage-key rotation and exact hosted concurrent-update/error semantics remain separate. + +
+ + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/credentials/retrieve-safe-vault-credential-metadata.mdx b/apps/docs/content/docs/api-reference/credentials/retrieve-safe-vault-credential-metadata.mdx new file mode 100644 index 000000000..0fa65d1cc --- /dev/null +++ b/apps/docs/content/docs/api-reference/credentials/retrieve-safe-vault-credential-metadata.mdx @@ -0,0 +1,23 @@ +--- +title: Retrieve safe Vault Credential metadata +description: Reads only non-secret metadata scoped to the authenticated project and owning Vault. +full: true +_openapi: + method: GET + route: /vaults/{vault_id}/credentials/{credential_id} + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Reads only non-secret metadata scoped to the authenticated project and owning Vault. No + token decryption, network request or execution is performed. Unknown, foreign, wrong-Vault + and malformed IDs use the same local not-found response; hosted error parity remains + unverified. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +No token decryption, network request or execution is performed. Unknown, foreign, wrong-Vault and malformed IDs use the same local not-found response; hosted error parity remains unverified. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/environment-templates.mdx b/apps/docs/content/docs/api-reference/environment-templates.mdx deleted file mode 100644 index 32e05af1a..000000000 --- a/apps/docs/content/docs/api-reference/environment-templates.mdx +++ /dev/null @@ -1,58 +0,0 @@ ---- -title: Environment Templates -description: >- - Environment Templates. Application API: Project API key. Public schema - constrained by the pinned OpenAI Agents API baseline; documented x_agents_core - fields remain Core extensions. -full: true -_openapi: - toc: [] - structuredData: - headings: [] - contents: - - content: >- - Lists tenant-owned safe template metadata in creation order with ID - tie-breaking. Defaults to limit 20 and descending order; limit 0 is - treated as 1 and larger limits as 100. Foreign, missing and malformed - cursors return the same not found error. Concurrent-page and exact - hosted error behavior remain unverified. - - content: >- - Saves tenant-owned hosted configuration. Supports nullable name, - enabled/disabled or exact-domain restricted network, initial - inline/file_id files, confidential env, ordered setup_commands, - npm/Python packages inline/referenced Skill ZIPs, Plugin ZIPs and - workspace-contained capability directories. Omitted/null network - defaults to enabled. Restricted network requires 1–100 exact ASCII - hostnames; other host forms and populated unsupported installations - are rejected before persistence without echoing input. Network policy - rejections return invalid_request_error with a null param. System - dependencies must be preinstalled in the sandbox image or template, or - on the host machine; packages.system is rejected. No compute is - allocated. Exact hosted error/retry semantics remain unverified. - - content: >- - Returns safe tenant-owned configuration metadata without allocating - compute. Missing and foreign resources return the same not-found - response. - - content: >- - Supplied fields replace atomically; omitted fields remain unchanged. - Null name clears and null network resets to the pinned enabled - default. Existing Session snapshots and creation retries remain - unchanged. Initial files replace as a list; null/empty clears. File - data is encrypted separately and excluded from response metadata. - Skills replace as a list; null/empty clears. Skill archives are - encrypted separately and omitted from responses. Plugins and - capability directories replace as lists; null/empty clears. Plugin - archives are encrypted and omitted from responses. Capability - directories are snapshotted after setup. Environment MCP execution - requires a qualified native transport and runtime network policy. - Empty updates advance updated_at without changing saved fields or - confidential contents. Network policy rejections return - invalid_request_error with a null param. - - content: >- - Deletes the tenant-owned reusable configuration without changing or - deleting existing Sessions and their frozen configuration. ---- - -{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} - - \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/environment-templates/create-an-environment-template.mdx b/apps/docs/content/docs/api-reference/environment-templates/create-an-environment-template.mdx new file mode 100644 index 000000000..6f6d1f4ef --- /dev/null +++ b/apps/docs/content/docs/api-reference/environment-templates/create-an-environment-template.mdx @@ -0,0 +1,38 @@ +--- +title: Create an Environment Template +description: Saves tenant-owned hosted configuration. +full: true +_openapi: + method: POST + route: /agents/environments/templates + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Saves tenant-owned hosted configuration. Supports nullable name, enabled/disabled or + exact-domain restricted network, initial inline/file_id files, confidential env, ordered + setup_commands, npm/Python packages inline/referenced Skill ZIPs, Plugin ZIPs and + workspace-contained capability directories. Omitted/null network defaults to enabled. + Restricted network requires 1–100 exact ASCII hostnames; other host forms and populated + unsupported installations are rejected before persistence without echoing input. Network + policy rejections return invalid_request_error with a null param. System dependencies must + be preinstalled in the sandbox image or template, or on the host machine; packages.system + is rejected. No compute is allocated. Exact hosted error/retry semantics remain + unverified. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +
+Full description + +Supports nullable name, enabled/disabled or exact-domain restricted network, initial inline/file_id files, confidential env, ordered setup_commands, npm/Python packages inline/referenced Skill ZIPs, Plugin ZIPs and workspace-contained capability directories. Omitted/null network defaults to enabled. Restricted network requires 1–100 exact ASCII hostnames; other host forms and populated unsupported installations are rejected before persistence without echoing input. + +Network policy rejections return invalid_request_error with a null param. System dependencies must be preinstalled in the sandbox image or template, or on the host machine; packages.system is rejected. No compute is allocated. + +Exact hosted error/retry semantics remain unverified. + +
+ + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/environment-templates/delete-an-environment-template.mdx b/apps/docs/content/docs/api-reference/environment-templates/delete-an-environment-template.mdx new file mode 100644 index 000000000..1896ba1f3 --- /dev/null +++ b/apps/docs/content/docs/api-reference/environment-templates/delete-an-environment-template.mdx @@ -0,0 +1,21 @@ +--- +title: Delete an Environment Template +description: >- + Deletes the tenant-owned reusable configuration without changing or deleting existing Sessions and + their frozen configuration. +full: true +_openapi: + method: DELETE + route: /agents/environments/templates/{environment_template_id} + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Deletes the tenant-owned reusable configuration without changing or deleting existing + Sessions and their frozen configuration. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/environment-templates/index.mdx b/apps/docs/content/docs/api-reference/environment-templates/index.mdx new file mode 100644 index 000000000..e2b3a7bda --- /dev/null +++ b/apps/docs/content/docs/api-reference/environment-templates/index.mdx @@ -0,0 +1,14 @@ +--- +title: "Environment Templates" +description: "Environment Templates. Application API: Project API key." +--- + +Public schema constrained by the pinned OpenAI Agents API baseline; documented x_agents_core fields remain Core extensions. + +| Operation | Method | Path | +| --- | --- | --- | +| [List Environment Templates](/api-reference/environment-templates/list-environment-templates) | `GET` | `/v1/agents/environments/templates` | +| [Create an Environment Template](/api-reference/environment-templates/create-an-environment-template) | `POST` | `/v1/agents/environments/templates` | +| [Retrieve an Environment Template](/api-reference/environment-templates/retrieve-an-environment-template) | `GET` | `/v1/agents/environments/templates/{environment_template_id}` | +| [Update an Environment Template](/api-reference/environment-templates/update-an-environment-template) | `POST` | `/v1/agents/environments/templates/{environment_template_id}` | +| [Delete an Environment Template](/api-reference/environment-templates/delete-an-environment-template) | `DELETE` | `/v1/agents/environments/templates/{environment_template_id}` | diff --git a/apps/docs/content/docs/api-reference/environment-templates/list-environment-templates.mdx b/apps/docs/content/docs/api-reference/environment-templates/list-environment-templates.mdx new file mode 100644 index 000000000..f9c0e044d --- /dev/null +++ b/apps/docs/content/docs/api-reference/environment-templates/list-environment-templates.mdx @@ -0,0 +1,23 @@ +--- +title: List Environment Templates +description: Lists tenant-owned safe template metadata in creation order with ID tie-breaking. +full: true +_openapi: + method: GET + route: /agents/environments/templates + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Lists tenant-owned safe template metadata in creation order with ID tie-breaking. Defaults + to limit 20 and descending order; limit 0 is treated as 1 and larger limits as 100. + Foreign, missing and malformed cursors return the same not found error. Concurrent-page + and exact hosted error behavior remain unverified. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Defaults to limit 20 and descending order; limit 0 is treated as 1 and larger limits as 100. Foreign, missing and malformed cursors return the same not found error. Concurrent-page and exact hosted error behavior remain unverified. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/environment-templates/meta.json b/apps/docs/content/docs/api-reference/environment-templates/meta.json new file mode 100644 index 000000000..309876151 --- /dev/null +++ b/apps/docs/content/docs/api-reference/environment-templates/meta.json @@ -0,0 +1,10 @@ +{ + "title": "Environment Templates", + "pages": [ + "list-environment-templates", + "create-an-environment-template", + "retrieve-an-environment-template", + "update-an-environment-template", + "delete-an-environment-template" + ] +} diff --git a/apps/docs/content/docs/api-reference/environment-templates/retrieve-an-environment-template.mdx b/apps/docs/content/docs/api-reference/environment-templates/retrieve-an-environment-template.mdx new file mode 100644 index 000000000..372011640 --- /dev/null +++ b/apps/docs/content/docs/api-reference/environment-templates/retrieve-an-environment-template.mdx @@ -0,0 +1,21 @@ +--- +title: Retrieve an Environment Template +description: Returns safe tenant-owned configuration metadata without allocating compute. +full: true +_openapi: + method: GET + route: /agents/environments/templates/{environment_template_id} + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Returns safe tenant-owned configuration metadata without allocating compute. Missing and + foreign resources return the same not-found response. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Missing and foreign resources return the same not-found response. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/environment-templates/update-an-environment-template.mdx b/apps/docs/content/docs/api-reference/environment-templates/update-an-environment-template.mdx new file mode 100644 index 000000000..1bae574e9 --- /dev/null +++ b/apps/docs/content/docs/api-reference/environment-templates/update-an-environment-template.mdx @@ -0,0 +1,40 @@ +--- +title: Update an Environment Template +description: Supplied fields replace atomically; omitted fields remain unchanged. +full: true +_openapi: + method: POST + route: /agents/environments/templates/{environment_template_id} + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Supplied fields replace atomically; omitted fields remain unchanged. Null name clears and + null network resets to the pinned enabled default. Existing Session snapshots and creation + retries remain unchanged. Initial files replace as a list; null/empty clears. File data is + encrypted separately and excluded from response metadata. Skills replace as a list; + null/empty clears. Skill archives are encrypted separately and omitted from responses. + Plugins and capability directories replace as lists; null/empty clears. Plugin archives + are encrypted and omitted from responses. Capability directories are snapshotted after + setup. Environment MCP execution requires a qualified native transport and runtime network + policy. Empty updates advance updated_at without changing saved fields or confidential + contents. Network policy rejections return invalid_request_error with a null param. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +
+Full description + +Null name clears and null network resets to the pinned enabled default. Existing Session snapshots and creation retries remain unchanged. Initial files replace as a list; null/empty clears. + +File data is encrypted separately and excluded from response metadata. Skills replace as a list; null/empty clears. Skill archives are encrypted separately and omitted from responses. + +Plugins and capability directories replace as lists; null/empty clears. Plugin archives are encrypted and omitted from responses. Capability directories are snapshotted after setup. + +Environment MCP execution requires a qualified native transport and runtime network policy. Empty updates advance updated_at without changing saved fields or confidential contents. Network policy rejections return invalid_request_error with a null param. + +
+ + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/environments.mdx b/apps/docs/content/docs/api-reference/environments.mdx deleted file mode 100644 index 287d4db3f..000000000 --- a/apps/docs/content/docs/api-reference/environments.mdx +++ /dev/null @@ -1,63 +0,0 @@ ---- -title: Environments -description: >- - Environments. Application API: Project API key. Public schema constrained by - the pinned OpenAI Agents API baseline; documented x_agents_core fields remain - Core extensions. -full: true -_openapi: - toc: [] - structuredData: - headings: [] - contents: - - content: >- - Returns durable connection status and safe installed metadata for - supported self_hosted and basic openai_hosted profiles. Initial files - expose frozen safe metadata without content; Plugin/Skill entries - expose only safe configured installation metadata. - Capability-directory discoveries are not added to those arrays. - Unsupported installation configurations remain implementation gaps. - This read does not prepare execution, start compute or require an - enabled execution worker. Session deletion removes the associated - Environment from public reads; project-shared read authorization is - unchanged. Connection status does not prove native readiness or - process quiescence. - - content: >- - Lists direct regular files in one authorized self_hosted or qualified - local workspace directory. Local paths use the public /workspace root - and must be in cleaned form. This partial implementation defaults to - the workspace root and limit 20; recursive scope and these defaults - are not verified upstream semantics. A missing path, a regular file or - a symbolic link returns an empty page; links are never followed. - Daemons without a local workspace binding use the Claude SDK adapter - reader, which keeps 404 for a missing path and 503 for a regular file - or symbolic link. Well-formed unknown query keys are ignored; - malformed query encoding and a repeated supported key are rejected. - Sorts by case-sensitive path components, descending by default. Keep - the same path, order and limit when using page. Each page rereads the - complete bounded directory; changed file paths/sizes invalidate - continuation locally with 400. There is no snapshot guarantee. An - openai_hosted Environment that has not connected yet returns 400. - Truncated or uncertain native results fail with 503 without returning - a partial page. This read never starts a Turn or admits model input. - Actual transport disconnect/reconnect events remain observable. - - content: >- - Uploads standard Base64 bytes to a file beneath /workspace in a - qualified local Environment and returns 201. Accepts inline bytes or a - project-owned source file_id through the same write path. Unknown body - fields are rejected with their name as param. Basic public hosted - creation requires explicit managed Runtime configuration; an - openai_hosted Environment that has not connected yet returns 400. - Inline data is limited to 5 MiB decoded and a file_id copy to 50 MiB. - Missing parent directories are created with mode 0700 and the file - with mode 0600. An existing destination is never replaced; a - directory, an existing file or a path through a symlink or - non-directory returns 400. Idle writes exclude execution. Missing - receipts return unavailable and retain a durable mutation gate without - automatic replay. Error/timing parity with upstream remains - unverified. ---- - -{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} - - \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/environments/create-an-environment-file-from-inline-bytes-or-a-source-file.mdx b/apps/docs/content/docs/api-reference/environments/create-an-environment-file-from-inline-bytes-or-a-source-file.mdx new file mode 100644 index 000000000..182b8a5a6 --- /dev/null +++ b/apps/docs/content/docs/api-reference/environments/create-an-environment-file-from-inline-bytes-or-a-source-file.mdx @@ -0,0 +1,41 @@ +--- +title: Create an Environment file from inline bytes or a source file +description: >- + Uploads standard Base64 bytes to a file beneath /workspace in a qualified local Environment and + returns 201. +full: true +_openapi: + method: POST + route: /agents/environments/{environment_id}/files + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Uploads standard Base64 bytes to a file beneath /workspace in a qualified local + Environment and returns 201. Accepts inline bytes or a project-owned source file_id + through the same write path. Unknown body fields are rejected with their name as param. + Basic public hosted creation requires explicit managed Runtime configuration; an + openai_hosted Environment that has not connected yet returns 400. Inline data is limited + to 5 MiB decoded and a file_id copy to 50 MiB. Missing parent directories are created with + mode 0700 and the file with mode 0600. An existing destination is never replaced; a + directory, an existing file or a path through a symlink or non-directory returns 400. Idle + writes exclude execution. Missing receipts return unavailable and retain a durable + mutation gate without automatic replay. Error/timing parity with upstream remains + unverified. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +
+Full description + +Accepts inline bytes or a project-owned source file_id through the same write path. Unknown body fields are rejected with their name as param. Basic public hosted creation requires explicit managed Runtime configuration; an openai_hosted Environment that has not connected yet returns 400. + +Inline data is limited to 5 MiB decoded and a file_id copy to 50 MiB. Missing parent directories are created with mode 0700 and the file with mode 0600. An existing destination is never replaced; a directory, an existing file or a path through a symlink or non-directory returns 400. + +Idle writes exclude execution. Missing receipts return unavailable and retain a durable mutation gate without automatic replay. Error/timing parity with upstream remains unverified. + +
+ + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/environments/index.mdx b/apps/docs/content/docs/api-reference/environments/index.mdx new file mode 100644 index 000000000..8b005af77 --- /dev/null +++ b/apps/docs/content/docs/api-reference/environments/index.mdx @@ -0,0 +1,12 @@ +--- +title: "Environments" +description: "Environments. Application API: Project API key." +--- + +Public schema constrained by the pinned OpenAI Agents API baseline; documented x_agents_core fields remain Core extensions. + +| Operation | Method | Path | +| --- | --- | --- | +| [Retrieve an execution Environment](/api-reference/environments/retrieve-an-execution-environment) | `GET` | `/v1/agents/environments/{environment_id}` | +| [List live Environment files](/api-reference/environments/list-live-environment-files) | `GET` | `/v1/agents/environments/{environment_id}/files` | +| [Create an Environment file from inline bytes or a source file](/api-reference/environments/create-an-environment-file-from-inline-bytes-or-a-source-file) | `POST` | `/v1/agents/environments/{environment_id}/files` | diff --git a/apps/docs/content/docs/api-reference/environments/list-live-environment-files.mdx b/apps/docs/content/docs/api-reference/environments/list-live-environment-files.mdx new file mode 100644 index 000000000..682126d76 --- /dev/null +++ b/apps/docs/content/docs/api-reference/environments/list-live-environment-files.mdx @@ -0,0 +1,47 @@ +--- +title: List live Environment files +description: Lists direct regular files in one authorized self_hosted or qualified local workspace directory. +full: true +_openapi: + method: GET + route: /agents/environments/{environment_id}/files + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Lists direct regular files in one authorized self_hosted or qualified local workspace + directory. Local paths use the public /workspace root and must be in cleaned form. This + partial implementation defaults to the workspace root and limit 20; recursive scope and + these defaults are not verified upstream semantics. A missing path, a regular file or a + symbolic link returns an empty page; links are never followed. Daemons without a local + workspace binding use the Claude SDK adapter reader, which keeps 404 for a missing path + and 503 for a regular file or symbolic link. Well-formed unknown query keys are ignored; + malformed query encoding and a repeated supported key are rejected. Sorts by + case-sensitive path components, descending by default. Keep the same path, order and limit + when using page. Each page rereads the complete bounded directory; changed file + paths/sizes invalidate continuation locally with 400. There is no snapshot guarantee. An + openai_hosted Environment that has not connected yet returns 400. Truncated or uncertain + native results fail with 503 without returning a partial page. This read never starts a + Turn or admits model input. Actual transport disconnect/reconnect events remain + observable. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +
+Full description + +Local paths use the public /workspace root and must be in cleaned form. This partial implementation defaults to the workspace root and limit 20; recursive scope and these defaults are not verified upstream semantics. A missing path, a regular file or a symbolic link returns an empty page; links are never followed. + +Daemons without a local workspace binding use the Claude SDK adapter reader, which keeps 404 for a missing path and 503 for a regular file or symbolic link. Well-formed unknown query keys are ignored; malformed query encoding and a repeated supported key are rejected. Sorts by case-sensitive path components, descending by default. + +Keep the same path, order and limit when using page. Each page rereads the complete bounded directory; changed file paths/sizes invalidate continuation locally with 400. There is no snapshot guarantee. + +An openai_hosted Environment that has not connected yet returns 400. Truncated or uncertain native results fail with 503 without returning a partial page. This read never starts a Turn or admits model input. + +Actual transport disconnect/reconnect events remain observable. + +
+ + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/environments/meta.json b/apps/docs/content/docs/api-reference/environments/meta.json new file mode 100644 index 000000000..2531e78c7 --- /dev/null +++ b/apps/docs/content/docs/api-reference/environments/meta.json @@ -0,0 +1,8 @@ +{ + "title": "Environments", + "pages": [ + "retrieve-an-execution-environment", + "list-live-environment-files", + "create-an-environment-file-from-inline-bytes-or-a-source-file" + ] +} diff --git a/apps/docs/content/docs/api-reference/environments/retrieve-an-execution-environment.mdx b/apps/docs/content/docs/api-reference/environments/retrieve-an-execution-environment.mdx new file mode 100644 index 000000000..246ee75fe --- /dev/null +++ b/apps/docs/content/docs/api-reference/environments/retrieve-an-execution-environment.mdx @@ -0,0 +1,36 @@ +--- +title: Retrieve an execution Environment +description: >- + Returns durable connection status and safe installed metadata for supported self_hosted and basic + openai_hosted profiles. +full: true +_openapi: + method: GET + route: /agents/environments/{environment_id} + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Returns durable connection status and safe installed metadata for supported self_hosted + and basic openai_hosted profiles. Initial files expose frozen safe metadata without + content; Plugin/Skill entries expose only safe configured installation metadata. + Capability-directory discoveries are not added to those arrays. Unsupported installation + configurations remain implementation gaps. This read does not prepare execution, start + compute or require an enabled execution worker. Session deletion removes the associated + Environment from public reads; project-shared read authorization is unchanged. Connection + status does not prove native readiness or process quiescence. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +
+Full description + +Initial files expose frozen safe metadata without content; Plugin/Skill entries expose only safe configured installation metadata. Capability-directory discoveries are not added to those arrays. Unsupported installation configurations remain implementation gaps. + +This read does not prepare execution, start compute or require an enabled execution worker. Session deletion removes the associated Environment from public reads; project-shared read authorization is unchanged. Connection status does not prove native readiness or process quiescence. + +
+ + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/events.mdx b/apps/docs/content/docs/api-reference/events.mdx deleted file mode 100644 index f0b0639a7..000000000 --- a/apps/docs/content/docs/api-reference/events.mdx +++ /dev/null @@ -1,37 +0,0 @@ ---- -title: Events -description: >- - Events. Application API: Project API key. Public schema constrained by the - pinned OpenAI Agents API baseline; documented x_agents_core fields remain Core - extensions. -full: true -_openapi: - method: GET - route: /agents/sessions/{session_id}/events - toc: [] - structuredData: - headings: [] - contents: - - content: >- - Live-only events, including command output fragments from capable - Codex peers as agent.output.command_execution_output.delta with stable - Item/output indexes. Native text conversion and output quotas apply; - completion snapshots remain authoritative. Reconnect through Session, - Turn and Items reads; missed events are not replayed. A lagging stream - closes with an error when its bounded buffer is exceeded. When a - hosted Environment fails to provision, the stream sends - agent.session.environment.failed, an error event - (environment_error/sandbox_error with the safe step and exit-status - reason, never command output) and agent.session.failed, then ends. - Session activity includes immutable pending-input connection actions - before Turn creation; self_hosted environments use the same safe - output as Session retrieval. - - Active streams revalidate the original Project key every second before - output; revocation, Project archival or authentication unavailability - closes the stream. Authentication checks use a five-second timeout. ---- - -{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} - - \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/events/index.mdx b/apps/docs/content/docs/api-reference/events/index.mdx new file mode 100644 index 000000000..fc50c4f35 --- /dev/null +++ b/apps/docs/content/docs/api-reference/events/index.mdx @@ -0,0 +1,10 @@ +--- +title: "Events" +description: "Events. Application API: Project API key." +--- + +Public schema constrained by the pinned OpenAI Agents API baseline; documented x_agents_core fields remain Core extensions. + +| Operation | Method | Path | +| --- | --- | --- | +| [Stream live Session events](/api-reference/events/stream-live-session-events) | `GET` | `/v1/agents/sessions/{session_id}/events` | diff --git a/apps/docs/content/docs/api-reference/events/meta.json b/apps/docs/content/docs/api-reference/events/meta.json new file mode 100644 index 000000000..53672b206 --- /dev/null +++ b/apps/docs/content/docs/api-reference/events/meta.json @@ -0,0 +1,6 @@ +{ + "title": "Events", + "pages": [ + "stream-live-session-events" + ] +} diff --git a/apps/docs/content/docs/api-reference/events/stream-live-session-events.mdx b/apps/docs/content/docs/api-reference/events/stream-live-session-events.mdx new file mode 100644 index 000000000..1af1429d6 --- /dev/null +++ b/apps/docs/content/docs/api-reference/events/stream-live-session-events.mdx @@ -0,0 +1,41 @@ +--- +title: Stream live Session events +description: >- + Live-only events, including command output fragments from capable Codex peers as + agent.output.command_execution_output.delta with stable Item/output indexes. +full: true +_openapi: + method: GET + route: /agents/sessions/{session_id}/events + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Live-only events, including command output fragments from capable Codex peers as + agent.output.command_execution_output.delta with stable Item/output indexes. Native text + conversion and output quotas apply; completion snapshots remain authoritative. Reconnect + through Session, Turn and Items reads; missed events are not replayed. A lagging stream + closes with an error when its bounded buffer is exceeded. When a hosted Environment fails + to provision, the stream sends agent.session.environment.failed, an error event + (environment_error/sandbox_error with the safe step and exit-status reason, never command + output) and agent.session.failed, then ends. Session activity includes immutable + pending-input connection actions before Turn creation; self_hosted environments use the + same safe output as Session retrieval. + + Active streams revalidate the original Project key every second before output; revocation, + Project archival or authentication unavailability closes the stream. Authentication checks + use a five-second timeout. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +
+Full description + +Native text conversion and output quotas apply; completion snapshots remain authoritative. Reconnect through Session, Turn and Items reads; missed events are not replayed. A lagging stream closes with an error when its bounded buffer is exceeded. When a hosted Environment fails to provision, the stream sends agent.session.environment.failed, an error event (environment_error/sandbox_error with the safe step and exit-status reason, never command output) and agent.session.failed, then ends. Session activity includes immutable pending-input connection actions before Turn creation; self_hosted environments use the same safe output as Session retrieval. +Active streams revalidate the original Project key every second before output; revocation, Project archival or authentication unavailability closes the stream. Authentication checks use a five-second timeout. + +
+ + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/files.mdx b/apps/docs/content/docs/api-reference/files.mdx deleted file mode 100644 index 21b1c0709..000000000 --- a/apps/docs/content/docs/api-reference/files.mdx +++ /dev/null @@ -1,48 +0,0 @@ ---- -title: Files -description: >- - Files. Application API: Project API key. Public schema constrained by the - pinned OpenAI Agents API baseline; documented x_agents_core fields remain Core - extensions. -full: true -_openapi: - toc: [] - structuredData: - headings: [] - contents: - - content: >- - Lists project-owned Files without reading their bodies. The limit - defaults to 10000 and must be 1–10000. Equal creation times use ID - ordering. Purpose validation precedes cursor lookup; current storage - contains only user_data. An explicit empty purpose is treated as - omitted. Repeated purpose values remain rejected. Hosted positive - filtering, default order and concurrent-page behavior remain - unverified. No Beta header is required. - - content: >- - Accepts one multipart file and purpose=user_data in either order, with - a private 512 MiB content limit and 64 KiB envelope allowance. Commits - only after the entire request validates. The source is project-owned, - independent of Sessions and workspace copies. No Beta header is - required. Other purposes, expires_after, listing, resumable Uploads, - quotas/rate-limit and complete hosted error/status parity remain - unsupported or unverified. - - content: >- - Returns immutable project-owned user_data file metadata. No Beta - header is required. Other purposes, expiration and full hosted - status/error semantics remain unimplemented or unverified. - - content: >- - Atomically deletes project-owned metadata and stored bytes. - Already-admitted reads or copies may finish. Workspace copies remain - independent. Historical WAL/backups are not erased. No Beta header is - required; exact hosted concurrent deletion/error semantics remain - unverified. - - content: >- - Resolves project-owned File metadata before enforcing download policy. - Public download of user_data Files returns 400; missing and foreign - Files return the same 404. Internal initial-file and workspace copies - remain available. No Beta header is required. ---- - -{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} - - \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/files/delete-a-source-file.mdx b/apps/docs/content/docs/api-reference/files/delete-a-source-file.mdx new file mode 100644 index 000000000..274556372 --- /dev/null +++ b/apps/docs/content/docs/api-reference/files/delete-a-source-file.mdx @@ -0,0 +1,25 @@ +--- +title: Delete a source file +description: Atomically deletes project-owned metadata and stored bytes. +full: true +_openapi: + method: DELETE + route: /files/{file_id} + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Atomically deletes project-owned metadata and stored bytes. Already-admitted reads or + copies may finish. Workspace copies remain independent. Historical WAL/backups are not + erased. No Beta header is required; exact hosted concurrent deletion/error semantics + remain unverified. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Already-admitted reads or copies may finish. Workspace copies remain independent. Historical WAL/backups are not erased. + +No Beta header is required; exact hosted concurrent deletion/error semantics remain unverified. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/files/download-source-file-bytes.mdx b/apps/docs/content/docs/api-reference/files/download-source-file-bytes.mdx new file mode 100644 index 000000000..8541afdd3 --- /dev/null +++ b/apps/docs/content/docs/api-reference/files/download-source-file-bytes.mdx @@ -0,0 +1,22 @@ +--- +title: Download source file bytes +description: Resolves project-owned File metadata before enforcing download policy. +full: true +_openapi: + method: GET + route: /files/{file_id}/content + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Resolves project-owned File metadata before enforcing download policy. Public download of + user_data Files returns 400; missing and foreign Files return the same 404. Internal + initial-file and workspace copies remain available. No Beta header is required. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Public download of user_data Files returns 400; missing and foreign Files return the same 404. Internal initial-file and workspace copies remain available. No Beta header is required. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/files/index.mdx b/apps/docs/content/docs/api-reference/files/index.mdx new file mode 100644 index 000000000..bbe9c4ebc --- /dev/null +++ b/apps/docs/content/docs/api-reference/files/index.mdx @@ -0,0 +1,14 @@ +--- +title: "Files" +description: "Files. Application API: Project API key." +--- + +Public schema constrained by the pinned OpenAI Agents API baseline; documented x_agents_core fields remain Core extensions. + +| Operation | Method | Path | +| --- | --- | --- | +| [List source files](/api-reference/files/list-source-files) | `GET` | `/v1/files` | +| [Upload a source file](/api-reference/files/upload-a-source-file) | `POST` | `/v1/files` | +| [Retrieve source file metadata](/api-reference/files/retrieve-source-file-metadata) | `GET` | `/v1/files/{file_id}` | +| [Delete a source file](/api-reference/files/delete-a-source-file) | `DELETE` | `/v1/files/{file_id}` | +| [Download source file bytes](/api-reference/files/download-source-file-bytes) | `GET` | `/v1/files/{file_id}/content` | diff --git a/apps/docs/content/docs/api-reference/files/list-source-files.mdx b/apps/docs/content/docs/api-reference/files/list-source-files.mdx new file mode 100644 index 000000000..5aaba62d6 --- /dev/null +++ b/apps/docs/content/docs/api-reference/files/list-source-files.mdx @@ -0,0 +1,28 @@ +--- +title: List source files +description: Lists project-owned Files without reading their bodies. +full: true +_openapi: + method: GET + route: /files + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Lists project-owned Files without reading their bodies. The limit defaults to 10000 and + must be 1–10000. Equal creation times use ID ordering. Purpose validation precedes cursor + lookup; current storage contains only user_data. An explicit empty purpose is treated as + omitted. Repeated purpose values remain rejected. Hosted positive filtering, default order + and concurrent-page behavior remain unverified. No Beta header is required. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +The limit defaults to 10000 and must be 1–10000. Equal creation times use ID ordering. Purpose validation precedes cursor lookup; current storage contains only user_data. + +An explicit empty purpose is treated as omitted. Repeated purpose values remain rejected. Hosted positive filtering, default order and concurrent-page behavior remain unverified. + +No Beta header is required. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/files/meta.json b/apps/docs/content/docs/api-reference/files/meta.json new file mode 100644 index 000000000..5c734bddc --- /dev/null +++ b/apps/docs/content/docs/api-reference/files/meta.json @@ -0,0 +1,10 @@ +{ + "title": "Files", + "pages": [ + "list-source-files", + "upload-a-source-file", + "retrieve-source-file-metadata", + "delete-a-source-file", + "download-source-file-bytes" + ] +} diff --git a/apps/docs/content/docs/api-reference/files/retrieve-source-file-metadata.mdx b/apps/docs/content/docs/api-reference/files/retrieve-source-file-metadata.mdx new file mode 100644 index 000000000..cfd7e870c --- /dev/null +++ b/apps/docs/content/docs/api-reference/files/retrieve-source-file-metadata.mdx @@ -0,0 +1,22 @@ +--- +title: Retrieve source file metadata +description: Returns immutable project-owned user_data file metadata. +full: true +_openapi: + method: GET + route: /files/{file_id} + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Returns immutable project-owned user_data file metadata. No Beta header is required. Other + purposes, expiration and full hosted status/error semantics remain unimplemented or + unverified. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +No Beta header is required. Other purposes, expiration and full hosted status/error semantics remain unimplemented or unverified. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/files/upload-a-source-file.mdx b/apps/docs/content/docs/api-reference/files/upload-a-source-file.mdx new file mode 100644 index 000000000..64e0beed9 --- /dev/null +++ b/apps/docs/content/docs/api-reference/files/upload-a-source-file.mdx @@ -0,0 +1,29 @@ +--- +title: Upload a source file +description: >- + Accepts one multipart file and purpose=user_data in either order, with a private 512 MiB content + limit and 64 KiB envelope allowance. +full: true +_openapi: + method: POST + route: /files + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Accepts one multipart file and purpose=user_data in either order, with a private 512 MiB + content limit and 64 KiB envelope allowance. Commits only after the entire request + validates. The source is project-owned, independent of Sessions and workspace copies. No + Beta header is required. Other purposes, expires_after, listing, resumable Uploads, + quotas/rate-limit and complete hosted error/status parity remain unsupported or + unverified. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Commits only after the entire request validates. The source is project-owned, independent of Sessions and workspace copies. No Beta header is required. + +Other purposes, expires_after, listing, resumable Uploads, quotas/rate-limit and complete hosted error/status parity remain unsupported or unverified. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/index.mdx b/apps/docs/content/docs/api-reference/index.mdx index e2bee0bf0..eebd3a1d1 100644 --- a/apps/docs/content/docs/api-reference/index.mdx +++ b/apps/docs/content/docs/api-reference/index.mdx @@ -7,18 +7,18 @@ Public schema constrained by the pinned OpenAI Agents API baseline; documented x **Credential:** Project API key. Examples use reserved `example.com` origins. This reference does not send requests or collect credentials. -[API namespaces and credentials](/public-api) · [Application reference](/api-reference) · [Administration reference](/api-reference/core) · [Machine reference](/api-reference/machine) +[API namespaces and credentials](/public-api) · [Application reference](/api-reference) · [Administration reference](/api-reference/core) · [Machine reference](/api-reference/machine) · [Error codes](/error-codes) -- [agents](/api-reference/agents) -- [environments](/api-reference/environments) -- [environment-templates](/api-reference/environment-templates) -- [sessions](/api-reference/sessions) -- [artifacts](/api-reference/artifacts) -- [events](/api-reference/events) -- [items](/api-reference/items) -- [subagents](/api-reference/subagents) -- [turns](/api-reference/turns) -- [files](/api-reference/files) -- [skills](/api-reference/skills) -- [vaults](/api-reference/vaults) -- [credentials](/api-reference/credentials) +- [Agents](/api-reference/agents) · 5 operations +- [Environments](/api-reference/environments) · 3 operations +- [Environment Templates](/api-reference/environment-templates) · 5 operations +- [Sessions](/api-reference/sessions) · 6 operations +- [Artifacts](/api-reference/artifacts) · 4 operations +- [Events](/api-reference/events) · 1 operation +- [Items](/api-reference/items) · 1 operation +- [Subagents](/api-reference/subagents) · 6 operations +- [Turns](/api-reference/turns) · 2 operations +- [Files](/api-reference/files) · 5 operations +- [Skills](/api-reference/skills) · 11 operations +- [Vaults](/api-reference/vaults) · 4 operations +- [Credentials](/api-reference/credentials) · 5 operations diff --git a/apps/docs/content/docs/api-reference/items.mdx b/apps/docs/content/docs/api-reference/items.mdx deleted file mode 100644 index 1c010f4b0..000000000 --- a/apps/docs/content/docs/api-reference/items.mdx +++ /dev/null @@ -1,26 +0,0 @@ ---- -title: Items -description: >- - Items. Application API: Project API key. Public schema constrained by the - pinned OpenAI Agents API baseline; documented x_agents_core fields remain Core - extensions. -full: true -_openapi: - method: GET - route: /agents/sessions/{session_id}/items - toc: [] - structuredData: - headings: [] - contents: - - content: >- - Returns supported message and tool Items in first-observation order. - Native engine fields are projected explicitly; unfinished Items on - terminal Turns are incomplete. Cursors are Items of the same tenant - and Session. Any other after value, including a malformed one, returns - 400 invalid_request_error with the message "Invalid session item ID in - `after`". ---- - -{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} - - \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/items/index.mdx b/apps/docs/content/docs/api-reference/items/index.mdx new file mode 100644 index 000000000..24672480c --- /dev/null +++ b/apps/docs/content/docs/api-reference/items/index.mdx @@ -0,0 +1,10 @@ +--- +title: "Items" +description: "Items. Application API: Project API key." +--- + +Public schema constrained by the pinned OpenAI Agents API baseline; documented x_agents_core fields remain Core extensions. + +| Operation | Method | Path | +| --- | --- | --- | +| [List persisted execution Items](/api-reference/items/list-persisted-execution-items) | `GET` | `/v1/agents/sessions/{session_id}/items` | diff --git a/apps/docs/content/docs/api-reference/items/list-persisted-execution-items.mdx b/apps/docs/content/docs/api-reference/items/list-persisted-execution-items.mdx new file mode 100644 index 000000000..9a910dca8 --- /dev/null +++ b/apps/docs/content/docs/api-reference/items/list-persisted-execution-items.mdx @@ -0,0 +1,23 @@ +--- +title: List persisted execution Items +description: Returns supported message and tool Items in first-observation order. +full: true +_openapi: + method: GET + route: /agents/sessions/{session_id}/items + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Returns supported message and tool Items in first-observation order. Native engine fields + are projected explicitly; unfinished Items on terminal Turns are incomplete. Cursors are + Items of the same tenant and Session. Any other after value, including a malformed one, + returns 400 invalid_request_error with the message "Invalid session item ID in `after`". +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Native engine fields are projected explicitly; unfinished Items on terminal Turns are incomplete. Cursors are Items of the same tenant and Session. Any other after value, including a malformed one, returns 400 invalid_request_error with the message "Invalid session item ID in `after`". + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/items/meta.json b/apps/docs/content/docs/api-reference/items/meta.json new file mode 100644 index 000000000..68e4f83d8 --- /dev/null +++ b/apps/docs/content/docs/api-reference/items/meta.json @@ -0,0 +1,6 @@ +{ + "title": "Items", + "pages": [ + "list-persisted-execution-items" + ] +} diff --git a/apps/docs/content/docs/api-reference/machine/index.mdx b/apps/docs/content/docs/api-reference/machine/index.mdx index a6d699b4d..465b3939e 100644 --- a/apps/docs/content/docs/api-reference/machine/index.mdx +++ b/apps/docs/content/docs/api-reference/machine/index.mdx @@ -7,9 +7,9 @@ Generated local machine contract. These connections reach Core directly, never t **Credential:** Route-specific node enrollment, node, daemon, or executor credential. Examples use reserved `example.com` origins. This reference does not send requests or collect credentials. -This schema covers node configuration, enrollment and identity. Daemon WebSockets and executor connection details are described in the [machine overview](/public-api#machine-connection-api). +This schema covers node configuration, enrollment and identity, and native Runtime installation. Daemon WebSockets and executor connection details are described in the [machine overview](/public-api#machine-connection-api). -[API namespaces and credentials](/public-api) · [Application reference](/api-reference) · [Administration reference](/api-reference/core) · [Machine reference](/api-reference/machine) +[API namespaces and credentials](/public-api) · [Application reference](/api-reference) · [Administration reference](/api-reference/core) · [Machine reference](/api-reference/machine) · [Error codes](/error-codes) -- [native-installation](/api-reference/machine/native-installation) -- [sandbox-node](/api-reference/machine/sandbox-node) +- [Native Installation](/api-reference/machine/native-installation) · 2 operations +- [Sandbox Node](/api-reference/machine/sandbox-node) · 3 operations diff --git a/apps/docs/content/docs/api-reference/machine/meta.json b/apps/docs/content/docs/api-reference/machine/meta.json index 5d07906a3..a35d86c95 100644 --- a/apps/docs/content/docs/api-reference/machine/meta.json +++ b/apps/docs/content/docs/api-reference/machine/meta.json @@ -1,7 +1,6 @@ { "title": "Machine connection API", "pages": [ - "index", "native-installation", "sandbox-node" ] diff --git a/apps/docs/content/docs/api-reference/machine/native-installation.mdx b/apps/docs/content/docs/api-reference/machine/native-installation.mdx deleted file mode 100644 index 80f373a71..000000000 --- a/apps/docs/content/docs/api-reference/machine/native-installation.mdx +++ /dev/null @@ -1,26 +0,0 @@ ---- -title: Native Installation -description: >- - Native Installation. Machine connection API: Route-specific node enrollment, - node, daemon, or executor credential. Generated local machine contract. These - connections reach Core directly, never through Web. -full: true -_openapi: - toc: [] - structuredData: - headings: [] - contents: - - content: >- - Accepts a short-lived Environment installation Bearer authorization, - not a Project or Core key. Returns frozen connection constraints; it - does not claim or rotate credentials. - - content: >- - A valid installation Bearer authorization can claim one connect-only - key. The client persists its generated secret before submitting it. - Retries must present that same secret; a different, rotated or revoked - credential is never replaced. ---- - -{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} - - \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/machine/native-installation/claim-an-environment-s-installation-credential.mdx b/apps/docs/content/docs/api-reference/machine/native-installation/claim-an-environment-s-installation-credential.mdx new file mode 100644 index 000000000..7bcbf9f70 --- /dev/null +++ b/apps/docs/content/docs/api-reference/machine/native-installation/claim-an-environment-s-installation-credential.mdx @@ -0,0 +1,22 @@ +--- +title: Claim an Environment's installation credential +description: A valid installation Bearer authorization can claim one connect-only key. +full: true +_openapi: + method: POST + route: /api/v1/agent-daemon/installation/claim + toc: [] + structuredData: + headings: [] + contents: + - content: >- + A valid installation Bearer authorization can claim one connect-only key. The client + persists its generated secret before submitting it. Retries must present that same secret; + a different, rotated or revoked credential is never replaced. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +The client persists its generated secret before submitting it. Retries must present that same secret; a different, rotated or revoked credential is never replaced. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/machine/native-installation/index.mdx b/apps/docs/content/docs/api-reference/machine/native-installation/index.mdx new file mode 100644 index 000000000..e4fbbe1c3 --- /dev/null +++ b/apps/docs/content/docs/api-reference/machine/native-installation/index.mdx @@ -0,0 +1,11 @@ +--- +title: "Native Installation" +description: "Native Installation. Machine connection API: Route-specific node enrollment, node, daemon, or executor credential." +--- + +Generated local machine contract. These connections reach Core directly, never through Web. + +| Operation | Method | Path | +| --- | --- | --- | +| [Resolve a native installation authorization](/api-reference/machine/native-installation/resolve-a-native-installation-authorization) | `POST` | `/api/v1/agent-daemon/installation` | +| [Claim an Environment's installation credential](/api-reference/machine/native-installation/claim-an-environment-s-installation-credential) | `POST` | `/api/v1/agent-daemon/installation/claim` | diff --git a/apps/docs/content/docs/api-reference/machine/native-installation/meta.json b/apps/docs/content/docs/api-reference/machine/native-installation/meta.json new file mode 100644 index 000000000..0cd526bdd --- /dev/null +++ b/apps/docs/content/docs/api-reference/machine/native-installation/meta.json @@ -0,0 +1,7 @@ +{ + "title": "Native Installation", + "pages": [ + "resolve-a-native-installation-authorization", + "claim-an-environment-s-installation-credential" + ] +} diff --git a/apps/docs/content/docs/api-reference/machine/native-installation/resolve-a-native-installation-authorization.mdx b/apps/docs/content/docs/api-reference/machine/native-installation/resolve-a-native-installation-authorization.mdx new file mode 100644 index 000000000..77ccab6f3 --- /dev/null +++ b/apps/docs/content/docs/api-reference/machine/native-installation/resolve-a-native-installation-authorization.mdx @@ -0,0 +1,21 @@ +--- +title: Resolve a native installation authorization +description: Accepts a short-lived Environment installation Bearer authorization, not a Project or Core key. +full: true +_openapi: + method: POST + route: /api/v1/agent-daemon/installation + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Accepts a short-lived Environment installation Bearer authorization, not a Project or Core + key. Returns frozen connection constraints; it does not claim or rotate credentials. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Returns frozen connection constraints; it does not claim or rotate credentials. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/machine/sandbox-node.mdx b/apps/docs/content/docs/api-reference/machine/sandbox-node.mdx deleted file mode 100644 index 7ab0fde2a..000000000 --- a/apps/docs/content/docs/api-reference/machine/sandbox-node.mdx +++ /dev/null @@ -1,31 +0,0 @@ ---- -title: Sandbox Node -description: >- - Sandbox Node. Machine connection API: Route-specific node enrollment, node, - daemon, or executor credential. Generated local machine contract. These - connections reach Core directly, never through Web. -full: true -_openapi: - toc: [] - structuredData: - headings: [] - contents: - - content: >- - Authenticates with an unconsumed enrollment token, or a retained node - credential with X-OAC-Node-ID. Does not consume the token or expose - E2B credentials. Node files cannot override this specification. - - content: >- - Node machine connection. Consumes a one-use enrollment token; grants - no project or administrator access. Responses contain only explicit - safe fields. core_url is required and must equal the installation - public URL; a different address gets 409 sandbox_node_address_mismatch - and leaves the token unused. - - content: >- - Node machine connection. Authenticates with the retained node - credential; grants no project or administrator access. Responses - contain only explicit safe fields. ---- - -{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} - - \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/machine/sandbox-node/enroll-a-sandbox-node.mdx b/apps/docs/content/docs/api-reference/machine/sandbox-node/enroll-a-sandbox-node.mdx new file mode 100644 index 000000000..eb47fb22f --- /dev/null +++ b/apps/docs/content/docs/api-reference/machine/sandbox-node/enroll-a-sandbox-node.mdx @@ -0,0 +1,25 @@ +--- +title: Enroll a sandbox node +description: >- + Node machine connection. Consumes a one-use enrollment token; grants no project or administrator + access. +full: true +_openapi: + method: POST + route: /api/v1/sandbox-node/enroll + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Node machine connection. Consumes a one-use enrollment token; grants no project or + administrator access. Responses contain only explicit safe fields. core_url is required + and must equal the installation public URL; a different address gets 409 + sandbox_node_address_mismatch and leaves the token unused. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Responses contain only explicit safe fields. core_url is required and must equal the installation public URL; a different address gets 409 sandbox_node_address_mismatch and leaves the token unused. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/machine/sandbox-node/index.mdx b/apps/docs/content/docs/api-reference/machine/sandbox-node/index.mdx new file mode 100644 index 000000000..ccde17e60 --- /dev/null +++ b/apps/docs/content/docs/api-reference/machine/sandbox-node/index.mdx @@ -0,0 +1,12 @@ +--- +title: "Sandbox Node" +description: "Sandbox Node. Machine connection API: Route-specific node enrollment, node, daemon, or executor credential." +--- + +Generated local machine contract. These connections reach Core directly, never through Web. + +| Operation | Method | Path | +| --- | --- | --- | +| [Read the active configuration for node installation](/api-reference/machine/sandbox-node/read-the-active-configuration-for-node-installation) | `GET` | `/api/v1/sandbox-node/configuration` | +| [Enroll a sandbox node](/api-reference/machine/sandbox-node/enroll-a-sandbox-node) | `POST` | `/api/v1/sandbox-node/enroll` | +| [Recover an enrolled sandbox node identity and observe its readiness](/api-reference/machine/sandbox-node/recover-an-enrolled-sandbox-node-identity-and-observe-its-readiness) | `GET` | `/api/v1/sandbox-node/identity` | diff --git a/apps/docs/content/docs/api-reference/machine/sandbox-node/meta.json b/apps/docs/content/docs/api-reference/machine/sandbox-node/meta.json new file mode 100644 index 000000000..eb0ad0124 --- /dev/null +++ b/apps/docs/content/docs/api-reference/machine/sandbox-node/meta.json @@ -0,0 +1,8 @@ +{ + "title": "Sandbox Node", + "pages": [ + "read-the-active-configuration-for-node-installation", + "enroll-a-sandbox-node", + "recover-an-enrolled-sandbox-node-identity-and-observe-its-readiness" + ] +} diff --git a/apps/docs/content/docs/api-reference/machine/sandbox-node/read-the-active-configuration-for-node-installation.mdx b/apps/docs/content/docs/api-reference/machine/sandbox-node/read-the-active-configuration-for-node-installation.mdx new file mode 100644 index 000000000..cdcc2791c --- /dev/null +++ b/apps/docs/content/docs/api-reference/machine/sandbox-node/read-the-active-configuration-for-node-installation.mdx @@ -0,0 +1,24 @@ +--- +title: Read the active configuration for node installation +description: >- + Authenticates with an unconsumed enrollment token, or a retained node credential with + X-OAC-Node-ID. +full: true +_openapi: + method: GET + route: /api/v1/sandbox-node/configuration + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Authenticates with an unconsumed enrollment token, or a retained node credential with + X-OAC-Node-ID. Does not consume the token or expose E2B credentials. Node files cannot + override this specification. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Does not consume the token or expose E2B credentials. Node files cannot override this specification. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/machine/sandbox-node/recover-an-enrolled-sandbox-node-identity-and-observe-its-readiness.mdx b/apps/docs/content/docs/api-reference/machine/sandbox-node/recover-an-enrolled-sandbox-node-identity-and-observe-its-readiness.mdx new file mode 100644 index 000000000..5e14b5fe1 --- /dev/null +++ b/apps/docs/content/docs/api-reference/machine/sandbox-node/recover-an-enrolled-sandbox-node-identity-and-observe-its-readiness.mdx @@ -0,0 +1,23 @@ +--- +title: Recover an enrolled sandbox node identity and observe its readiness +description: >- + Node machine connection. Authenticates with the retained node credential; grants no project or + administrator access. +full: true +_openapi: + method: GET + route: /api/v1/sandbox-node/identity + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Node machine connection. Authenticates with the retained node credential; grants no + project or administrator access. Responses contain only explicit safe fields. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Responses contain only explicit safe fields. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/meta.json b/apps/docs/content/docs/api-reference/meta.json index f96a25397..9e23f4fae 100644 --- a/apps/docs/content/docs/api-reference/meta.json +++ b/apps/docs/content/docs/api-reference/meta.json @@ -1,7 +1,6 @@ { "title": "Application API", "pages": [ - "index", "agents", "environments", "environment-templates", diff --git a/apps/docs/content/docs/api-reference/sessions.mdx b/apps/docs/content/docs/api-reference/sessions.mdx deleted file mode 100644 index 011a38b27..000000000 --- a/apps/docs/content/docs/api-reference/sessions.mdx +++ /dev/null @@ -1,246 +0,0 @@ ---- -title: Sessions -description: >- - Sessions. Application API: Project API key. Public schema constrained by the - pinned OpenAI Agents API baseline; documented x_agents_core fields remain Core - extensions. -full: true -_openapi: - toc: [] - structuredData: - headings: [] - contents: - - content: >- - Cursor and results are scoped to the authenticated execution tenant; - an unknown, malformed or foreign after cursor returns not found. - Optional agent_id matches the immutable root Agent ID, including - inline Agents and historical Sessions whose saved source was updated - or deleted. Omission lists all Agents. Returns the same Environment - and pending-input activity projection as Session retrieval, including - self_hosted Sessions. - - content: >- - The optional Core model_provider bundle resolves from the Session - override, saved Agent defaults, then, for openai_hosted and none, the - deployment default of the resolved harness; self_hosted never uses the - deployment default and none accepts only it. openai_hosted and - self_hosted Sessions that resolve no bundle return 400 - model_provider_required with param x_agents_core.model_provider before - any write. Core encrypts and freezes the resolved bundle; later Agent - or deployment default edits and same-key retries cannot change it. - Keys are never returned. Supports inline configuration or a - tenant-owned saved agent_id with per-Session field replacements. - Execution supports model/instructions, text verbosity, non-deferred - function tools, adapter-qualified multi_agent with persisted Subagent - reads, implicit reasoning, service tier auto and environment type - none, subject to the configured engine. Codex additionally supports - HTTP MCP with service origin (omitted or null on HTTP transport is - saved as service), native allowed_tools and boolean required - defaulting to false. Session vault_ids attach only project-owned - Vaults; credential_id selects an attached static bearer or OAuth - credential for the exact HTTPS URL, while null/omission selects a - unique match or remains anonymous. Session reads, lists and event - snapshots show that implicitly selected credential ID in a null or - omitted credential_id, also after the credential is deleted; anonymous - selections stay null and the stored caller intent is unchanged. After - the input requirement and before any write, a credential_id without - vault_ids, one outside the attached Vaults (one message for missing, - foreign and unattached IDs) or one for another server_url returns 400 - invalid_request_error, and several implicit matches return 409 - conflict_error. Missing decryption configuration fails dispatch - without anonymous fallback. Required initialization uses native - startup before the first native Turn, including cold resume, and - requires a separately advertised capability; exact hosted creation - timing and error parity remain unverified. Other MCP origins and - native OAuth login remain unsupported. The self_hosted profile uses a - qualified native harness, a clean absolute workspace_directory and - optional absolute local capability_directories prepared by Runtime, - with optional non-deferred function tools and HTTP MCP using service - origin, optionally authenticated by the attached Vault rules. Remote - MCP and remote Bearer authentication each require separately - advertised combination support; old peers cannot receive unsupported - work. Omitted/null capability_directories use the empty-list default; - self_hosted requires configured execution plus executor registry. - Claude SDK currently requires medium verbosity and object-root - function schemas. It supports anonymous or attached static-bearer - service-origin HTTP MCP on none with boolean required and separately - advertised MCP/bearer/required runtime support. Required servers must - be connected before the first native input is released; pending or - failed startup rejects execution. The shared Vault selection and - immutable binding rules apply; unsupported native labels/tool names - reject before persistence. An attached Vault with no matching - credential may remain anonymous; missing keys or failed credential - lookup/decryption never fall back to anonymous execution. Omitted - stream defaults to false; stream and agent_id cannot be null. Metadata - may be null; non-string values and limit violations return - invalid_request_error with a metadata or metadata. param. The - inline agent uses the Agent create configuration validation with - agent.-prefixed params, reported before the input requirement and - saved-Agent lookup; saved configurations with conflicting tools or - schema roots reject admission with the same errors, and execution - limits keep unsupported_or_invalid_configuration. Hosted network - policy rejections return invalid_request_error with a null param. - Initial input accepts a string or ordered user-message array. Codex - and Claude SDK on none and qualified managed or self_hosted workspace - profiles also accept inline PNG/JPEG image content; other image - combinations and remote URLs are unsupported. None initial input - atomically starts a Turn; self_hosted initial input is reserved while - returning its Environment connection target, with execution deferred - to native readiness and Session failure on initial timeout. Initial - input is required for none and for streamed creation outside - self_hosted. Omitted/null input remains valid for non-streaming hosted - and self_hosted creation. With stream=true, returns live Session - events starting with the committed creation snapshot and closes right - after the first agent.session.idle recorded when a Turn ends or an - input reservation stops being pending, or any agent.session.failed, - without sending later events. A creation that admitted nothing closes - after the snapshot; a settlement that records no event closes after - events up to the cursor read with a settled Session projection. - Required actions keep it open; disconnect does not cancel execution. - The GET events stream remains live-only. New Sessions retain their - authenticated creator; all creation retries require the same typed - subject, including across key rotation. Saved-Agent retries and inline - requests using Vault attachments or credential references retain - caller intent independently of later resource changes; new hosted - inline requests also freeze caller intent before deployment defaults - resolve; unrelated non-hosted inline retries preserve resolved/default - equivalences, and their resolved hash leaves out any deployment - default. Provider keys enter retry hashes only as fingerprints keyed - by the credential key. Unknown historical creators reject retries; - known creators without recorded intent retain resolved-snapshot retry - rules. These conflict policies are local and not verified hosted - parity. A same-key stream=true retry of an existing creation returns - 201 with no events and closes at once; retry with stream=false or use - the GET events stream to recover. Claude SDK on none, Core-managed - Docker openai_hosted and self_hosted supports qualified object-root - json_schema output with medium verbosity, single-Agent execution and - ordinary functions. Hosted execution reuses native workspace tools and - Files/Artifacts; Skills, Plugins, capability directories, HTTP MCP, - Subagent and tool_search combinations remain unqualified, including - inherited template contents. Other non-text initial input remains - unsupported. Basic Codex and Claude SDK openai_hosted creation - requires an explicitly configured managed provider. The Claude - workspace profile supports non-deferred function tools with text or - successful inline PNG/JPEG results alongside native workspace tools; - HTTP MCP remains unsupported. Idle Sessions provision automatically; - initial provisioning has no caller connection action. Network defaults - to enabled; disabled and restricted policies reject before compute - allocation because the current Runtime cannot enforce them. The - x_agents_core.environment extension accepts common preparation fields - for either hosted or self-hosted placement: environment_template_id, - files, env, packages, setup_commands, skills, plugins and - capability_directories. Duplicate fields in environment and the - extension reject. Confidential env, npm/Python packages and ordered - setup commands use the same Environment-owned initialization - lifecycle; compute allocation does not own preparation. Unknown side - effects are not replayed after disconnect or restart. System - dependencies must be preinstalled in the sandbox image or template, or - on the host machine; packages.system is rejected. Initial inline and - tenant-owned file_id files freeze encrypted bytes before provisioning, - then install through the common Core lifecycle before native execution - or live Files access. With a template reference, omitted/null files, - env, packages and setup_commands inherit. Non-null files and command - lists replace; env overlays by key; each package manager inherits on - omission/null and otherwise replaces its list. Empty lists clear their - selected field. Tenant-owned environment_template_id references - inherit omitted/null network and allow only narrowing overrides. - Inline hosted network:null retains the enabled default; updating a - Template with network:null resets its saved policy to enabled. Core - freezes effective configuration; template updates/deletion do not - alter Session snapshots or same-intent creation retries. Inline or - tenant-owned skill_reference Skills share initialization. Templates - preserve default/latest/explicit selectors; Session creation freezes - concrete metadata and encrypted content atomically. Skill, Plugin and - capability-directory list omission/null inherit; a non-null list - replaces, including empty-list clearing. Omitted/null Skill version - selectors resolve the default version. Source deletion/default updates - cannot change committed Session Skill contents. Deferred function - discovery uses type-only tool_search and per-function defer_loading in - the qualified single-agent Claude function profile on none or a - managed/user-owned workspace, including qualified inline image - messages and text results. Explicit web_search mode disabled and - programmatic_tool_calling enabled false use frozen common Runtime - controls. Enabled forms, including those saved on an Agent, remain - unqualified and reject before any write unless the Session replaces - tools. Omitted programmatic configuration preserves native behavior, a - documented difference from the official default-on behavior. Other - combinations remain unqualified; see the operation coverage. - - content: >- - Returns supported none, self_hosted and basic openai_hosted Session - environments. Self-hosted pending input can require a caller - connection before a Turn exists. Hosted initial provisioning remains - idle until a Turn starts; connection observations are not native - execution readiness. - - content: >- - The metadata field is required in an update body. Send null or {} to - clear it, or supply an object to replace all pairs. Up to 16 string - pairs, with keys at most 64 characters and values at most 512 - characters; violations and non-string values return - invalid_request_error with a metadata or metadata. param. U+0000 - is rejected as a local storage limit. Malformed, missing and foreign - Session IDs share the not-found response. Execution configuration and - activity are unchanged. Returns the same safe Environment and - pending-input activity projection as Session retrieval. - - content: >- - Removes a durably idle or failed Session and its history from the - public API. A Session whose root Turn is queued, in progress or - waiting (including required actions) or whose input reservation is - pending returns 409 conflict_error and is left unchanged; cancel it - and wait until it is idle before deleting. Subagent child Turns and - pending Environment file writes are not checked and do not block - deletion. Repeating the deletion of the caller's own deleted Session - returns the same confirmation; missing and foreign Sessions return - 404. Internal records and native history are retained pending separate - physical cleanup; overlapping stream timing remains unverified. - - content: >- - An empty events array is a resource-authorized no-op; it creates no - execution retry identity, Turn, Item or input receipt. For environment - none, atomically accepts text messages, cancellation and function - results. Messages steer active work or start a queued Turn. Qualified - Codex and Claude SDK workspace profiles accept text and inline - PNG/JPEG messages, independently of managed or self_hosted ownership. - Under the Session lock, matching retries retain their original target; - new active messages append to the current Turn, while idle messages - reserve work and wait up to the original five-minute - connection/admission deadline. Return 202 only after durable - admission, without claiming native application; active messages create - no Turn or reservation. Cancellation-only prepared-environment batches - use existing durable cancellation admission and return 202 without - waiting for native exit; a new cancellation conflicts while a pre-Turn - reservation is pending. Homogeneous tool_result-only - prepared-environment batches reuse existing scoped result admission - and application receipts without creating a Turn or bypassing a - pending reservation. Mixed prepared-environment batches remain - unsupported. HTTP expiry/cancellation use local 409 - environment_input_expired/environment_input_cancelled errors. New - input on a Session whose hosted Environment failed to provision - returns the observed 409 conflict_error "the hosted environment failed - to provision"; input already waiting when it fails and expired - Environments keep the local 409 environment_unavailable. Input the - Session cannot accept in its current state, such as a result after - cancellation or a batch while earlier input is pending, and a result - that differs from the call's saved result return 409 with type and - code conflict_error; reusing an Idempotency-Key with a different batch - returns the local 409 idempotency_conflict. Inside an owned Session, a - result for an unknown call or for a call of another Turn returns 400 - invalid_request_error and changes nothing; missing and foreign - Sessions return 404. Losing execution ownership returns 503. The - response write deadline accommodates the admission window for either - prepared Environment, independently of new-hosted-admission and - executor URL settings. Disconnecting the waiting HTTP request does not - cancel retained work or restart its deadline. Retry keys identify the - whole ordered batch. Function output accepts text or ordered - text/image parts subject to engine support; Claude SDK accepts text - results and, on none and qualified workspace profiles, successful - inline PNG/JPEG results, preserving ordered content; error images and - remote references reject before admission. Native image resizing may - change bytes. Runtime image-result support is checked only for - image-bearing delivery. Codex and Claude SDK on none and qualified - managed or self_hosted workspace profiles accept ordered inline - PNG/JPEG image messages. Other engines remain text-only; remote image - URLs are unsupported. Image references are retained unchanged without - service-side downloads. ---- - -{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} - - \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/sessions/create-an-execution-session.mdx b/apps/docs/content/docs/api-reference/sessions/create-an-execution-session.mdx new file mode 100644 index 000000000..c57e6f95d --- /dev/null +++ b/apps/docs/content/docs/api-reference/sessions/create-an-execution-session.mdx @@ -0,0 +1,185 @@ +--- +title: Create an execution Session +description: >- + The optional Core model_provider bundle resolves from the Session override, saved Agent defaults, + then, for openai_hosted and none, the deployment default of the resolved harness; self_hosted + never uses the deployment default and none accepts only it. openai_hosted and self_hosted Sessions + that resolve no bundle return 400 model_provider_required with param x_agents_core.model_provider + before any write. +full: true +_openapi: + method: POST + route: /agents/sessions + toc: [] + structuredData: + headings: [] + contents: + - content: >- + The optional Core model_provider bundle resolves from the Session override, saved Agent + defaults, then, for openai_hosted and none, the deployment default of the resolved + harness; self_hosted never uses the deployment default and none accepts only it. + openai_hosted and self_hosted Sessions that resolve no bundle return 400 + model_provider_required with param x_agents_core.model_provider before any write. Core + encrypts and freezes the resolved bundle; later Agent or deployment default edits and + same-key retries cannot change it. Keys are never returned. Supports inline configuration + or a tenant-owned saved agent_id with per-Session field replacements. Execution supports + model/instructions, text verbosity, non-deferred function tools, adapter-qualified + multi_agent with persisted Subagent reads, implicit reasoning, service tier auto and + environment type none, subject to the configured engine. Codex additionally supports HTTP + MCP with service origin (omitted or null on HTTP transport is saved as service), native + allowed_tools and boolean required defaulting to false. Session vault_ids attach only + project-owned Vaults; credential_id selects an attached static bearer or OAuth credential + for the exact HTTPS URL, while null/omission selects a unique match or remains anonymous. + Session reads, lists and event snapshots show that implicitly selected credential ID in a + null or omitted credential_id, also after the credential is deleted; anonymous selections + stay null and the stored caller intent is unchanged. After the input requirement and + before any write, a credential_id without vault_ids, one outside the attached Vaults (one + message for missing, foreign and unattached IDs) or one for another server_url returns 400 + invalid_request_error, and several implicit matches return 409 conflict_error. Missing + decryption configuration fails dispatch without anonymous fallback. Required + initialization uses native startup before the first native Turn, including cold resume, + and requires a separately advertised capability; exact hosted creation timing and error + parity remain unverified. Other MCP origins and native OAuth login remain unsupported. The + self_hosted profile uses a qualified native harness, a clean absolute workspace_directory + and optional absolute local capability_directories prepared by Runtime, with optional + non-deferred function tools and HTTP MCP using service origin, optionally authenticated by + the attached Vault rules. Remote MCP and remote Bearer authentication each require + separately advertised combination support; old peers cannot receive unsupported work. + Omitted/null capability_directories use the empty-list default; self_hosted requires + configured execution plus executor registry. Claude SDK currently requires medium + verbosity and object-root function schemas. It supports anonymous or attached + static-bearer service-origin HTTP MCP on none with boolean required and separately + advertised MCP/bearer/required runtime support. Required servers must be connected before + the first native input is released; pending or failed startup rejects execution. The + shared Vault selection and immutable binding rules apply; unsupported native labels/tool + names reject before persistence. An attached Vault with no matching credential may remain + anonymous; missing keys or failed credential lookup/decryption never fall back to + anonymous execution. Omitted stream defaults to false; stream and agent_id cannot be null. + Metadata may be null; non-string values and limit violations return invalid_request_error + with a metadata or metadata. param. The inline agent uses the Agent create + configuration validation with agent.-prefixed params, reported before the input + requirement and saved-Agent lookup; saved configurations with conflicting tools or schema + roots reject admission with the same errors, and execution limits keep + unsupported_or_invalid_configuration. Hosted network policy rejections return + invalid_request_error with a null param. Initial input accepts a string or ordered + user-message array. Codex and Claude SDK on none and qualified openai_hosted also accept + inline PNG/JPEG image content; other image combinations and remote URLs are unsupported. + None initial input atomically starts a Turn; self_hosted initial input is reserved while + returning its Environment connection target, with execution deferred to native readiness + and Session failure on initial timeout. Initial input is required for none and for + streamed creation outside self_hosted. Omitted/null input remains valid for non-streaming + hosted and self_hosted creation. With stream=true, returns live Session events starting + with the committed creation snapshot and closes right after the first agent.session.idle + recorded when a Turn ends or an input reservation stops being pending, or any + agent.session.failed, without sending later events. A creation that admitted nothing + closes after the snapshot; a settlement that records no event closes after events up to + the cursor read with a settled Session projection. Required actions keep it open; + disconnect does not cancel execution. The GET events stream remains live-only. New + Sessions retain their authenticated creator; all creation retries require the same typed + subject, including across key rotation. Saved-Agent retries and inline requests using + Vault attachments or credential references retain caller intent independently of later + resource changes; new hosted inline requests also freeze caller intent before deployment + defaults resolve; unrelated non-hosted inline retries preserve resolved/default + equivalences, and their resolved hash leaves out any deployment default. Provider keys + enter retry hashes only as fingerprints keyed by the credential key. Unknown historical + creators reject retries; known creators without recorded intent retain resolved-snapshot + retry rules. These conflict policies are local and not verified hosted parity. A same-key + stream=true retry of an existing creation returns 201 with no events and closes at once; + retry with stream=false or use the GET events stream to recover. Claude SDK on none and + Core-managed Docker openai_hosted supports qualified object-root json_schema output with + medium verbosity, single-Agent execution and ordinary functions. Hosted execution reuses + native workspace tools and Files/Artifacts; Skills, Plugins, capability directories, HTTP + MCP, Subagent and tool_search combinations remain unqualified, including inherited + template contents. Other non-text initial input remains unsupported. Basic Codex and + Claude SDK openai_hosted creation requires an explicitly configured managed provider. The + Claude workspace profile supports non-deferred function tools with text or successful + inline PNG/JPEG results alongside native workspace tools; HTTP MCP remains unsupported. + Idle Sessions provision automatically; initial provisioning has no caller connection + action. Network defaults to enabled; disabled and restricted policies reject before + compute allocation because the current Runtime cannot enforce them. The + x_agents_core.environment extension accepts common preparation fields for either hosted or + self-hosted placement: environment_template_id, files, env, packages, setup_commands, + skills, plugins and capability_directories. Duplicate fields in environment and the + extension reject. Confidential env, npm/Python packages and ordered setup commands use the + same Environment-owned initialization lifecycle; compute allocation does not own + preparation. Unknown side effects are not replayed after disconnect or restart. System + dependencies must be preinstalled in the sandbox image or template, or on the host + machine; packages.system is rejected. Initial inline and tenant-owned file_id files freeze + encrypted bytes before provisioning, then install through the common Core lifecycle before + native execution or live Files access. With a template reference, omitted/null files, env, + packages and setup_commands inherit. Non-null files and command lists replace; env + overlays by key; each package manager inherits on omission/null and otherwise replaces its + list. Empty lists clear their selected field. Tenant-owned environment_template_id + references inherit omitted/null network and allow only narrowing overrides. Inline hosted + network:null retains the enabled default; updating a Template with network:null resets its + saved policy to enabled. Core freezes effective configuration; template updates/deletion + do not alter Session snapshots or same-intent creation retries. Inline or tenant-owned + skill_reference Skills share initialization. Templates preserve default/latest/explicit + selectors; Session creation freezes concrete metadata and encrypted content atomically. + Skill, Plugin and capability-directory list omission/null inherit; a non-null list + replaces, including empty-list clearing. Omitted/null Skill version selectors resolve the + default version. Source deletion/default updates cannot change committed Session Skill + contents. Deferred function discovery uses type-only tool_search and per-function + defer_loading in the qualified single-agent Claude environment:none function profile, + including qualified inline image messages and text results. Explicit web_search mode + disabled and programmatic_tool_calling enabled false use frozen common Runtime controls. + Enabled forms, including those saved on an Agent, remain unqualified and reject before any + write unless the Session replaces tools. Omitted programmatic configuration preserves + native behavior, a documented difference from the official default-on behavior. Other + combinations remain unqualified; see the operation coverage. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +
+Full description + +Core encrypts and freezes the resolved bundle; later Agent or deployment default edits and same-key retries cannot change it. Keys are never returned. Supports inline configuration or a tenant-owned saved agent_id with per-Session field replacements. + +Execution supports model/instructions, text verbosity, non-deferred function tools, adapter-qualified multi_agent with persisted Subagent reads, implicit reasoning, service tier auto and environment type none, subject to the configured engine. Codex additionally supports HTTP MCP with service origin (omitted or null on HTTP transport is saved as service), native allowed_tools and boolean required defaulting to false. Session vault_ids attach only project-owned Vaults; credential_id selects an attached static bearer or OAuth credential for the exact HTTPS URL, while null/omission selects a unique match or remains anonymous. + +Session reads, lists and event snapshots show that implicitly selected credential ID in a null or omitted credential_id, also after the credential is deleted; anonymous selections stay null and the stored caller intent is unchanged. After the input requirement and before any write, a credential_id without vault_ids, one outside the attached Vaults (one message for missing, foreign and unattached IDs) or one for another server_url returns 400 invalid_request_error, and several implicit matches return 409 conflict_error. Missing decryption configuration fails dispatch without anonymous fallback. + +Required initialization uses native startup before the first native Turn, including cold resume, and requires a separately advertised capability; exact hosted creation timing and error parity remain unverified. Other MCP origins and native OAuth login remain unsupported. The self_hosted profile uses a qualified native harness, a clean absolute workspace_directory and optional absolute local capability_directories prepared by Runtime, with optional non-deferred function tools and HTTP MCP using service origin, optionally authenticated by the attached Vault rules. + +Remote MCP and remote Bearer authentication each require separately advertised combination support; old peers cannot receive unsupported work. Omitted/null capability_directories use the empty-list default; self_hosted requires configured execution plus executor registry. Claude SDK currently requires medium verbosity and object-root function schemas. + +It supports anonymous or attached static-bearer service-origin HTTP MCP on none with boolean required and separately advertised MCP/bearer/required runtime support. Required servers must be connected before the first native input is released; pending or failed startup rejects execution. The shared Vault selection and immutable binding rules apply; unsupported native labels/tool names reject before persistence. + +An attached Vault with no matching credential may remain anonymous; missing keys or failed credential lookup/decryption never fall back to anonymous execution. Omitted stream defaults to false; stream and agent_id cannot be null. Metadata may be null; non-string values and limit violations return invalid_request_error with a metadata or metadata.<key> param. + +The inline agent uses the Agent create configuration validation with agent.-prefixed params, reported before the input requirement and saved-Agent lookup; saved configurations with conflicting tools or schema roots reject admission with the same errors, and execution limits keep unsupported_or_invalid_configuration. Hosted network policy rejections return invalid_request_error with a null param. Initial input accepts a string or ordered user-message array. + +Codex and Claude SDK on none and qualified openai_hosted also accept inline PNG/JPEG image content; other image combinations and remote URLs are unsupported. None initial input atomically starts a Turn; self_hosted initial input is reserved while returning its Environment connection target, with execution deferred to native readiness and Session failure on initial timeout. Initial input is required for none and for streamed creation outside self_hosted. + +Omitted/null input remains valid for non-streaming hosted and self_hosted creation. With stream=true, returns live Session events starting with the committed creation snapshot and closes right after the first agent.session.idle recorded when a Turn ends or an input reservation stops being pending, or any agent.session.failed, without sending later events. A creation that admitted nothing closes after the snapshot; a settlement that records no event closes after events up to the cursor read with a settled Session projection. + +Required actions keep it open; disconnect does not cancel execution. The GET events stream remains live-only. New Sessions retain their authenticated creator; all creation retries require the same typed subject, including across key rotation. + +Saved-Agent retries and inline requests using Vault attachments or credential references retain caller intent independently of later resource changes; new hosted inline requests also freeze caller intent before deployment defaults resolve; unrelated non-hosted inline retries preserve resolved/default equivalences, and their resolved hash leaves out any deployment default. Provider keys enter retry hashes only as fingerprints keyed by the credential key. Unknown historical creators reject retries; known creators without recorded intent retain resolved-snapshot retry rules. + +These conflict policies are local and not verified hosted parity. A same-key stream=true retry of an existing creation returns 201 with no events and closes at once; retry with stream=false or use the GET events stream to recover. Claude SDK on none and Core-managed Docker openai_hosted supports qualified object-root json_schema output with medium verbosity, single-Agent execution and ordinary functions. + +Hosted execution reuses native workspace tools and Files/Artifacts; Skills, Plugins, capability directories, HTTP MCP, Subagent and tool_search combinations remain unqualified, including inherited template contents. Other non-text initial input remains unsupported. Basic Codex and Claude SDK openai_hosted creation requires an explicitly configured managed provider. + +The Claude workspace profile supports non-deferred function tools with text or successful inline PNG/JPEG results alongside native workspace tools; HTTP MCP remains unsupported. Idle Sessions provision automatically; initial provisioning has no caller connection action. Network defaults to enabled; disabled and restricted policies reject before compute allocation because the current Runtime cannot enforce them. + +The x_agents_core.environment extension accepts common preparation fields for either hosted or self-hosted placement: environment_template_id, files, env, packages, setup_commands, skills, plugins and capability_directories. Duplicate fields in environment and the extension reject. Confidential env, npm/Python packages and ordered setup commands use the same Environment-owned initialization lifecycle; compute allocation does not own preparation. + +Unknown side effects are not replayed after disconnect or restart. System dependencies must be preinstalled in the sandbox image or template, or on the host machine; packages.system is rejected. Initial inline and tenant-owned file_id files freeze encrypted bytes before provisioning, then install through the common Core lifecycle before native execution or live Files access. + +With a template reference, omitted/null files, env, packages and setup_commands inherit. Non-null files and command lists replace; env overlays by key; each package manager inherits on omission/null and otherwise replaces its list. Empty lists clear their selected field. + +Tenant-owned environment_template_id references inherit omitted/null network and allow only narrowing overrides. Inline hosted network:null retains the enabled default; updating a Template with network:null resets its saved policy to enabled. Core freezes effective configuration; template updates/deletion do not alter Session snapshots or same-intent creation retries. + +Inline or tenant-owned skill_reference Skills share initialization. Templates preserve default/latest/explicit selectors; Session creation freezes concrete metadata and encrypted content atomically. Skill, Plugin and capability-directory list omission/null inherit; a non-null list replaces, including empty-list clearing. + +Omitted/null Skill version selectors resolve the default version. Source deletion/default updates cannot change committed Session Skill contents. Deferred function discovery uses type-only tool_search and per-function defer_loading in the qualified single-agent Claude environment:none function profile, including qualified inline image messages and text results. + +Explicit web_search mode disabled and programmatic_tool_calling enabled false use frozen common Runtime controls. Enabled forms, including those saved on an Agent, remain unqualified and reject before any write unless the Session replaces tools. Omitted programmatic configuration preserves native behavior, a documented difference from the official default-on behavior. + +Other combinations remain unqualified; see the operation coverage. + +
+ + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/sessions/delete-an-execution-session.mdx b/apps/docs/content/docs/api-reference/sessions/delete-an-execution-session.mdx new file mode 100644 index 000000000..8955f330b --- /dev/null +++ b/apps/docs/content/docs/api-reference/sessions/delete-an-execution-session.mdx @@ -0,0 +1,34 @@ +--- +title: Delete an execution Session +description: Removes a durably idle or failed Session and its history from the public API. +full: true +_openapi: + method: DELETE + route: /agents/sessions/{session_id} + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Removes a durably idle or failed Session and its history from the public API. A Session + whose root Turn is queued, in progress or waiting (including required actions) or whose + input reservation is pending returns 409 conflict_error and is left unchanged; cancel it + and wait until it is idle before deleting. Subagent child Turns and pending Environment + file writes are not checked and do not block deletion. Repeating the deletion of the + caller's own deleted Session returns the same confirmation; missing and foreign Sessions + return 404. Internal records and native history are retained pending separate physical + cleanup; overlapping stream timing remains unverified. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +
+Full description + +A Session whose root Turn is queued, in progress or waiting (including required actions) or whose input reservation is pending returns 409 conflict_error and is left unchanged; cancel it and wait until it is idle before deleting. Subagent child Turns and pending Environment file writes are not checked and do not block deletion. Repeating the deletion of the caller's own deleted Session returns the same confirmation; missing and foreign Sessions return 404. + +Internal records and native history are retained pending separate physical cleanup; overlapping stream timing remains unverified. + +
+ + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/sessions/index.mdx b/apps/docs/content/docs/api-reference/sessions/index.mdx new file mode 100644 index 000000000..bbe609d98 --- /dev/null +++ b/apps/docs/content/docs/api-reference/sessions/index.mdx @@ -0,0 +1,15 @@ +--- +title: "Sessions" +description: "Sessions. Application API: Project API key." +--- + +Public schema constrained by the pinned OpenAI Agents API baseline; documented x_agents_core fields remain Core extensions. + +| Operation | Method | Path | +| --- | --- | --- | +| [List execution Sessions](/api-reference/sessions/list-execution-sessions) | `GET` | `/v1/agents/sessions` | +| [Create an execution Session](/api-reference/sessions/create-an-execution-session) | `POST` | `/v1/agents/sessions` | +| [Retrieve an execution Session](/api-reference/sessions/retrieve-an-execution-session) | `GET` | `/v1/agents/sessions/{session_id}` | +| [Update execution Session metadata](/api-reference/sessions/update-execution-session-metadata) | `POST` | `/v1/agents/sessions/{session_id}` | +| [Delete an execution Session](/api-reference/sessions/delete-an-execution-session) | `DELETE` | `/v1/agents/sessions/{session_id}` | +| [Submit Session input events](/api-reference/sessions/submit-session-input-events) | `POST` | `/v1/agents/sessions/{session_id}/events` | diff --git a/apps/docs/content/docs/api-reference/sessions/list-execution-sessions.mdx b/apps/docs/content/docs/api-reference/sessions/list-execution-sessions.mdx new file mode 100644 index 000000000..fd644b16c --- /dev/null +++ b/apps/docs/content/docs/api-reference/sessions/list-execution-sessions.mdx @@ -0,0 +1,26 @@ +--- +title: List execution Sessions +description: >- + Cursor and results are scoped to the authenticated execution tenant; an unknown, malformed or + foreign after cursor returns not found. +full: true +_openapi: + method: GET + route: /agents/sessions + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Cursor and results are scoped to the authenticated execution tenant; an unknown, malformed + or foreign after cursor returns not found. Optional agent_id matches the immutable root + Agent ID, including inline Agents and historical Sessions whose saved source was updated + or deleted. Omission lists all Agents. Returns the same Environment and pending-input + activity projection as Session retrieval, including self_hosted Sessions. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Optional agent_id matches the immutable root Agent ID, including inline Agents and historical Sessions whose saved source was updated or deleted. Omission lists all Agents. Returns the same Environment and pending-input activity projection as Session retrieval, including self_hosted Sessions. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/sessions/meta.json b/apps/docs/content/docs/api-reference/sessions/meta.json new file mode 100644 index 000000000..0743e2d6b --- /dev/null +++ b/apps/docs/content/docs/api-reference/sessions/meta.json @@ -0,0 +1,11 @@ +{ + "title": "Sessions", + "pages": [ + "list-execution-sessions", + "create-an-execution-session", + "retrieve-an-execution-session", + "update-execution-session-metadata", + "delete-an-execution-session", + "submit-session-input-events" + ] +} diff --git a/apps/docs/content/docs/api-reference/sessions/retrieve-an-execution-session.mdx b/apps/docs/content/docs/api-reference/sessions/retrieve-an-execution-session.mdx new file mode 100644 index 000000000..3ea9afdeb --- /dev/null +++ b/apps/docs/content/docs/api-reference/sessions/retrieve-an-execution-session.mdx @@ -0,0 +1,23 @@ +--- +title: Retrieve an execution Session +description: Returns supported none, self_hosted and basic openai_hosted Session environments. +full: true +_openapi: + method: GET + route: /agents/sessions/{session_id} + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Returns supported none, self_hosted and basic openai_hosted Session environments. + Self-hosted pending input can require a caller connection before a Turn exists. Hosted + initial provisioning remains idle until a Turn starts; connection observations are not + native execution readiness. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Self-hosted pending input can require a caller connection before a Turn exists. Hosted initial provisioning remains idle until a Turn starts; connection observations are not native execution readiness. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/sessions/submit-session-input-events.mdx b/apps/docs/content/docs/api-reference/sessions/submit-session-input-events.mdx new file mode 100644 index 000000000..dc44ebc63 --- /dev/null +++ b/apps/docs/content/docs/api-reference/sessions/submit-session-input-events.mdx @@ -0,0 +1,76 @@ +--- +title: Submit Session input events +description: >- + An empty events array is a resource-authorized no-op; it creates no execution retry identity, + Turn, Item or input receipt. +full: true +_openapi: + method: POST + route: /agents/sessions/{session_id}/events + toc: [] + structuredData: + headings: [] + contents: + - content: >- + An empty events array is a resource-authorized no-op; it creates no execution retry + identity, Turn, Item or input receipt. For environment none, atomically accepts text + messages, cancellation and function results. Messages steer active work or start a queued + Turn. The supported self_hosted profile accepts text-only messages; qualified Codex and + Claude SDK openai_hosted profiles also accept inline PNG/JPEG. Under the Session lock, + matching retries retain their original target; new active messages append to the current + Turn, while idle messages reserve work and wait up to the original five-minute + connection/admission deadline. Return 202 only after durable admission, without claiming + native application; active messages create no Turn or reservation. Cancellation-only + prepared-environment batches use existing durable cancellation admission and return 202 + without waiting for native exit; a new cancellation conflicts while a pre-Turn reservation + is pending. Homogeneous tool_result-only prepared-environment batches reuse existing + scoped result admission and application receipts without creating a Turn or bypassing a + pending reservation. Mixed prepared-environment batches remain unsupported. HTTP + expiry/cancellation use local 409 environment_input_expired/environment_input_cancelled + errors. New input on a Session whose hosted Environment failed to provision returns the + observed 409 conflict_error "the hosted environment failed to provision"; input already + waiting when it fails and expired Environments keep the local 409 environment_unavailable. + Input the Session cannot accept in its current state, such as a result after cancellation + or a batch while earlier input is pending, and a result that differs from the call's saved + result return 409 with type and code conflict_error; reusing an Idempotency-Key with a + different batch returns the local 409 idempotency_conflict. Inside an owned Session, a + result for an unknown call or for a call of another Turn returns 400 invalid_request_error + and changes nothing; missing and foreign Sessions return 404. Losing execution ownership + returns 503. The response write deadline accommodates the admission window for either + prepared Environment, independently of new-hosted-admission and executor URL settings. + Disconnecting the waiting HTTP request does not cancel retained work or restart its + deadline. Retry keys identify the whole ordered batch. Function output accepts text or + ordered text/image parts subject to engine support; Claude SDK accepts text results and, + on none and qualified openai_hosted, successful inline PNG/JPEG results, preserving + ordered content; error images and remote references reject before admission. Native image + resizing may change bytes. Runtime image-result support is checked only for image-bearing + delivery. Codex and Claude SDK on none and qualified openai_hosted accept ordered inline + PNG/JPEG image messages. Self-hosted profiles and other engines remain text-only; remote + image URLs are unsupported. Image references are retained unchanged without service-side + downloads. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +
+Full description + +For environment none, atomically accepts text messages, cancellation and function results. Messages steer active work or start a queued Turn. The supported self_hosted profile accepts text-only messages; qualified Codex and Claude SDK openai_hosted profiles also accept inline PNG/JPEG. + +Under the Session lock, matching retries retain their original target; new active messages append to the current Turn, while idle messages reserve work and wait up to the original five-minute connection/admission deadline. Return 202 only after durable admission, without claiming native application; active messages create no Turn or reservation. Cancellation-only prepared-environment batches use existing durable cancellation admission and return 202 without waiting for native exit; a new cancellation conflicts while a pre-Turn reservation is pending. + +Homogeneous tool_result-only prepared-environment batches reuse existing scoped result admission and application receipts without creating a Turn or bypassing a pending reservation. Mixed prepared-environment batches remain unsupported. HTTP expiry/cancellation use local 409 environment_input_expired/environment_input_cancelled errors. + +New input on a Session whose hosted Environment failed to provision returns the observed 409 conflict_error "the hosted environment failed to provision"; input already waiting when it fails and expired Environments keep the local 409 environment_unavailable. Input the Session cannot accept in its current state, such as a result after cancellation or a batch while earlier input is pending, and a result that differs from the call's saved result return 409 with type and code conflict_error; reusing an Idempotency-Key with a different batch returns the local 409 idempotency_conflict. Inside an owned Session, a result for an unknown call or for a call of another Turn returns 400 invalid_request_error and changes nothing; missing and foreign Sessions return 404. + +Losing execution ownership returns 503. The response write deadline accommodates the admission window for either prepared Environment, independently of new-hosted-admission and executor URL settings. Disconnecting the waiting HTTP request does not cancel retained work or restart its deadline. + +Retry keys identify the whole ordered batch. Function output accepts text or ordered text/image parts subject to engine support; Claude SDK accepts text results and, on none and qualified openai_hosted, successful inline PNG/JPEG results, preserving ordered content; error images and remote references reject before admission. Native image resizing may change bytes. + +Runtime image-result support is checked only for image-bearing delivery. Codex and Claude SDK on none and qualified openai_hosted accept ordered inline PNG/JPEG image messages. Self-hosted profiles and other engines remain text-only; remote image URLs are unsupported. + +Image references are retained unchanged without service-side downloads. + +
+ + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/sessions/update-execution-session-metadata.mdx b/apps/docs/content/docs/api-reference/sessions/update-execution-session-metadata.mdx new file mode 100644 index 000000000..62edefbd8 --- /dev/null +++ b/apps/docs/content/docs/api-reference/sessions/update-execution-session-metadata.mdx @@ -0,0 +1,33 @@ +--- +title: Update execution Session metadata +description: The metadata field is required in an update body. +full: true +_openapi: + method: POST + route: /agents/sessions/{session_id} + toc: [] + structuredData: + headings: [] + contents: + - content: >- + The metadata field is required in an update body. Send null or {} to clear it, or supply + an object to replace all pairs. Up to 16 string pairs, with keys at most 64 characters and + values at most 512 characters; violations and non-string values return + invalid_request_error with a metadata or metadata. param. U+0000 is rejected as a + local storage limit. Malformed, missing and foreign Session IDs share the not-found + response. Execution configuration and activity are unchanged. Returns the same safe + Environment and pending-input activity projection as Session retrieval. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +
+Full description + +Send null or {} to clear it, or supply an object to replace all pairs. Up to 16 string pairs, with keys at most 64 characters and values at most 512 characters; violations and non-string values return invalid_request_error with a metadata or metadata.<key> param. U+0000 is rejected as a local storage limit. + +Malformed, missing and foreign Session IDs share the not-found response. Execution configuration and activity are unchanged. Returns the same safe Environment and pending-input activity projection as Session retrieval. + +
+ + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/skills.mdx b/apps/docs/content/docs/api-reference/skills.mdx deleted file mode 100644 index 8757bc526..000000000 --- a/apps/docs/content/docs/api-reference/skills.mdx +++ /dev/null @@ -1,51 +0,0 @@ ---- -title: Skills -description: >- - Skills. Application API: Project API key. Public schema constrained by the - pinned OpenAI Agents API baseline; documented x_agents_core fields remain Core - extensions. -full: true -_openapi: - toc: [] - structuredData: - headings: [] - contents: - - content: >- - Lists tenant-owned metadata in timestamp order. Default page size 20, - maximum 100. Limit 0 returns an empty page whose has_more reports - whether any Skill follows the cursor; exact hosted defaults remain - unverified. - - content: >- - Accepts one ZIP in files or a directory in files[]. Applies the - qualified portable Skill bundle profile. No Beta header is required; - full hosted upload limits and activation extensions are not qualified. - - content: >- - Returns tenant-owned metadata without decrypting contents or starting - Runtime. No Beta header is required. - - content: >- - Changes only the tenant-owned default pointer; immutable versions and - existing Session snapshots remain unchanged. - - content: >- - Deletes tenant-owned source bundles. Existing Session installation - snapshots remain independent. - - content: >- - Downloads an authorized ZIP using the default pointer when no concrete - version is supplied. Exact upstream unversioned selection, content - headers and range semantics remain unverified. - - content: >- - Orders by version number; after identifies a version resource, not a - version number. An after value that does not begin with skillver, or a - version of another Skill, returns 400 invalid_value with param after; - a missing version returns not found. No contents are decrypted. Limit - 0 returns an empty page whose has_more reports whether any version - follows the cursor. - - content: >- - Deleting the only remaining version also deletes the Skill; existing - Session installation snapshots remain independent. The default version - cannot be deleted while other versions remain. Version numbers are - never reused. ---- - -{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} - - \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/skills/delete-a-skill-and-its-versions.mdx b/apps/docs/content/docs/api-reference/skills/delete-a-skill-and-its-versions.mdx new file mode 100644 index 000000000..086cb281c --- /dev/null +++ b/apps/docs/content/docs/api-reference/skills/delete-a-skill-and-its-versions.mdx @@ -0,0 +1,21 @@ +--- +title: Delete a Skill and its versions +description: Deletes tenant-owned source bundles. +full: true +_openapi: + method: DELETE + route: /skills/{skill_id} + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Deletes tenant-owned source bundles. Existing Session installation snapshots remain + independent. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Existing Session installation snapshots remain independent. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/skills/delete-a-skill-version.mdx b/apps/docs/content/docs/api-reference/skills/delete-a-skill-version.mdx new file mode 100644 index 000000000..ddd03b4be --- /dev/null +++ b/apps/docs/content/docs/api-reference/skills/delete-a-skill-version.mdx @@ -0,0 +1,24 @@ +--- +title: Delete a Skill version +description: >- + Deleting the only remaining version also deletes the Skill; existing Session installation + snapshots remain independent. +full: true +_openapi: + method: DELETE + route: /skills/{skill_id}/versions/{version} + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Deleting the only remaining version also deletes the Skill; existing Session installation + snapshots remain independent. The default version cannot be deleted while other versions + remain. Version numbers are never reused. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +The default version cannot be deleted while other versions remain. Version numbers are never reused. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/skills/download-immutable-skill-version-content.mdx b/apps/docs/content/docs/api-reference/skills/download-immutable-skill-version-content.mdx new file mode 100644 index 000000000..89f01acaa --- /dev/null +++ b/apps/docs/content/docs/api-reference/skills/download-immutable-skill-version-content.mdx @@ -0,0 +1,16 @@ +--- +title: Download immutable Skill version content +full: true +_openapi: + method: GET + route: /skills/{skill_id}/versions/{version}/content + toc: [] + structuredData: + headings: [] + contents: [] +description: '' +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/skills/download-skill-content.mdx b/apps/docs/content/docs/api-reference/skills/download-skill-content.mdx new file mode 100644 index 000000000..40468a62b --- /dev/null +++ b/apps/docs/content/docs/api-reference/skills/download-skill-content.mdx @@ -0,0 +1,22 @@ +--- +title: Download Skill content +description: Downloads an authorized ZIP using the default pointer when no concrete version is supplied. +full: true +_openapi: + method: GET + route: /skills/{skill_id}/content + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Downloads an authorized ZIP using the default pointer when no concrete version is + supplied. Exact upstream unversioned selection, content headers and range semantics remain + unverified. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Exact upstream unversioned selection, content headers and range semantics remain unverified. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/skills/index.mdx b/apps/docs/content/docs/api-reference/skills/index.mdx new file mode 100644 index 000000000..8cf8bd7b1 --- /dev/null +++ b/apps/docs/content/docs/api-reference/skills/index.mdx @@ -0,0 +1,20 @@ +--- +title: "Skills" +description: "Skills. Application API: Project API key." +--- + +Public schema constrained by the pinned OpenAI Agents API baseline; documented x_agents_core fields remain Core extensions. + +| Operation | Method | Path | +| --- | --- | --- | +| [List Skills](/api-reference/skills/list-skills) | `GET` | `/v1/skills` | +| [Upload a Skill](/api-reference/skills/upload-a-skill) | `POST` | `/v1/skills` | +| [Retrieve Skill metadata](/api-reference/skills/retrieve-skill-metadata) | `GET` | `/v1/skills/{skill_id}` | +| [Update the default Skill version](/api-reference/skills/update-the-default-skill-version) | `POST` | `/v1/skills/{skill_id}` | +| [Delete a Skill and its versions](/api-reference/skills/delete-a-skill-and-its-versions) | `DELETE` | `/v1/skills/{skill_id}` | +| [Download Skill content](/api-reference/skills/download-skill-content) | `GET` | `/v1/skills/{skill_id}/content` | +| [List Skill versions](/api-reference/skills/list-skill-versions) | `GET` | `/v1/skills/{skill_id}/versions` | +| [Upload an immutable Skill version](/api-reference/skills/upload-an-immutable-skill-version) | `POST` | `/v1/skills/{skill_id}/versions` | +| [Retrieve Skill version metadata](/api-reference/skills/retrieve-skill-version-metadata) | `GET` | `/v1/skills/{skill_id}/versions/{version}` | +| [Delete a Skill version](/api-reference/skills/delete-a-skill-version) | `DELETE` | `/v1/skills/{skill_id}/versions/{version}` | +| [Download immutable Skill version content](/api-reference/skills/download-immutable-skill-version-content) | `GET` | `/v1/skills/{skill_id}/versions/{version}/content` | diff --git a/apps/docs/content/docs/api-reference/skills/list-skill-versions.mdx b/apps/docs/content/docs/api-reference/skills/list-skill-versions.mdx new file mode 100644 index 000000000..16ba6df07 --- /dev/null +++ b/apps/docs/content/docs/api-reference/skills/list-skill-versions.mdx @@ -0,0 +1,24 @@ +--- +title: List Skill versions +description: Orders by version number; after identifies a version resource, not a version number. +full: true +_openapi: + method: GET + route: /skills/{skill_id}/versions + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Orders by version number; after identifies a version resource, not a version number. An + after value that does not begin with skillver, or a version of another Skill, returns 400 + invalid_value with param after; a missing version returns not found. No contents are + decrypted. Limit 0 returns an empty page whose has_more reports whether any version + follows the cursor. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +An after value that does not begin with skillver, or a version of another Skill, returns 400 invalid_value with param after; a missing version returns not found. No contents are decrypted. Limit 0 returns an empty page whose has_more reports whether any version follows the cursor. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/skills/list-skills.mdx b/apps/docs/content/docs/api-reference/skills/list-skills.mdx new file mode 100644 index 000000000..b53f27b15 --- /dev/null +++ b/apps/docs/content/docs/api-reference/skills/list-skills.mdx @@ -0,0 +1,22 @@ +--- +title: List Skills +description: Lists tenant-owned metadata in timestamp order. +full: true +_openapi: + method: GET + route: /skills + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Lists tenant-owned metadata in timestamp order. Default page size 20, maximum 100. Limit 0 + returns an empty page whose has_more reports whether any Skill follows the cursor; exact + hosted defaults remain unverified. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Default page size 20, maximum 100. Limit 0 returns an empty page whose has_more reports whether any Skill follows the cursor; exact hosted defaults remain unverified. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/skills/meta.json b/apps/docs/content/docs/api-reference/skills/meta.json new file mode 100644 index 000000000..b231e6804 --- /dev/null +++ b/apps/docs/content/docs/api-reference/skills/meta.json @@ -0,0 +1,16 @@ +{ + "title": "Skills", + "pages": [ + "list-skills", + "upload-a-skill", + "retrieve-skill-metadata", + "update-the-default-skill-version", + "delete-a-skill-and-its-versions", + "download-skill-content", + "list-skill-versions", + "upload-an-immutable-skill-version", + "retrieve-skill-version-metadata", + "delete-a-skill-version", + "download-immutable-skill-version-content" + ] +} diff --git a/apps/docs/content/docs/api-reference/skills/retrieve-skill-metadata.mdx b/apps/docs/content/docs/api-reference/skills/retrieve-skill-metadata.mdx new file mode 100644 index 000000000..4ddcc70ab --- /dev/null +++ b/apps/docs/content/docs/api-reference/skills/retrieve-skill-metadata.mdx @@ -0,0 +1,21 @@ +--- +title: Retrieve Skill metadata +description: Returns tenant-owned metadata without decrypting contents or starting Runtime. +full: true +_openapi: + method: GET + route: /skills/{skill_id} + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Returns tenant-owned metadata without decrypting contents or starting Runtime. No Beta + header is required. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +No Beta header is required. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/skills/retrieve-skill-version-metadata.mdx b/apps/docs/content/docs/api-reference/skills/retrieve-skill-version-metadata.mdx new file mode 100644 index 000000000..3dca7d040 --- /dev/null +++ b/apps/docs/content/docs/api-reference/skills/retrieve-skill-version-metadata.mdx @@ -0,0 +1,16 @@ +--- +title: Retrieve Skill version metadata +full: true +_openapi: + method: GET + route: /skills/{skill_id}/versions/{version} + toc: [] + structuredData: + headings: [] + contents: [] +description: '' +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/skills/update-the-default-skill-version.mdx b/apps/docs/content/docs/api-reference/skills/update-the-default-skill-version.mdx new file mode 100644 index 000000000..42587594d --- /dev/null +++ b/apps/docs/content/docs/api-reference/skills/update-the-default-skill-version.mdx @@ -0,0 +1,21 @@ +--- +title: Update the default Skill version +description: >- + Changes only the tenant-owned default pointer; immutable versions and existing Session snapshots + remain unchanged. +full: true +_openapi: + method: POST + route: /skills/{skill_id} + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Changes only the tenant-owned default pointer; immutable versions and existing Session + snapshots remain unchanged. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/skills/upload-a-skill.mdx b/apps/docs/content/docs/api-reference/skills/upload-a-skill.mdx new file mode 100644 index 000000000..f399a3e80 --- /dev/null +++ b/apps/docs/content/docs/api-reference/skills/upload-a-skill.mdx @@ -0,0 +1,22 @@ +--- +title: Upload a Skill +description: Accepts one ZIP in files or a directory in files[]. +full: true +_openapi: + method: POST + route: /skills + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Accepts one ZIP in files or a directory in files[]. Applies the qualified portable Skill + bundle profile. No Beta header is required; full hosted upload limits and activation + extensions are not qualified. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Applies the qualified portable Skill bundle profile. No Beta header is required; full hosted upload limits and activation extensions are not qualified. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/skills/upload-an-immutable-skill-version.mdx b/apps/docs/content/docs/api-reference/skills/upload-an-immutable-skill-version.mdx new file mode 100644 index 000000000..ebc6eedc4 --- /dev/null +++ b/apps/docs/content/docs/api-reference/skills/upload-an-immutable-skill-version.mdx @@ -0,0 +1,16 @@ +--- +title: Upload an immutable Skill version +full: true +_openapi: + method: POST + route: /skills/{skill_id}/versions + toc: [] + structuredData: + headings: [] + contents: [] +description: '' +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/subagents.mdx b/apps/docs/content/docs/api-reference/subagents.mdx deleted file mode 100644 index e2f3346ee..000000000 --- a/apps/docs/content/docs/api-reference/subagents.mdx +++ /dev/null @@ -1,49 +0,0 @@ ---- -title: Subagents -description: >- - Subagents. Application API: Project API key. Public schema constrained by the - pinned OpenAI Agents API baseline; documented x_agents_core fields remain Core - extensions. -full: true -_openapi: - toc: [] - structuredData: - headings: [] - contents: - - content: >- - Includes nested and closed Subagents. Cursors are Subagents of the - same tenant and Session. Any other after value, including a malformed - one, returns 400 invalid_request_error with the message "Invalid - resource ID in `after`". A limit outside 1–100 is rejected. - - content: >- - Returns this Session's persisted Subagent. Active includes idle - between Turns. Resuming preserves opened_at and clears closed_at. - Unknown or inaccessible parent scopes return not found. - - content: >- - Returns only this Subagent's own Items across all its Turns, not its - descendants' Items. Cursors are Items of the same tenant, Session and - Subagent. Any other after value, including a malformed one, returns - 400 invalid_request_error with the message "Invalid session item ID in - `after`". - - content: >- - Includes this Subagent's Turns after resume, with the Session's Agent - ID as agent_id. Cursors are Turns of the same tenant, Session and - Subagent. Any other after value, including a malformed one, returns - 400 invalid_request_error with the message "Invalid resource ID in - `after`". Missing recorded usage remains null. A limit outside 1–100 - is rejected. - - content: >- - Returns a Turn owned by this Subagent. Its agent_id is the Session's - Agent ID and its subagent_id identifies the Subagent. Session Turn - routes do not return child Turns. Unknown or inaccessible parent - scopes return not found. - - content: >- - Returns Items owned by this exact Subagent Turn. Cursors are Items of - the same tenant, Session, Subagent and Turn. Any other after value, - including a malformed one, returns 400 invalid_request_error with the - message "Invalid session item ID in `after`". ---- - -{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} - - \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/subagents/index.mdx b/apps/docs/content/docs/api-reference/subagents/index.mdx new file mode 100644 index 000000000..a7031da4b --- /dev/null +++ b/apps/docs/content/docs/api-reference/subagents/index.mdx @@ -0,0 +1,15 @@ +--- +title: "Subagents" +description: "Subagents. Application API: Project API key." +--- + +Public schema constrained by the pinned OpenAI Agents API baseline; documented x_agents_core fields remain Core extensions. + +| Operation | Method | Path | +| --- | --- | --- | +| [List Session Subagents](/api-reference/subagents/list-session-subagents) | `GET` | `/v1/agents/sessions/{session_id}/subagents` | +| [Retrieve a Session Subagent](/api-reference/subagents/retrieve-a-session-subagent) | `GET` | `/v1/agents/sessions/{session_id}/subagents/{subagent_id}` | +| [List a Subagent's Items](/api-reference/subagents/list-a-subagent-s-items) | `GET` | `/v1/agents/sessions/{session_id}/subagents/{subagent_id}/items` | +| [List a Subagent's Turns](/api-reference/subagents/list-a-subagent-s-turns) | `GET` | `/v1/agents/sessions/{session_id}/subagents/{subagent_id}/turns` | +| [Retrieve a Subagent Turn](/api-reference/subagents/retrieve-a-subagent-turn) | `GET` | `/v1/agents/sessions/{session_id}/subagents/{subagent_id}/turns/{turn_id}` | +| [List a Subagent Turn's Items](/api-reference/subagents/list-a-subagent-turn-s-items) | `GET` | `/v1/agents/sessions/{session_id}/subagents/{subagent_id}/turns/{turn_id}/items` | diff --git a/apps/docs/content/docs/api-reference/subagents/list-a-subagent-s-items.mdx b/apps/docs/content/docs/api-reference/subagents/list-a-subagent-s-items.mdx new file mode 100644 index 000000000..ad08099bf --- /dev/null +++ b/apps/docs/content/docs/api-reference/subagents/list-a-subagent-s-items.mdx @@ -0,0 +1,23 @@ +--- +title: List a Subagent's Items +description: Returns only this Subagent's own Items across all its Turns, not its descendants' Items. +full: true +_openapi: + method: GET + route: /agents/sessions/{session_id}/subagents/{subagent_id}/items + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Returns only this Subagent's own Items across all its Turns, not its descendants' Items. + Cursors are Items of the same tenant, Session and Subagent. Any other after value, + including a malformed one, returns 400 invalid_request_error with the message "Invalid + session item ID in `after`". +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Cursors are Items of the same tenant, Session and Subagent. Any other after value, including a malformed one, returns 400 invalid_request_error with the message "Invalid session item ID in `after`". + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/subagents/list-a-subagent-s-turns.mdx b/apps/docs/content/docs/api-reference/subagents/list-a-subagent-s-turns.mdx new file mode 100644 index 000000000..c10e870b5 --- /dev/null +++ b/apps/docs/content/docs/api-reference/subagents/list-a-subagent-s-turns.mdx @@ -0,0 +1,26 @@ +--- +title: List a Subagent's Turns +description: Includes this Subagent's Turns after resume, with the Session's Agent ID as agent_id. +full: true +_openapi: + method: GET + route: /agents/sessions/{session_id}/subagents/{subagent_id}/turns + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Includes this Subagent's Turns after resume, with the Session's Agent ID as agent_id. + Cursors are Turns of the same tenant, Session and Subagent. Any other after value, + including a malformed one, returns 400 invalid_request_error with the message "Invalid + resource ID in `after`". Missing recorded usage remains null. A limit outside 1–100 is + rejected. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Cursors are Turns of the same tenant, Session and Subagent. Any other after value, including a malformed one, returns 400 invalid_request_error with the message "Invalid resource ID in `after`". Missing recorded usage remains null. + +A limit outside 1–100 is rejected. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/subagents/list-a-subagent-turn-s-items.mdx b/apps/docs/content/docs/api-reference/subagents/list-a-subagent-turn-s-items.mdx new file mode 100644 index 000000000..b3b49bb1a --- /dev/null +++ b/apps/docs/content/docs/api-reference/subagents/list-a-subagent-turn-s-items.mdx @@ -0,0 +1,22 @@ +--- +title: List a Subagent Turn's Items +description: Returns Items owned by this exact Subagent Turn. +full: true +_openapi: + method: GET + route: /agents/sessions/{session_id}/subagents/{subagent_id}/turns/{turn_id}/items + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Returns Items owned by this exact Subagent Turn. Cursors are Items of the same tenant, + Session, Subagent and Turn. Any other after value, including a malformed one, returns 400 + invalid_request_error with the message "Invalid session item ID in `after`". +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Cursors are Items of the same tenant, Session, Subagent and Turn. Any other after value, including a malformed one, returns 400 invalid_request_error with the message "Invalid session item ID in `after`". + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/subagents/list-session-subagents.mdx b/apps/docs/content/docs/api-reference/subagents/list-session-subagents.mdx new file mode 100644 index 000000000..1108529f2 --- /dev/null +++ b/apps/docs/content/docs/api-reference/subagents/list-session-subagents.mdx @@ -0,0 +1,23 @@ +--- +title: List Session Subagents +description: Includes nested and closed Subagents. Cursors are Subagents of the same tenant and Session. +full: true +_openapi: + method: GET + route: /agents/sessions/{session_id}/subagents + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Includes nested and closed Subagents. Cursors are Subagents of the same tenant and + Session. Any other after value, including a malformed one, returns 400 + invalid_request_error with the message "Invalid resource ID in `after`". A limit outside + 1–100 is rejected. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Any other after value, including a malformed one, returns 400 invalid_request_error with the message "Invalid resource ID in `after`". A limit outside 1–100 is rejected. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/subagents/meta.json b/apps/docs/content/docs/api-reference/subagents/meta.json new file mode 100644 index 000000000..adfac2576 --- /dev/null +++ b/apps/docs/content/docs/api-reference/subagents/meta.json @@ -0,0 +1,11 @@ +{ + "title": "Subagents", + "pages": [ + "list-session-subagents", + "retrieve-a-session-subagent", + "list-a-subagent-s-items", + "list-a-subagent-s-turns", + "retrieve-a-subagent-turn", + "list-a-subagent-turn-s-items" + ] +} diff --git a/apps/docs/content/docs/api-reference/subagents/retrieve-a-session-subagent.mdx b/apps/docs/content/docs/api-reference/subagents/retrieve-a-session-subagent.mdx new file mode 100644 index 000000000..02789e367 --- /dev/null +++ b/apps/docs/content/docs/api-reference/subagents/retrieve-a-session-subagent.mdx @@ -0,0 +1,22 @@ +--- +title: Retrieve a Session Subagent +description: Returns this Session's persisted Subagent. +full: true +_openapi: + method: GET + route: /agents/sessions/{session_id}/subagents/{subagent_id} + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Returns this Session's persisted Subagent. Active includes idle between Turns. Resuming + preserves opened_at and clears closed_at. Unknown or inaccessible parent scopes return not + found. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Active includes idle between Turns. Resuming preserves opened_at and clears closed_at. Unknown or inaccessible parent scopes return not found. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/subagents/retrieve-a-subagent-turn.mdx b/apps/docs/content/docs/api-reference/subagents/retrieve-a-subagent-turn.mdx new file mode 100644 index 000000000..5b76e16e7 --- /dev/null +++ b/apps/docs/content/docs/api-reference/subagents/retrieve-a-subagent-turn.mdx @@ -0,0 +1,24 @@ +--- +title: Retrieve a Subagent Turn +description: >- + Returns a Turn owned by this Subagent. Its agent_id is the Session's Agent ID and its subagent_id + identifies the Subagent. +full: true +_openapi: + method: GET + route: /agents/sessions/{session_id}/subagents/{subagent_id}/turns/{turn_id} + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Returns a Turn owned by this Subagent. Its agent_id is the Session's Agent ID and its + subagent_id identifies the Subagent. Session Turn routes do not return child Turns. + Unknown or inaccessible parent scopes return not found. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Session Turn routes do not return child Turns. Unknown or inaccessible parent scopes return not found. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/turns.mdx b/apps/docs/content/docs/api-reference/turns.mdx deleted file mode 100644 index e3dac307c..000000000 --- a/apps/docs/content/docs/api-reference/turns.mdx +++ /dev/null @@ -1,28 +0,0 @@ ---- -title: Turns -description: >- - Turns. Application API: Project API key. Public schema constrained by the - pinned OpenAI Agents API baseline; documented x_agents_core fields remain Core - extensions. -full: true -_openapi: - toc: [] - structuredData: - headings: [] - contents: - - content: >- - Returns the Session's root Turns in creation order; Subagent Turns are - listed through the Subagent Turn routes. The cursor belongs to the - same Session and tenant; any other after value, including a malformed - one or a Subagent Turn ID, returns not found. Usage contains the - latest recorded complete token breakdown; missing measurements remain - null. - - content: >- - Returns a root Turn of this Session. A Subagent Turn ID returns the - same not found error as a missing Turn; read it through the Subagent - Turn routes. ---- - -{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} - - \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/turns/index.mdx b/apps/docs/content/docs/api-reference/turns/index.mdx new file mode 100644 index 000000000..17e467b86 --- /dev/null +++ b/apps/docs/content/docs/api-reference/turns/index.mdx @@ -0,0 +1,11 @@ +--- +title: "Turns" +description: "Turns. Application API: Project API key." +--- + +Public schema constrained by the pinned OpenAI Agents API baseline; documented x_agents_core fields remain Core extensions. + +| Operation | Method | Path | +| --- | --- | --- | +| [List execution Turns](/api-reference/turns/list-execution-turns) | `GET` | `/v1/agents/sessions/{session_id}/turns` | +| [Retrieve an execution Turn](/api-reference/turns/retrieve-an-execution-turn) | `GET` | `/v1/agents/sessions/{session_id}/turns/{turn_id}` | diff --git a/apps/docs/content/docs/api-reference/turns/list-execution-turns.mdx b/apps/docs/content/docs/api-reference/turns/list-execution-turns.mdx new file mode 100644 index 000000000..bc0dc12cd --- /dev/null +++ b/apps/docs/content/docs/api-reference/turns/list-execution-turns.mdx @@ -0,0 +1,25 @@ +--- +title: List execution Turns +description: >- + Returns the Session's root Turns in creation order; Subagent Turns are listed through the Subagent + Turn routes. +full: true +_openapi: + method: GET + route: /agents/sessions/{session_id}/turns + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Returns the Session's root Turns in creation order; Subagent Turns are listed through the + Subagent Turn routes. The cursor belongs to the same Session and tenant; any other after + value, including a malformed one or a Subagent Turn ID, returns not found. Usage contains + the latest recorded complete token breakdown; missing measurements remain null. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +The cursor belongs to the same Session and tenant; any other after value, including a malformed one or a Subagent Turn ID, returns not found. Usage contains the latest recorded complete token breakdown; missing measurements remain null. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/turns/meta.json b/apps/docs/content/docs/api-reference/turns/meta.json new file mode 100644 index 000000000..7a2b5c34f --- /dev/null +++ b/apps/docs/content/docs/api-reference/turns/meta.json @@ -0,0 +1,7 @@ +{ + "title": "Turns", + "pages": [ + "list-execution-turns", + "retrieve-an-execution-turn" + ] +} diff --git a/apps/docs/content/docs/api-reference/turns/retrieve-an-execution-turn.mdx b/apps/docs/content/docs/api-reference/turns/retrieve-an-execution-turn.mdx new file mode 100644 index 000000000..c244c4159 --- /dev/null +++ b/apps/docs/content/docs/api-reference/turns/retrieve-an-execution-turn.mdx @@ -0,0 +1,21 @@ +--- +title: Retrieve an execution Turn +description: Returns a root Turn of this Session. +full: true +_openapi: + method: GET + route: /agents/sessions/{session_id}/turns/{turn_id} + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Returns a root Turn of this Session. A Subagent Turn ID returns the same not found error + as a missing Turn; read it through the Subagent Turn routes. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +A Subagent Turn ID returns the same not found error as a missing Turn; read it through the Subagent Turn routes. + + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/vaults.mdx b/apps/docs/content/docs/api-reference/vaults.mdx deleted file mode 100644 index 3bb1698f4..000000000 --- a/apps/docs/content/docs/api-reference/vaults.mdx +++ /dev/null @@ -1,50 +0,0 @@ ---- -title: Vaults -description: >- - Vaults. Application API: Project API key. Public schema constrained by the - pinned OpenAI Agents API baseline; documented x_agents_core fields remain Core - extensions. -full: true -_openapi: - toc: [] - structuredData: - headings: [] - contents: - - content: >- - Lists project-owned Vaults independently of execution. An unknown, - malformed or foreign after cursor returns not found. Includes active - and archived records by default. Status accepts a scalar, the SDK's - status[] array or both, filtering by their union; a repeated scalar is - rejected. Limits default to 20 and clamp to 1–100. Equal creation - times use ID ordering; exact hosted errors and concurrent-page - behavior remain unverified. Archive/delete lifecycle is not - implemented. - - content: >- - Creates a project-owned Vault independently of execution. Omitted name - stays null; a supplied string is trimmed and must contain 1–256 UTF-8 - bytes. Explicit null name is invalid. Omitted/null metadata becomes an - empty object; non-string values return invalid_request_error with a - metadata. param. Metadata has a local 64 KiB encoded storage - bound. U+0000 in stored strings is rejected as a local storage limit. - Credentials, Session binding and hosted error/retry parity remain - incomplete. - - content: >- - Reads a Vault owned by the authenticated project without resolving - credentials, Sessions or execution devices. Missing and foreign IDs - share the same not-found response; exact hosted error semantics remain - unverified. - - content: >- - Atomically removes the authenticated project's Vault and all its - stored Credentials without an encryption key, decryption or external - requests. Existing Session snapshots, history and recorded retries - retain their frozen identities; subsequent credential lookups fail - without reselection or anonymous fallback. Already-resolved tokens and - running Sessions are not revoked or cancelled. Missing/repeated - deletion locally returns 404. Exact hosted archive, post-delete - visibility and concurrent/error semantics remain unverified; physical - erasure from native history, WAL or backups is not established. ---- - -{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} - - \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/vaults/create-a-vault.mdx b/apps/docs/content/docs/api-reference/vaults/create-a-vault.mdx new file mode 100644 index 000000000..7b3ecdf12 --- /dev/null +++ b/apps/docs/content/docs/api-reference/vaults/create-a-vault.mdx @@ -0,0 +1,32 @@ +--- +title: Create a Vault +description: Creates a project-owned Vault independently of execution. +full: true +_openapi: + method: POST + route: /vaults + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Creates a project-owned Vault independently of execution. Omitted name stays null; a + supplied string is trimmed and must contain 1–256 UTF-8 bytes. Explicit null name is + invalid. Omitted/null metadata becomes an empty object; non-string values return + invalid_request_error with a metadata. param. Metadata has a local 64 KiB encoded + storage bound. U+0000 in stored strings is rejected as a local storage limit. Credentials, + Session binding and hosted error/retry parity remain incomplete. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +
+Full description + +Omitted name stays null; a supplied string is trimmed and must contain 1–256 UTF-8 bytes. Explicit null name is invalid. Omitted/null metadata becomes an empty object; non-string values return invalid_request_error with a metadata.<key> param. + +Metadata has a local 64 KiB encoded storage bound. U+0000 in stored strings is rejected as a local storage limit. Credentials, Session binding and hosted error/retry parity remain incomplete. + +
+ + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/vaults/delete-a-vault-and-all-its-credentials.mdx b/apps/docs/content/docs/api-reference/vaults/delete-a-vault-and-all-its-credentials.mdx new file mode 100644 index 000000000..0284ea3d7 --- /dev/null +++ b/apps/docs/content/docs/api-reference/vaults/delete-a-vault-and-all-its-credentials.mdx @@ -0,0 +1,35 @@ +--- +title: Delete a Vault and all its Credentials +description: >- + Atomically removes the authenticated project's Vault and all its stored Credentials without an + encryption key, decryption or external requests. +full: true +_openapi: + method: DELETE + route: /vaults/{vault_id} + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Atomically removes the authenticated project's Vault and all its stored Credentials + without an encryption key, decryption or external requests. Existing Session snapshots, + history and recorded retries retain their frozen identities; subsequent credential lookups + fail without reselection or anonymous fallback. Already-resolved tokens and running + Sessions are not revoked or cancelled. Missing/repeated deletion locally returns 404. + Exact hosted archive, post-delete visibility and concurrent/error semantics remain + unverified; physical erasure from native history, WAL or backups is not established. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +
+Full description + +Existing Session snapshots, history and recorded retries retain their frozen identities; subsequent credential lookups fail without reselection or anonymous fallback. Already-resolved tokens and running Sessions are not revoked or cancelled. Missing/repeated deletion locally returns 404. + +Exact hosted archive, post-delete visibility and concurrent/error semantics remain unverified; physical erasure from native history, WAL or backups is not established. + +
+ + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/vaults/index.mdx b/apps/docs/content/docs/api-reference/vaults/index.mdx new file mode 100644 index 000000000..00b22a93a --- /dev/null +++ b/apps/docs/content/docs/api-reference/vaults/index.mdx @@ -0,0 +1,13 @@ +--- +title: "Vaults" +description: "Vaults. Application API: Project API key." +--- + +Public schema constrained by the pinned OpenAI Agents API baseline; documented x_agents_core fields remain Core extensions. + +| Operation | Method | Path | +| --- | --- | --- | +| [List Vaults](/api-reference/vaults/list-vaults) | `GET` | `/v1/vaults` | +| [Create a Vault](/api-reference/vaults/create-a-vault) | `POST` | `/v1/vaults` | +| [Retrieve a Vault](/api-reference/vaults/retrieve-a-vault) | `GET` | `/v1/vaults/{vault_id}` | +| [Delete a Vault and all its Credentials](/api-reference/vaults/delete-a-vault-and-all-its-credentials) | `DELETE` | `/v1/vaults/{vault_id}` | diff --git a/apps/docs/content/docs/api-reference/vaults/list-vaults.mdx b/apps/docs/content/docs/api-reference/vaults/list-vaults.mdx new file mode 100644 index 000000000..e93d6e144 --- /dev/null +++ b/apps/docs/content/docs/api-reference/vaults/list-vaults.mdx @@ -0,0 +1,32 @@ +--- +title: List Vaults +description: Lists project-owned Vaults independently of execution. +full: true +_openapi: + method: GET + route: /vaults + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Lists project-owned Vaults independently of execution. An unknown, malformed or foreign + after cursor returns not found. Includes active and archived records by default. Status + accepts a scalar, the SDK's status[] array or both, filtering by their union; a repeated + scalar is rejected. Limits default to 20 and clamp to 1–100. Equal creation times use ID + ordering; exact hosted errors and concurrent-page behavior remain unverified. + Archive/delete lifecycle is not implemented. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +
+Full description + +An unknown, malformed or foreign after cursor returns not found. Includes active and archived records by default. Status accepts a scalar, the SDK's status[] array or both, filtering by their union; a repeated scalar is rejected. + +Limits default to 20 and clamp to 1–100. Equal creation times use ID ordering; exact hosted errors and concurrent-page behavior remain unverified. Archive/delete lifecycle is not implemented. + +
+ + \ No newline at end of file diff --git a/apps/docs/content/docs/api-reference/vaults/meta.json b/apps/docs/content/docs/api-reference/vaults/meta.json new file mode 100644 index 000000000..22f1a6b90 --- /dev/null +++ b/apps/docs/content/docs/api-reference/vaults/meta.json @@ -0,0 +1,9 @@ +{ + "title": "Vaults", + "pages": [ + "list-vaults", + "create-a-vault", + "retrieve-a-vault", + "delete-a-vault-and-all-its-credentials" + ] +} diff --git a/apps/docs/content/docs/api-reference/vaults/retrieve-a-vault.mdx b/apps/docs/content/docs/api-reference/vaults/retrieve-a-vault.mdx new file mode 100644 index 000000000..ee6057796 --- /dev/null +++ b/apps/docs/content/docs/api-reference/vaults/retrieve-a-vault.mdx @@ -0,0 +1,24 @@ +--- +title: Retrieve a Vault +description: >- + Reads a Vault owned by the authenticated project without resolving credentials, Sessions or + execution devices. +full: true +_openapi: + method: GET + route: /vaults/{vault_id} + toc: [] + structuredData: + headings: [] + contents: + - content: >- + Reads a Vault owned by the authenticated project without resolving credentials, Sessions + or execution devices. Missing and foreign IDs share the same not-found response; exact + hosted error semantics remain unverified. +--- + +{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} + +Missing and foreign IDs share the same not-found response; exact hosted error semantics remain unverified. + + \ No newline at end of file diff --git a/apps/docs/content/docs/error-codes.mdx b/apps/docs/content/docs/error-codes.mdx new file mode 100644 index 000000000..dd9691547 --- /dev/null +++ b/apps/docs/content/docs/error-codes.mdx @@ -0,0 +1,296 @@ +--- +title: "Error codes" +description: "Every error code Core, the console and the machine transport write, and what each means." +--- + +This registry lists every error `code` Core, the console (including the +installer rejections it relays) and the daemon transport write, the response shapes that carry no code, and the codes the +TypeScript client creates itself. Operation-specific triggers and `param` values +stay in the resource contracts; this page says what each code means and where it +can appear. + +Two checks compare it with the code. `contract_conformance_test.go` in +`services/agents-api/internal/api` requires the status and code of every row to +be written somewhere and every written status and code to have a row, and the +statuses of the uncoded tables to equal the statuses their handlers write. +`apps/docs/scripts/verify-error-codes.mjs` does the same for client-generated +codes and for every code the client and Web compare against, and the Go test +also compares the installation domain setup codes with the installer. The +Namespaces and Meaning columns are maintained by review. + +## Which "code" is meant + +The word names eight different things. Only the first three are HTTP error codes. + +| Layer | Where it appears | Examples | Reference | +| --- | --- | --- | --- | +| API envelope | `error.code` of a `/v1`, `/core/v1` or `/api/v1` JSON error, or of an error object inside a Session event | `invalid_request_error`, `project_archived`, `stream_interrupted` | [HTTP API codes](#http-api-codes), [Session event codes](#session-event-error-codes) | +| Console envelope | `error.code` of an error Web's server writes for `/core/*` | `console_sign_in_required`, `core_unreachable` | [Console codes](#console-codes), [Core errors](https://github.com/MiniMax-AI/parsar-core/blob/f6d258735fc601c521dd990e6f9e1ed261f4ef2d/contracts/agents-api/core-errors.md) | +| Daemon transport | `error` member of an `/api/v1/agent-daemon/*` JSON error | `missing_bearer`, `incompatible_version` | [Runtime daemon transport codes](#runtime-daemon-transport-codes) | +| Runtime protocol result | `error_code` of a Core–Runtime message after connection, such as a workspace, preparation or cancellation result; Core validates each value against its message and maps it to its own outcome or stored cause; no API response returns it | `write_rejected`, `read_unconfirmed`, `cancel_timeout` | [Core–Runtime protocol](/runtime-protocol) and its typed payloads; not listed here | +| Node diagnostic | `diagnostic` value inside a node payload; never an HTTP status | `docker_unavailable`, `kvm_unavailable` | [Sandbox deployment](https://github.com/MiniMax-AI/parsar-core/blob/f6d258735fc601c521dd990e6f9e1ed261f4ef2d/contracts/agents-api/sandbox-deployment.md), [nodes](/hosted-providers) | +| Session diagnostic category | `code` of a failure category inside a successful Session diagnostics snapshot | `harness_error`, `runtime_disconnected` | [Diagnostic failure categories](https://github.com/MiniMax-AI/parsar-core/blob/f6d258735fc601c521dd990e6f9e1ed261f4ef2d/contracts/agents-api/core-errors.md#diagnostic-failure-categories) | +| Turn error | `error.code` of a failed Turn or subagent Turn in a successful read; Core always publishes `internal_error`, and the other values of the pinned enum are never returned | `internal_error` | The cause is in the [diagnostic failure categories](https://github.com/MiniMax-AI/parsar-core/blob/f6d258735fc601c521dd990e6f9e1ed261f4ef2d/contracts/agents-api/core-errors.md#diagnostic-failure-categories); not listed here | +| Client identifier | `AgentCoreError.code` created by `packages/agents-client` without a response, or a local daemon/adapter error | `sandbox_configuration_unconfirmed`, `invalid_admin_response` | [Client-generated codes](#client-generated-codes), daemon and adapter guides | + +`error.type` is not a second code. It follows one rule: `server_error` for any 5xx, +`conflict_error` for any 409, `not_found_error` or `invalid_beta` when the code is +that value, and `invalid_request_error` otherwise. + +## HTTP API codes + +`/v1`, `/core/v1` and `/api/v1` share one writer, so a code keeps its meaning in +every namespace; a row names a namespace-specific trigger where one differs. `/core/v1` adds optional `details` ([Core errors](https://github.com/MiniMax-AI/parsar-core/blob/f6d258735fc601c521dd990e6f9e1ed261f4ef2d/contracts/agents-api/core-errors.md)). +Clients branch on `code`, never on `message`. A `null` row is a response whose +`code` is null. + +| Status | Code | Namespaces | Meaning | +| --- | --- | --- | --- | +| 400 | `invalid_request_error` | all | Request validation failed: body fields, list queries on Agents API Beta lists and on the Core resource lists under `/projects/{project_id}`, cursors, MCP credential selection or unstorable text. `param` names the field when known | +| 400 | `invalid_request` | all | Malformed body, identifier or local request limit outside the official fields, including invalid queries on the Core Project, key, audit log and summary lists | +| 400 | `invalid_value` | `/v1`, `/core/v1` | Skills: invalid `order` or Skill version `after` on `/v1`; on both namespaces, deletion of the default Skill version (param `version`) | +| 400 | `duplicate_parameter` | `/v1` | Skills list key supplied more than once; `param` is the key | +| 400 | `integer_below_min_value` | `/v1` | Skills list `limit` below 0 | +| 400 | `integer_above_max_value` | `/v1` | Skills list `limit` above 100 | +| 400 | `unsupported_parameter` | `/v1`, `/core/v1` | A body on a deletion that accepts none, a repeated Files list key, or query parameters Runtime observation and history reads do not accept | +| 400 | `invalid_beta` | `/v1` | Missing or wrong `OpenAI-Beta: agents=v1` on an Agents API Beta route | +| 400 | `unsupported_or_invalid_configuration` | `/v1` | The configuration or input is outside what the selected harness supports | +| 400 | `model_provider_required` | `/v1` | The Session resolved no model provider and cannot run | +| 400 | `invalid_sandbox_configuration` | `/core/v1` | Sandbox deployment configuration is invalid | +| 400 | `invalid_name` | `/core/v1`, `/api/v1` | A Project, key or node name, including the name a node enrolls with, fails its length or character rules; on `/core/v1`, `details.max_length` gives the limit | +| 400 | `invalid_node_capacity` | `/core/v1` | Node `max_active` or `max_retained` is outside 1-1000000, or retained is below active | +| 400 | `invalid_model_provider` | `/core/v1` | The model configuration body is missing or malformed; a complete bundle is required | +| 400 | `model_provider_base_url_invalid` | `/core/v1` | `base_url` is not HTTPS, or carries credentials, a query or a fragment | +| 400 | `model_provider_protocol_unsupported` | `/core/v1` | The protocol is unknown or unsupported by the harness; `details.allowed_protocols` lists the supported ones | +| 400 | `model_provider_api_key_invalid` | `/core/v1` | The key is empty, longer than 16384 characters or contains a prohibited character | +| 400 | `model_provider_token_limits_invalid` | `/core/v1` | `context_window` or `max_output_tokens` is invalid, or missing where the harness requires it | +| 400 | `model_configuration_model_invalid` | `/core/v1` | `model` is not a nonempty model identifier | +| 400 | `harness_config_invalid` | `/core/v1` | `harness_config` contains unsupported or invalid native model parameters | +| 400 | `e2b_api_key_invalid` | `/core/v1` | E2B rejected the API key (param `e2b.api_key`) | +| 400 | `e2b_template_build_invalid` | `/core/v1` | The E2B template build is not a ready immutable build with matching resources (param `e2b.template`) | +| 400 | null | `/v1`, `/core/v1` | Files list range and order errors on `/v1`, an unknown Files `purpose` filter (param `purpose`) on both namespaces, and public download of a `user_data` File | +| 401 | `invalid_api_key` | `/v1` | Files or Skills rejected a supplied Bearer Project API key | +| 401 | `invalid_admin_key` | `/core/v1` | The Core key is missing or wrong | +| 401 | `invalid_node_credential` | `/api/v1` | The node enrollment token or node credential is missing or wrong | +| 401 | `installation_authorization_invalid` | `/api/v1` | The native installation authorization is invalid or expired; get a new command from the Session | +| 401 | null | `/v1` | No valid Bearer Project API key on an Agents API Beta route, or none supplied to Files or Skills | +| 404 | `not_found_error` | `/v1`, `/core/v1`, `/api/v1` | The resource does not exist in the caller's or the selected Project's tenant, or the Environment of a native installation no longer exists | +| 404 | `not_found` | `/core/v1` | Unknown Core operation, unknown harness, or a harness without a deployment default model provider | +| 404 | `unsupported_operation` | `/v1` | Unknown `/v1` operation | +| 404 | null | `/v1` | Missing File or Skill on the public Files and Skills routes | +| 405 | `unsupported_operation` | all | Method not allowed, including HEAD on content downloads and Runtime reads | +| 409 | `conflict_error` | `/v1`, `/core/v1` | Official conflicts: Session not idle for deletion, pending input, MCP credential ambiguity, hosted environment failure or a different tool result | +| 409 | `turn_conflict` | `/v1` | The Session or Turn cannot accept this change in its current state, such as an Environment file write while Session input is pending | +| 409 | `idempotency_conflict` | `/v1`, `/api/v1` | The Idempotency-Key was used with different input; on sandbox node enrollment, the node ID is already enrolled | +| 409 | `environment_unavailable` | `/v1` | The Environment no longer accepts new input | +| 409 | `environment_input_expired` | `/v1` | The Environment input deadline passed before admission | +| 409 | `environment_input_cancelled` | `/v1` | The Environment input was cancelled before admission | +| 409 | `project_exists` | `/core/v1` | The Project ID already exists | +| 409 | `project_api_key_exists` | `/core/v1` | The API key ID already exists; list its metadata and revoke it if the secret was not saved | +| 409 | `project_archived` | `/core/v1` | The target Project is archived | +| 409 | `executor_credential_exists` | `/core/v1`, `/api/v1` | The executor key ID already exists; rotate it explicitly to replace the secret. On the native installation claim, the Environment already has another, rotated or revoked executor credential | +| 409 | `runtime_history_unsupported` | `/core/v1` | Runtime history is not supported for this Session | +| 409 | `sandbox_deployment_conflict` | `/core/v1`, `/api/v1` | The sandbox deployment cannot change in its current state | +| 409 | `sandbox_configuration_error` | `/core/v1` | The deployment cannot be served as configured, for example E2B with a loopback public URL | +| 409 | `sandbox_node_address_mismatch` | `/core/v1`, `/api/v1` | The node uses a different Core address than the installation public URL | +| 409 | `sandbox_specification_mismatch` | `/core/v1`, `/api/v1` | The node's resource limits or Runtime release do not match the active deployment | +| 409 | `runtime_node_in_use` | `/core/v1` | The node still holds allocations, snapshots, reservations or pending cleanup | +| 409 | `runtime_local_node_configured` | `/core/v1` | The local node is enabled in deployment configuration and cannot be removed | +| 409 | `sandbox_generation_stale` | `/core/v1` | The deployment generation changed; `details.current_generation` gives the new one. Refresh before submitting again | +| 409 | `sandbox_reset_required` | `/core/v1` | The change needs a reset first, such as another backend or E2B team; `details` names both providers | +| 409 | `sandbox_in_use` | `/core/v1` | Hosted sandbox resources still belong to the deployment; `details.allocations` and `details.pending` count them | +| 409 | `sandbox_reset_in_progress` | `/core/v1`, `/api/v1` | A sandbox reset is in progress, so the deployment cannot change and nodes cannot enroll or read their configuration | +| 409 | `sandbox_not_configured` | `/core/v1` | The operation needs a configured sandbox deployment | +| 409 | `e2b_team_mismatch` | `/core/v1` | The E2B key cannot manage the retained deployment; reset before changing teams (param `e2b.api_key`) | +| 413 | `request_too_large` | all | The body exceeds the operation's limit, or an uploaded File or Skill exceeds its content limit | +| 500 | `internal_error` | all | An unexpected persistence failure; no detail is exposed | +| 503 | `authentication_unavailable` | `/v1` | Project API key authentication is temporarily unavailable; written before any operation runs | +| 503 | `execution_unavailable` | `/v1`, `/core/v1` | Execution or Core Runtime observation is not available on this service, or a Core Runtime observation list exceeded its request budget | +| 503 | `stream_unavailable` | `/v1` | Live events or streaming creation are unavailable | +| 503 | `credential_storage_unavailable` | `/v1`, `/core/v1` | Credential encryption is not configured | +| 503 | `file_storage_unavailable` | `/v1`, `/core/v1` | Source File storage is not configured | +| 503 | `file_transfer_unavailable` | `/v1`, `/core/v1` | The bounded transfer deadline cannot be set for an upload or download | +| 503 | `skill_storage_unavailable` | `/v1`, `/core/v1` | Skill storage is not configured | +| 503 | `artifact_storage_unavailable` | `/v1`, `/core/v1` | Artifact storage is not configured | +| 503 | `subagent_storage_unavailable` | `/v1` | Subagent storage is not configured | +| 503 | `execution_configuration_unavailable` | `/core/v1` | Session execution configuration cannot be read | +| 503 | `runtime_history_unavailable` | `/core/v1` | Durable Runtime history is not configured or temporarily unavailable | +| 503 | `core_metrics_unavailable` | `/core/v1` | Core metrics are not configured or could not be read | +| 503 | `runtime_node_unavailable` | `/v1`, `/core/v1`, `/api/v1` | The selected sandbox node is unavailable, or no node has capacity for a new hosted Session | +| 503 | `sandbox_credential_unavailable` | `/core/v1`, `/api/v1` | Sandbox credentials cannot be decrypted; check the service credential encryption configuration | +| 503 | `sandbox_reset_in_progress` | `/v1` | Hosted admission is paused while a sandbox reset runs; nothing was admitted | +| 503 | `sandbox_nodes_preparing` | `/v1` | The nodes with free capacity are still preparing the deployment's Runtime | +| 503 | `e2b_request_unconfirmed` | `/core/v1` | E2B verification could not be confirmed; nothing is replayed | +| 503 | `provider_unavailable` | `/core/v1` | E2B template discovery is unavailable; check the credential, endpoint and connection | +| 503 | `diagnostics_unavailable` | `/core/v1` | The Session diagnostics reader is not configured | +| 503 | `installation_unavailable` | `/api/v1` | Matching native installation artifacts are unavailable on this Core | + +The namespace column shows where each code is expected. Codes from the shared +stored-error mapping can appear on any operation whose storage reports that +condition. No 503 carries `Retry-After`. + +Core's reverse-path canonicalization answers a path that cannot be decoded with a +plain-text 400 before any namespace is selected; a parsed request path always +decodes, so this is not expected in practice. + +## Session event error codes + +These codes appear inside Session events, in a live stream that has already +answered 200 and in the saved event history. Core's own interruption is an +`event: error` frame whose `error` object has `code`, `type` and `message` but no +`param`. A hosted provisioning failure records the pinned `error` event, with a +null `param`, and the Environment state `error` of +`agent.session.environment.failed`, which has no `param`. See +[history, events and usage](https://github.com/MiniMax-AI/parsar-core/blob/f6d258735fc601c521dd990e6f9e1ed261f4ef2d/contracts/agents-api/history-events-usage.md). + +| Status | Code | Meaning | +| --- | --- | --- | +| 200 | `stream_interrupted` | The live stream was interrupted; reconnect, then read the Session and its saved Items to recover | +| 200 | `sandbox_error` | `error` event, type `environment_error`: the hosted Environment failed to provision; the message is a safe reason without command output | +| 200 | `environment_connection_failed` | Environment state error, type `environment_error`, in `agent.session.environment.failed` | + +## Console codes + +Web's server writes these for `/core/*` requests it rejects before forwarding, +and for the console-local `POST /console/installation/domain` HTTPS setup request. +See [Core errors](https://github.com/MiniMax-AI/parsar-core/blob/f6d258735fc601c521dd990e6f9e1ed261f4ef2d/contracts/agents-api/core-errors.md#console-generated-failures) and +[Web request boundaries](/execution-model#request-boundaries). + +| Status | Code | Meaning | +| --- | --- | --- | +| 400 | `console_request_invalid` | Request path, method or upgrade is unsafe | +| 400 | `domain_setup_unavailable` | Domain setup: this installation uses an external reverse proxy, so HTTPS is configured there | +| 400 | `invalid_request` | Domain setup: the request body exceeds 2 KiB | +| 401 | `console_sign_in_required` | Console session is missing or expired | +| 403 | `console_origin_rejected` | Host, Origin or Fetch Metadata checks failed | +| 502 | `core_unreachable` | Core transport failed or Core tried to redirect | +| 502 | `installation_unreachable` | Domain setup: the installer did not answer or returned an invalid or 5xx response; run `oac status` on the server | + +## Installation domain setup codes + +`POST /console/installation/domain` relays these installer rejections unchanged +in `{"error":{"code":"…","message":"…"}}`. The installation controller in +`deploy/install/ingress.py` writes them; see [Web management](/admin-api) +and the [installer contract](https://github.com/MiniMax-AI/parsar-core/blob/f6d258735fc601c521dd990e6f9e1ed261f4ef2d/docs/maintainers.md#managed-https-ownership). +Failures after the `202` acceptance are reported through the status `message`, +not as codes. + +| Status | Code | Meaning | +| --- | --- | --- | +| 400 | `domain_setup_unavailable` | Managed HTTPS needs a combined Docker installation | +| 400 | `invalid_hostname` | The installer's hostname validation rejected the value | +| 400 | `invalid_confirmation` | `confirm_public_url_change` does not equal the new HTTPS URL | +| 400 | `invalid_request` | The body is missing, larger than 2 KiB, not JSON or has other members | +| 401 | `unauthorized` | The installer rejected the console's Core key | +| 409 | `configuration_pending` | `config.json` has pending edits; apply or revert them first | +| 409 | `installation_not_ready` | The installation has not been applied yet | +| 409 | `installation_not_running` | Core, Web, the gateway or the installation service is not running | +| 409 | `generated_files_edited` | Generated files were edited by hand; resolve them with `oac apply` | +| 409 | `public_url_confirmation_required` | The address changes existing bindings; resubmit with `confirm_public_url_change` | +| 409 | `installation_busy` | Another installation operation holds the lock, or the installer rejected the change | + +## Console sign-in responses + +`/console/auth`, `/console/auth/login`, `/console/auth/logout` and the other +signed-in console pages outside `/core/*` answer failures as +`{"error":""}` with no code. Clients branch on the status. + +| Status | Code | Meaning | +| --- | --- | --- | +| 400 | null | The login body is not a JSON object with only a non-empty `core_key` | +| 401 | null | Wrong Core key, or a console page requested without a session | +| 403 | null | Host, Origin or Fetch Metadata checks failed outside `/core/*` | +| 404 | null | Unknown `/console/auth/*` route | +| 405 | null | Login or logout without POST (`Allow: POST`) | +| 415 | null | The login body is not `application/json` | +| 429 | null | Sign-in is busy (`Retry-After: 1`) or ten failed attempts in one minute (`Retry-After: 60`) | +| 503 | null | A session token could not be generated | + +Outside `/core/*` the console also answers an unsafe path with a plain-text 400, +a wrong method on static pages and `/node-install/*` with a plain-text 405 +(`Allow: GET, HEAD`), and unknown or direct `/v1` and `/api/v1` paths with a +plain-text 404. After sign-in, `/core` and `/core/*` paths outside `/core/v1` +also get a plain-text 404, `/console/api-keys` and its subpaths a plain-text 404, +and `/console/installation/domain` with a method other than GET or POST a +plain-text 405 (`Allow: GET, POST`). `GET /healthz` returns `200 ok` without +authentication. + +## Runtime daemon transport codes + +`/api/v1/agent-daemon/ws`, `/bootstrap` and `/device-status` answer the failures +their handlers detect as `{"error":"","detail":""}`. `detail` is +diagnostic text, not a stable value. The router in front of them answers an +unknown `/api/v1/agent-daemon/*` path with a plain-text 404 and a wrong method with +an empty 405, and a failed WebSocket handshake on `ws` is answered as plain text by +the WebSocket library, so clients must not assume the JSON body on every +failure. + +| Status | Code | Meaning | +| --- | --- | --- | +| 400 | `missing_params` | `device_id`, `version` or the Bearer credential is missing | +| 400 | `missing_device_id` | The bootstrap body or device-status query has no `device_id` | +| 400 | `bad_json` | The bootstrap body is not valid JSON | +| 401 | `missing_bearer` | No Bearer daemon credential | +| 401 | `unknown_device` | The device is not enrolled | +| 401 | `bad_credential` | The daemon credential does not match the device | +| 403 | `wrong_runtime_type` | The credential belongs to another Runtime type | +| 405 | `method_not_allowed` | Bootstrap without POST, if the handler is reached; the router's empty 405 normally answers first | +| 426 | `incompatible_version` | The daemon version is not supported by this Core | +| 500 | `internal` | Authentication failed unexpectedly | + +## Plain-text transport responses + +These routes answer failures with a `text/plain` body and no code. + +| Status | Code | Routes | Meaning | +| --- | --- | --- | --- | +| 400 | null | `POST agent-daemon/enroll`, `GET agent-daemon/connection` | Invalid body or query | +| 401 | null | enroll, connection, `GET sandbox-node/connect` | Missing or rejected credential | +| 405 | null | enroll, connection | Wrong method (`Allow` names the method) | +| 409 | null | enroll, connection, sandbox-node/connect | The Environment is bound to another executor, or the node identity is already connected | +| 503 | null | enroll, connection, sandbox-node/connect | Enrollment storage, node authentication or the connection owner is unavailable | + +The public installer artifacts under `/api/v1/agent-daemon/install/{version}/` +answer a method other than GET or HEAD with an empty 405 and an unknown file with +a plain-text 404. + +## Client-generated codes + +`packages/agents-client` creates these `AgentCoreError` codes itself; Core never +sends them. + +Codes that report a malformed response use status 502 (or 0 for Core metrics) +and mean the client rejected what Core returned; they never indicate a request +error. + +| Code | Meaning | +| --- | --- | +| `invalid_admin_response` | An administration or sandbox administration response has the wrong shape (`AdminClient`, `SandboxAdminClient`) | +| `invalid_response` | A Core metrics response has the wrong shape (`CoreMetricsClient`) | +| `sandbox_configuration_unconfirmed` | A sandbox configuration write failed without a confirmed outcome, or its reason was withheld because it could echo the key; refresh before submitting again | +| `credential_write_failed` | A Vault credential write was rejected; the client keeps the status but never parses the body, which could reflect the secret | +| `invalid_environment_template` | An Environment Template response has the wrong shape | +| `invalid_environment_template_list` | An Environment Template list has the wrong shape | +| `invalid_vault_resource` | A Vault response has the wrong shape or another ID | +| `invalid_vault_list` | A Vault list has the wrong shape | +| `invalid_vault_deletion` | A Vault deletion receipt has the wrong shape or another ID | +| `invalid_vault_credential` | Credential metadata has the wrong shape or another ID | +| `invalid_vault_credential_list` | A Credential list has the wrong shape | +| `invalid_vault_credential_deletion` | A Credential deletion receipt has the wrong shape or another ID | +| `invalid_session_vaults` | A Session's Vault attachments have the wrong shape | +| `invalid_environment_resource` | An Environment response has the wrong shape | +| `invalid_environment_file` | An Environment file response has the wrong shape | +| `invalid_environment_files` | An Environment files page has the wrong shape | +| `invalid_session_resource` | A Session response has the wrong shape | +| `invalid_session_list` | A Session list has the wrong shape | +| `invalid_history_resource` | A Turn, Item or other history response has the wrong shape | +| `invalid_runtime_observation` | A Runtime observation has the wrong shape | +| `invalid_stream_event` | An event stream frame has the wrong shape | +| `empty_stream` | An event stream closed before its first event | +| `invalid_source_file` | Source File metadata has the wrong shape | +| `invalid_source_file_list` | A Files list has the wrong shape | +| `invalid_source_file_content` | Source File content is incomplete or has the wrong headers | +| `invalid_skill_resource` | A Skill or Skill version response has the wrong shape | +| `invalid_skill_content` | Skill content is incomplete or has the wrong headers | + +[Repository source](https://github.com/MiniMax-AI/parsar-core/blob/f6d258735fc601c521dd990e6f9e1ed261f4ef2d/contracts/agents-api/error-codes.md) diff --git a/apps/docs/content/docs/public-api.mdx b/apps/docs/content/docs/public-api.mdx index ca6557cd6..297887921 100644 --- a/apps/docs/content/docs/public-api.mdx +++ b/apps/docs/content/docs/public-api.mdx @@ -20,7 +20,8 @@ A credential used in another namespace gets 401: a Project API key on `/core/v1` **Routing.** The reverse proxy sends `/v1` and `/api/v1` to Core and everything else to Web ([proxy setup](/install#https-and-the-reverse-proxy)). Browsers reach `/core/v1` only through Web's server, which adds the Core key after -sign-in; Web returns 404 for `/v1` and `/api/v1`. Operator scripts call `/core/v1` +sign-in; Web returns 404 for `/v1` and `/api/v1`, and answers an unauthenticated +`GET /healthz` liveness probe with `200 ok`. Operator scripts call `/core/v1` on Core's loopback port. Details: [Web and Core](/admin-api). ## Public API @@ -28,7 +29,8 @@ on Core's loopback port. Details: [Web and Core](/admin-api). Applications call `/v1` with a Project API key. The routes are exactly the 58 pairs in [upstream-routes.json](https://github.com/MiniMax-AI/parsar-core/blob/f6d258735fc601c521dd990e6f9e1ed261f4ef2d/contracts/agents-api/upstream-routes.json). The [Agents API guide](/sessions) explains every resource with SDK and HTTP -examples. +examples. [Request conventions](/request-conventions) covers the headers, JSON body +checks and list parameters every `/v1` operation shares. ## Core API @@ -93,6 +95,16 @@ the Core key or a Project API key. | `POST agent-daemon/enroll`, `GET agent-daemon/connection` | Self-hosted executor and its installer | Executor credential from `/core/v1/projects/{project_id}/environments/{environment_id}/executor-credentials` | [Executor credentials](https://github.com/MiniMax-AI/parsar-core/blob/f6d258735fc601c521dd990e6f9e1ed261f4ef2d/contracts/agents-api/environment-executor-credentials.md) | | WebSocket `GET agent-daemon/ws`, `POST agent-daemon/bootstrap`, `GET agent-daemon/device-status` | Runtime daemons | Daemon credential: Core writes one into each hosted sandbox it prepares; a self-hosted executor uses its executor credential | [Runtime enrollment](https://github.com/MiniMax-AI/parsar-core/blob/f6d258735fc601c521dd990e6f9e1ed261f4ef2d/services/agents-api/README.md#user-managed-runtime-enrollment) | +Only the three `sandbox-node` HTTP routes and the two native installation routes +(`agent-daemon/installation` and its `/claim` subroute) are in the machine OpenAPI +and use the JSON error envelope. The node WebSocket and the daemon transport are served +beside the API router: `agent-daemon/enroll`, `agent-daemon/connection` and +`sandbox-node/connect` answer failures with a plain-text body and no code, and +`agent-daemon/ws`, `bootstrap` and `device-status` answer the failures their +handlers detect with `{"error":"","detail":"…"}`; router and WebSocket +handshake failures stay plain text. Both are listed in the +[error code registry](/error-codes#runtime-daemon-transport-codes). + ## Contract sources - [Pinned upstream baseline](https://github.com/MiniMax-AI/parsar-core/blob/f6d258735fc601c521dd990e6f9e1ed261f4ef2d/contracts/agents-api/upstream.json): OpenAI @@ -137,4 +149,10 @@ browser session and same-origin checks. It delegates only domain setup to the installer, with the server-held Core key over a private Unix socket; it is not part of the Agents API or Core management API. See [Web request boundaries](/execution-model#request-boundaries). +Core administration failures use the [Core error envelope](https://github.com/MiniMax-AI/parsar-core/blob/f6d258735fc601c521dd990e6f9e1ed261f4ef2d/contracts/agents-api/core-errors.md), +including typed optional safe details and distinct console proxy rejection codes. +The [error code registry](/error-codes) lists every error +code in all three namespaces, the console and the daemon transport, and is checked +against the code. + [Repository source](https://github.com/MiniMax-AI/parsar-core/blob/f6d258735fc601c521dd990e6f9e1ed261f4ef2d/docs/api/README.md) diff --git a/apps/docs/content/docs/request-conventions.mdx b/apps/docs/content/docs/request-conventions.mdx new file mode 100644 index 000000000..4f36beed5 --- /dev/null +++ b/apps/docs/content/docs/request-conventions.mdx @@ -0,0 +1,72 @@ +--- +title: "Request conventions" +description: "Headers, JSON body checks, list parameters and errors shared by every /v1 operation." +--- + +These rules apply to every `/v1` operation. Operation pages state only what differs +from them. + +## Headers + +| Header | Rule | +| --- | --- | +| `Authorization` | `Bearer ` on every operation. See [API namespaces and credentials](/public-api). | +| `OpenAI-Beta` | Exactly one `agents=v1` value on every operation except Files (`/files`) and Skills (`/skills`). Otherwise 400 `invalid_beta`. The pinned SDK sends it. | +| `OpenAI-Organization`, `OpenAI-Project` | Optional. If present they must be `core` and `proj_`; otherwise the request gets the same 401 as a rejected key. | +| `Idempotency-Key` | Optional on Session creation and on event submission, up to 128 bytes. A Core extension: a retry with the same key and request returns the original result, and the same key with a different request returns 409 `idempotency_conflict`. A streamed Session creation retry is the exception; see Create an execution Session. The hosted service returned distinct Sessions for repeated creation keys; its event submission behavior is not documented. | + +## JSON request bodies + +Every operation with a JSON body checks it in this order, before any field +validation or resource lookup: + +1. The `Content-Type` must be `application/json` or another `application/*+json` + type, case-insensitive, with well-formed parameters. +2. The body must fit the operation's limit: 1 MiB, or 16 MiB for Session creation and + for creating or updating an Environment Template. Environment file uploads have + their own limits. A larger body returns 413 `request_too_large` with a Core + message naming the limit. +3. The body must be valid UTF-8 and one JSON value, with no unpaired surrogate + escape and no repeated key at any depth, and its root must be an object. An empty + body or `null` is treated as `{}`. + +Failures of checks 1 and 3 return 400 `invalid_request_error` with a null `param` +and the official message. + +Updating a Skill's default version (`POST /v1/skills/{skill_id}`) is the one +exception: it reads its body without these checks, up to 64 KiB, and an unreadable +body returns 400 `invalid_request`. + +Member names match exactly; a case variant is an unknown member. Text that contains +U+0000 or cannot be stored as UTF-8 returns 400 `invalid_request_error`. This is a +limit of Core's storage, not of the official API. + +## Lists + +Lists take `after`, `limit` and `order`; the Environment files list takes `path`, +`limit` and `order` and continues with an opaque `page` token instead of `after`. `order` is `asc` or `desc`; omitting it uses the +operation's default, and an explicitly empty value is invalid. Unknown query keys +are ignored, and a supported scalar key given twice is rejected. Array parameters, +such as the Vault and Credential `status[]` filter, may repeat. + +The `limit` bounds, the default order and the fields of each error differ between +the Agents API lists, Files and Skills. Each operation page states its bounds and how +an unresolved `after` cursor fails. The +[list query record](https://github.com/MiniMax-AI/parsar-core/blob/f6d258735fc601c521dd990e6f9e1ed261f4ef2d/contracts/agents-api/list-query-semantics.md) has the +evidence for each family. + +## Errors + +Clients branch on the HTTP status and `error.code`, never on `message`. The +[error code registry](/error-codes) lists every code. + +## Compatibility notes + +Core implements the pinned OpenAI Agents API. Where an operation page says a +behavior is not yet verified against the hosted service, Core's behavior is +documented but has not been compared with the official service. The +[coverage record](https://github.com/MiniMax-AI/parsar-core/blob/f6d258735fc601c521dd990e6f9e1ed261f4ef2d/contracts/agents-api/README.md) and +[operation evidence](https://github.com/MiniMax-AI/parsar-core/blob/f6d258735fc601c521dd990e6f9e1ed261f4ef2d/contracts/agents-api/operation-evidence.md) hold the +details and the request evidence. + +[Repository source](https://github.com/MiniMax-AI/parsar-core/blob/f6d258735fc601c521dd990e6f9e1ed261f4ef2d/docs/api/request-conventions.md) diff --git a/apps/docs/content/guide-sources.json b/apps/docs/content/guide-sources.json index 3bb814ba3..0fa2009d3 100644 --- a/apps/docs/content/guide-sources.json +++ b/apps/docs/content/guide-sources.json @@ -9,27 +9,29 @@ "docs/configuration.md": "7dc0031145bb5811bf22cab15270b511b1c43b1bd1ee2b71175d3bc848751bd6", "docs/web/core-connection.md": "861c75c32676fd17b84eb356b263096703af5750c1ceb71bb339e84607fffc56", "docs/getting-started/quickstart.md": "b989682ac2e58d59a794118fd371b37d1ea64c957d3512ff53739458a95d0f9a", - "docs/api/README.md": "dbe3f172a997ee2fd3d2e5765d382b4fb7cf7c50f1dd17212ab9646f6959d63e", - "contracts/agents-api/execution-tools.md": "8cc0dbe207e8e80ac104bf482c37ea297cd64250b51d288ed4baf553756424d2", + "docs/api/README.md": "878a540c3876f703d5e1ded36a2cee7ca462f80b27627897135ac981246fe9f3", + "docs/api/request-conventions.md": "96c23f127aff348a71215ca2474dd15e4725910022b31e9ca1dc704595f3183d", + "contracts/agents-api/execution-tools.md": "e0b61f6c0c236c362186c5f6d0ad69a16dd8a8d9afabe1329a1fe22e5f4a71e9", "docs/api/public-agent-api.md": "00979732412a971013e8f01b4c74820ff51aafdded6b0f105d25a78af86a6627", "docs/examples.md": "0e1bdaeff51c9c36779f817be31ea9816b7d8cb2290cf8350d3c4801f436f4f9", - "contracts/agents-api/environments.md": "424dac4bfd63418afc314896dd6a3e4c5c4375dd0a8bb7579920c5dd9743da22", + "contracts/agents-api/environments.md": "d5fc16c904f751bd13e2af35c9e43c92ca39c6b86401f85cf7f9ee4093c156c9", "docs/getting-started/nodes.md": "c1ad18c445990ea696625011cc3cfa0725779beefd379064d278656801d5578e", "docs/getting-started/self-hosted.md": "5ade597e09cbfa2e321f341693b47730b3696fe7bd4d6834eafbe6b279a55e6b", "docs/self-hosted-native.md": "b3cf736f88792e6925c50b81a4c33eba6b9ee86e195f9ed4e2187db7bed71d88", "apps/web/public/onboarding/monitor-en.webp": "29dc220cb1250c7016b7c4bf7f30e9510b07c07b814a48c3aa9303b2d76f20b2", "docs/web/README.md": "47159689b2488f0a94a1af8488bcf98b465e0cca4003d64a4699d7b4db24e086", "docs/api/web-management.md": "fe24e883f5745d262d3bd88eb73ae2cbbb723297b9a237f28849f9e3b50dffd4", + "contracts/agents-api/error-codes.md": "fa28f8d34083b3e4ca7ba765280a913a525548d29211791ae8c2ca203d1ca57c", "contracts/agents-api/runtime-observability-api.md": "cd46e777fe716a7e76374f4655c96dfbad9d8be1bfca6203ed6118ab87874c2b", "docs/getting-started/operations.md": "4069e89deed7ef619f28cc8d9779055669246eabe322089113ac3a786c3cb2d5", "docs/user-guide.md": "190bea5bfe23b71db3d9437065ee270e07226a89a6e98c668853e5c7f7555529", "docs/assets/development-architecture.png": "24e6d0145d4f16ad70b07b6bc643808a6455aaf6398434d199cf74def200fca6", "docs/development.md": "f5c340253036a2cabc43e22aecdf70522d90280d6511e7649278ae93712ab8b6", - "contracts/agents-api/harness-onboarding.md": "874a80dc1ffc5e97b2783bea3f6b217893f997b38bb8180a29f09c6dbf75e622", + "contracts/agents-api/harness-onboarding.md": "234906652d381f4920d2245a795ad7f12f2f66577018db4dd5d545697d4f111b", "docs/runtime-bootstrap.md": "0d49aed73b298039e04453e6f465b0e925fb2227fa35d4206820bb3acbd8df39", - "docs/runtime-protocol.md": "e8aa4cf862b5f63a4138cfeb25196a6bdb5c40a2e389e828b464585415dc6c45", + "docs/runtime-protocol.md": "79f6bf1597eb0c82b41074fd21a6617225ffb7d11572c156e1d56c4e8741f322", "docs/sandbox-provider.md": "4d47b234a457f874f3ff7e61a7f5da6fc8b75b0c6df0ce0ce9ead1c07afdfb3e", - "apps/docs/scripts/guides.json": "3c3768fb94fd3d42464d4ce8c55724b9ba8360133c7cc19d513d8ec83a8e034f" + "apps/docs/scripts/guides.json": "d786676bb21bd89554392015b530dbcb5bd5364894abf9fd365334d54a9ae0c9" }, "outputs": { "content/docs/index.mdx": "432dd8f02f72edb9f39b92d272719b146c5c1bf5b0429191d0f4a56932b92353", @@ -40,25 +42,27 @@ "content/docs/configure.mdx": "02d1eee789646fdf65ed2ec48b6fe954c81107d6ff5891536ec6ac2df0a8c4dc", "content/docs/bootstrap-projects-keys.mdx": "91a6f62cbe41737adfce9e8ec56e6dc3e2fb0ec8f6b677576f941cdfb378dc47", "content/docs/quickstart.mdx": "d0ab9537ab68f6dd3109353e937a29c5d58ec3894b56a52873c9a1d79dfa60a6", - "content/docs/public-api.mdx": "cd59f4a661f897d1a9dc6ff08a09f7b7504c355288bbf022eff9b70500a9865c", - "content/docs/agents-and-tools.mdx": "44dfde4e3b3906b30323c2e75a89650ae4837210c7ba425be2266edf87ce8ff8", + "content/docs/public-api.mdx": "051ea0082c9875431fd18a03764e38488fae9e79bb0c92291c0c4972042770df", + "content/docs/request-conventions.mdx": "3a81e0faf0e603709c6c59614caaa6a113000a89052e3e38366877219e4c22fc", + "content/docs/agents-and-tools.mdx": "b8a85fe92e19a71b7ad7c9357ce7ad0595d50c9190edb748ca834df615b056cb", "content/docs/sessions.mdx": "bb63d799ed90038836d652f3f866d0309822425114c6b2aa36654b8a991947f6", "content/docs/examples.mdx": "587061e65ab2e841d14980539ba94e2216d4e8135c948a852b9a8bb0359c85d7", - "content/docs/environments-and-files.mdx": "6d8b2a5d5e95e3a5eff47ce93f0239c7cc38d4678bac53c58f5c8df016c23dc5", + "content/docs/environments-and-files.mdx": "352ca1f2b0ab1b0853b890be694629bb47399ba6bc88905f68feaa3bfe401949", "content/docs/hosted-providers.mdx": "85696d88b76f1233db3d8db3266bb0ab4d297d795a44ede13cf34e5169524c68", "content/docs/self-hosted-execution.mdx": "eeed4c6b3646927ccc3c7ac2d20b2c0f9c8a65e42d734310fe3959e016324e57", "content/docs/self-hosted-native.mdx": "671451580dfb4f5c134221991f68292a4f992008174d23190b1da3742046571f", "public/images/source/apps/web/public/onboarding/monitor-en.webp": "29dc220cb1250c7016b7c4bf7f30e9510b07c07b814a48c3aa9303b2d76f20b2", "content/docs/console.mdx": "a930ce36035de74f0c2bef71bed067fc2287ba1c70a485758bf100d484f6adfd", "content/docs/admin-api.mdx": "f43f4f1cac887bc4baa4968d76542a87ba1a6ddeef9259299b53cd98a4aea5e1", + "content/docs/error-codes.mdx": "0f46873e8041b084996fb10c40f063a45d150e9d7a27def590426390e8630720", "content/docs/observability.mdx": "c81214e1865517a9163c48c7ce7c396f5490c9d162080dfa05fa5ebc147f6c8b", "content/docs/troubleshooting.mdx": "bccd725d2389a80b66caf1a1da80532bd68dd3d470bf851799d0114f84e0af25", "content/docs/user-guide.mdx": "7c099b2d787ce3d7876889c7cefd621840ec083f267eadf278214a83f11ba274", "public/images/source/docs/assets/development-architecture.png": "24e6d0145d4f16ad70b07b6bc643808a6455aaf6398434d199cf74def200fca6", "content/docs/development.mdx": "2e5249ddfca571d264e93fd1e0e390a4bd5b0b623bda100cd02f2982929850bb", - "content/docs/harness-onboarding.mdx": "17626e9f6256ddfffc95fd81dfa8d9c712d9ff16792ea5ef54bfe8c3ce1a2a9f", + "content/docs/harness-onboarding.mdx": "d9c9dcbd339ba9b278b133816c1d905bdbd849f44e2ff27882090cd39002e1c8", "content/docs/runtime-bootstrap.mdx": "58982955811c9ad46a9fc04d8d2aef5a762fc9d25d5833f88aa75ee3fc46523f", - "content/docs/runtime-protocol.mdx": "d6b818edf2a0e0c4f2d3878f75805043c6dba3b09c6563f80faa4cecd05d40c7", + "content/docs/runtime-protocol.mdx": "fed94a899e953c486d8560a21a2eb15a8c41c173d020e21b57cd207c08c272b7", "content/docs/sandbox-provider.mdx": "9db833fe9ff3f30a65451f80d7251348695a08e7830f9e95871739a710529818" } } diff --git a/apps/docs/openapi/core-api.yaml b/apps/docs/openapi/core-api.yaml index 94179a5b2..e6c8c26ab 100644 --- a/apps/docs/openapi/core-api.yaml +++ b/apps/docs/openapi/core-api.yaml @@ -260,7 +260,7 @@ paths: application/json: schema: $ref: '#/components/schemas/v1.ModelConfigurationInput' - description: Complete model provider bundle + description: Complete model configuration required: true /core/v1/installation: get: @@ -413,6 +413,12 @@ paths: application/json: schema: $ref: '#/components/schemas/api.CoreErrorResponse' + '413': + description: Request Entity Too Large + content: + application/json: + schema: + $ref: '#/components/schemas/api.CoreErrorResponse' '500': description: Internal Server Error content: @@ -471,6 +477,12 @@ paths: application/json: schema: $ref: '#/components/schemas/api.CoreErrorResponse' + '413': + description: Request Entity Too Large + content: + application/json: + schema: + $ref: '#/components/schemas/api.CoreErrorResponse' '500': description: Internal Server Error content: @@ -968,6 +980,12 @@ paths: application/json: schema: $ref: '#/components/schemas/api.CoreErrorResponse' + '413': + description: Request Entity Too Large + content: + application/json: + schema: + $ref: '#/components/schemas/api.CoreErrorResponse' '500': description: Internal Server Error content: @@ -1075,6 +1093,12 @@ paths: application/json: schema: $ref: '#/components/schemas/api.CoreErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/api.CoreErrorResponse' security: - DeploymentAdminAuth: [] summary: Get a self_hosted Session's installation commands @@ -1371,6 +1395,12 @@ paths: application/json: schema: $ref: '#/components/schemas/api.CoreErrorResponse' + '413': + description: Request Entity Too Large + content: + application/json: + schema: + $ref: '#/components/schemas/api.CoreErrorResponse' '500': description: Internal Server Error content: @@ -2349,6 +2379,12 @@ paths: application/json: schema: $ref: '#/components/schemas/api.CoreErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/api.CoreErrorResponse' '503': description: Service Unavailable content: @@ -2624,8 +2660,8 @@ paths: - schema: type: integer maximum: 100 - minimum: 0 - description: Page size; 0 returns an empty page + minimum: 1 + description: Page size, 1–100 in: query name: limit - schema: @@ -2649,6 +2685,36 @@ paths: application/json: schema: $ref: '#/components/schemas/v1.SkillList' + '400': + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/api.CoreErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/api.CoreErrorResponse' + '404': + description: Not Found + content: + application/json: + schema: + $ref: '#/components/schemas/api.CoreErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/api.CoreErrorResponse' + '503': + description: Service Unavailable + content: + application/json: + schema: + $ref: '#/components/schemas/api.CoreErrorResponse' security: - DeploymentAdminAuth: [] summary: List Skills in a Project @@ -2677,6 +2743,36 @@ paths: application/json: schema: $ref: '#/components/schemas/v1.SkillDeleted' + '400': + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/api.CoreErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/api.CoreErrorResponse' + '404': + description: Not Found + content: + application/json: + schema: + $ref: '#/components/schemas/api.CoreErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/api.CoreErrorResponse' + '503': + description: Service Unavailable + content: + application/json: + schema: + $ref: '#/components/schemas/api.CoreErrorResponse' security: - DeploymentAdminAuth: [] summary: Delete a Skill and its versions in a Project @@ -2704,6 +2800,36 @@ paths: application/json: schema: $ref: '#/components/schemas/v1.Skill' + '400': + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/api.CoreErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/api.CoreErrorResponse' + '404': + description: Not Found + content: + application/json: + schema: + $ref: '#/components/schemas/api.CoreErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/api.CoreErrorResponse' + '503': + description: Service Unavailable + content: + application/json: + schema: + $ref: '#/components/schemas/api.CoreErrorResponse' security: - DeploymentAdminAuth: [] summary: Retrieve Skill metadata in a Project @@ -2733,6 +2859,36 @@ paths: schema: type: string format: binary + '400': + description: Bad Request + content: + application/octet-stream: + schema: + $ref: '#/components/schemas/api.CoreErrorResponse' + '401': + description: Unauthorized + content: + application/octet-stream: + schema: + $ref: '#/components/schemas/api.CoreErrorResponse' + '404': + description: Not Found + content: + application/octet-stream: + schema: + $ref: '#/components/schemas/api.CoreErrorResponse' + '500': + description: Internal Server Error + content: + application/octet-stream: + schema: + $ref: '#/components/schemas/api.CoreErrorResponse' + '503': + description: Service Unavailable + content: + application/octet-stream: + schema: + $ref: '#/components/schemas/api.CoreErrorResponse' security: - DeploymentAdminAuth: [] summary: Download Skill content in a Project @@ -2756,8 +2912,8 @@ paths: - schema: type: integer maximum: 100 - minimum: 0 - description: Page size; 0 returns an empty page + minimum: 1 + description: Page size, 1–100 in: query name: limit - schema: @@ -2781,6 +2937,36 @@ paths: application/json: schema: $ref: '#/components/schemas/v1.SkillVersionList' + '400': + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/api.CoreErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/api.CoreErrorResponse' + '404': + description: Not Found + content: + application/json: + schema: + $ref: '#/components/schemas/api.CoreErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/api.CoreErrorResponse' + '503': + description: Service Unavailable + content: + application/json: + schema: + $ref: '#/components/schemas/api.CoreErrorResponse' security: - DeploymentAdminAuth: [] summary: List Skill versions in a Project @@ -2815,6 +3001,36 @@ paths: application/json: schema: $ref: '#/components/schemas/v1.SkillVersionDeleted' + '400': + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/api.CoreErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/api.CoreErrorResponse' + '404': + description: Not Found + content: + application/json: + schema: + $ref: '#/components/schemas/api.CoreErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/api.CoreErrorResponse' + '503': + description: Service Unavailable + content: + application/json: + schema: + $ref: '#/components/schemas/api.CoreErrorResponse' security: - DeploymentAdminAuth: [] summary: Delete a Skill version in a Project @@ -2848,6 +3064,36 @@ paths: application/json: schema: $ref: '#/components/schemas/v1.SkillVersion' + '400': + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/api.CoreErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/api.CoreErrorResponse' + '404': + description: Not Found + content: + application/json: + schema: + $ref: '#/components/schemas/api.CoreErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/api.CoreErrorResponse' + '503': + description: Service Unavailable + content: + application/json: + schema: + $ref: '#/components/schemas/api.CoreErrorResponse' security: - DeploymentAdminAuth: [] summary: Retrieve Skill version metadata in a Project @@ -2883,6 +3129,36 @@ paths: schema: type: string format: binary + '400': + description: Bad Request + content: + application/octet-stream: + schema: + $ref: '#/components/schemas/api.CoreErrorResponse' + '401': + description: Unauthorized + content: + application/octet-stream: + schema: + $ref: '#/components/schemas/api.CoreErrorResponse' + '404': + description: Not Found + content: + application/octet-stream: + schema: + $ref: '#/components/schemas/api.CoreErrorResponse' + '500': + description: Internal Server Error + content: + application/octet-stream: + schema: + $ref: '#/components/schemas/api.CoreErrorResponse' + '503': + description: Service Unavailable + content: + application/octet-stream: + schema: + $ref: '#/components/schemas/api.CoreErrorResponse' security: - DeploymentAdminAuth: [] summary: Download immutable Skill version content in a Project @@ -3451,6 +3727,12 @@ paths: application/json: schema: $ref: '#/components/schemas/api.CoreErrorResponse' + '413': + description: Request Entity Too Large + content: + application/json: + schema: + $ref: '#/components/schemas/api.CoreErrorResponse' '500': description: Internal Server Error content: @@ -3502,6 +3784,12 @@ paths: application/json: schema: $ref: '#/components/schemas/api.CoreErrorResponse' + '413': + description: Request Entity Too Large + content: + application/json: + schema: + $ref: '#/components/schemas/api.CoreErrorResponse' '500': description: Internal Server Error content: @@ -3605,6 +3893,12 @@ paths: application/json: schema: $ref: '#/components/schemas/api.CoreErrorResponse' + '413': + description: Request Entity Too Large + content: + application/json: + schema: + $ref: '#/components/schemas/api.CoreErrorResponse' '500': description: Internal Server Error content: @@ -3651,6 +3945,12 @@ paths: application/json: schema: $ref: '#/components/schemas/api.CoreErrorResponse' + '413': + description: Request Entity Too Large + content: + application/json: + schema: + $ref: '#/components/schemas/api.CoreErrorResponse' '503': description: Service Unavailable content: @@ -3698,6 +3998,12 @@ paths: application/json: schema: $ref: '#/components/schemas/api.CoreErrorResponse' + '413': + description: Request Entity Too Large + content: + application/json: + schema: + $ref: '#/components/schemas/api.CoreErrorResponse' '503': description: Service Unavailable content: @@ -3750,6 +4056,12 @@ paths: application/json: schema: $ref: '#/components/schemas/api.CoreErrorResponse' + '413': + description: Request Entity Too Large + content: + application/json: + schema: + $ref: '#/components/schemas/api.CoreErrorResponse' '500': description: Internal Server Error content: @@ -3983,6 +4295,12 @@ paths: application/json: schema: $ref: '#/components/schemas/api.CoreErrorResponse' + '413': + description: Request Entity Too Large + content: + application/json: + schema: + $ref: '#/components/schemas/api.CoreErrorResponse' '500': description: Internal Server Error content: diff --git a/apps/docs/openapi/public-api.yaml b/apps/docs/openapi/public-api.yaml index 9f8111cc0..f31b6459a 100644 --- a/apps/docs/openapi/public-api.yaml +++ b/apps/docs/openapi/public-api.yaml @@ -68,6 +68,12 @@ paths: application/json: schema: $ref: '#/components/schemas/v1.ErrorResponse' + '503': + description: Service Unavailable + content: + application/json: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' security: - BearerAuth: [] summary: List reusable Agents @@ -113,6 +119,12 @@ paths: application/json: schema: $ref: '#/components/schemas/v1.ErrorResponse' + '503': + description: Service Unavailable + content: + application/json: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' security: - BearerAuth: [] summary: Create a reusable Agent @@ -178,6 +190,12 @@ paths: application/json: schema: $ref: '#/components/schemas/v1.ErrorResponse' + '503': + description: Service Unavailable + content: + application/json: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' security: - BearerAuth: [] summary: Delete a reusable Agent @@ -229,6 +247,12 @@ paths: application/json: schema: $ref: '#/components/schemas/v1.ErrorResponse' + '503': + description: Service Unavailable + content: + application/json: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' security: - BearerAuth: [] summary: Retrieve a reusable Agent @@ -286,6 +310,12 @@ paths: application/json: schema: $ref: '#/components/schemas/v1.ErrorResponse' + '503': + description: Service Unavailable + content: + application/json: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' security: - BearerAuth: [] summary: Update a reusable Agent @@ -345,6 +375,12 @@ paths: application/json: schema: $ref: '#/components/schemas/v1.ErrorResponse' + '503': + description: Service Unavailable + content: + application/json: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' security: - BearerAuth: [] summary: Retrieve an execution Environment @@ -569,6 +605,12 @@ paths: application/json: schema: $ref: '#/components/schemas/v1.ErrorResponse' + '503': + description: Service Unavailable + content: + application/json: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' security: - BearerAuth: [] summary: List Environment Templates @@ -614,6 +656,12 @@ paths: application/json: schema: $ref: '#/components/schemas/v1.ErrorResponse' + '503': + description: Service Unavailable + content: + application/json: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' security: - BearerAuth: [] summary: Create an Environment Template @@ -673,6 +721,12 @@ paths: application/json: schema: $ref: '#/components/schemas/v1.ErrorResponse' + '503': + description: Service Unavailable + content: + application/json: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' security: - BearerAuth: [] summary: Delete an Environment Template @@ -724,6 +778,12 @@ paths: application/json: schema: $ref: '#/components/schemas/v1.ErrorResponse' + '503': + description: Service Unavailable + content: + application/json: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' security: - BearerAuth: [] summary: Retrieve an Environment Template @@ -781,6 +841,12 @@ paths: application/json: schema: $ref: '#/components/schemas/v1.ErrorResponse' + '503': + description: Service Unavailable + content: + application/json: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' security: - BearerAuth: [] summary: Update an Environment Template @@ -858,6 +924,12 @@ paths: application/json: schema: $ref: '#/components/schemas/v1.ErrorResponse' + '503': + description: Service Unavailable + content: + application/json: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' security: - BearerAuth: [] summary: List execution Sessions @@ -1021,6 +1093,12 @@ paths: application/json: schema: $ref: '#/components/schemas/v1.ErrorResponse' + '503': + description: Service Unavailable + content: + application/json: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' security: - BearerAuth: [] summary: Delete an execution Session @@ -1072,6 +1150,12 @@ paths: application/json: schema: $ref: '#/components/schemas/v1.ErrorResponse' + '503': + description: Service Unavailable + content: + application/json: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' security: - BearerAuth: [] summary: Retrieve an execution Session @@ -1129,6 +1213,12 @@ paths: application/json: schema: $ref: '#/components/schemas/v1.ErrorResponse' + '503': + description: Service Unavailable + content: + application/json: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' security: - BearerAuth: [] summary: Update execution Session metadata @@ -1618,6 +1708,12 @@ paths: application/json: schema: $ref: '#/components/schemas/v1.ErrorResponse' + '503': + description: Service Unavailable + content: + application/json: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' security: - BearerAuth: [] summary: List persisted execution Items @@ -2158,6 +2254,12 @@ paths: application/json: schema: $ref: '#/components/schemas/v1.ErrorResponse' + '503': + description: Service Unavailable + content: + application/json: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' security: - BearerAuth: [] summary: List execution Turns @@ -2216,6 +2318,12 @@ paths: application/json: schema: $ref: '#/components/schemas/v1.ErrorResponse' + '503': + description: Service Unavailable + content: + application/json: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' security: - BearerAuth: [] summary: Retrieve an execution Turn @@ -2531,6 +2639,36 @@ paths: application/json: schema: $ref: '#/components/schemas/v1.SkillList' + '400': + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' + '404': + description: Not Found + content: + application/json: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' + '503': + description: Service Unavailable + content: + application/json: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' security: - BearerAuth: [] summary: List Skills @@ -2545,6 +2683,36 @@ paths: application/json: schema: $ref: '#/components/schemas/v1.Skill' + '400': + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' + '413': + description: Request Entity Too Large + content: + application/json: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' + '503': + description: Service Unavailable + content: + application/json: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' security: - BearerAuth: [] summary: Upload a Skill @@ -2578,6 +2746,36 @@ paths: application/json: schema: $ref: '#/components/schemas/v1.SkillDeleted' + '400': + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' + '404': + description: Not Found + content: + application/json: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' + '503': + description: Service Unavailable + content: + application/json: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' security: - BearerAuth: [] summary: Delete a Skill and its versions @@ -2599,6 +2797,36 @@ paths: application/json: schema: $ref: '#/components/schemas/v1.Skill' + '400': + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' + '404': + description: Not Found + content: + application/json: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' + '503': + description: Service Unavailable + content: + application/json: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' security: - BearerAuth: [] summary: Retrieve Skill metadata @@ -2620,6 +2848,42 @@ paths: application/json: schema: $ref: '#/components/schemas/v1.Skill' + '400': + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' + '404': + description: Not Found + content: + application/json: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' + '413': + description: Request Entity Too Large + content: + application/json: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' + '503': + description: Service Unavailable + content: + application/json: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' security: - BearerAuth: [] summary: Update the default Skill version @@ -2650,6 +2914,36 @@ paths: schema: type: string format: binary + '400': + description: Bad Request + content: + application/octet-stream: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' + '401': + description: Unauthorized + content: + application/octet-stream: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' + '404': + description: Not Found + content: + application/octet-stream: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' + '500': + description: Internal Server Error + content: + application/octet-stream: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' + '503': + description: Service Unavailable + content: + application/octet-stream: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' security: - BearerAuth: [] summary: Download Skill content @@ -2692,6 +2986,36 @@ paths: application/json: schema: $ref: '#/components/schemas/v1.SkillVersionList' + '400': + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' + '404': + description: Not Found + content: + application/json: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' + '503': + description: Service Unavailable + content: + application/json: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' security: - BearerAuth: [] summary: List Skill versions @@ -2712,6 +3036,42 @@ paths: application/json: schema: $ref: '#/components/schemas/v1.SkillVersion' + '400': + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' + '404': + description: Not Found + content: + application/json: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' + '413': + description: Request Entity Too Large + content: + application/json: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' + '503': + description: Service Unavailable + content: + application/json: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' security: - BearerAuth: [] summary: Upload an immutable Skill version @@ -2754,6 +3114,36 @@ paths: application/json: schema: $ref: '#/components/schemas/v1.SkillVersionDeleted' + '400': + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' + '404': + description: Not Found + content: + application/json: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' + '503': + description: Service Unavailable + content: + application/json: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' security: - BearerAuth: [] summary: Delete a Skill version @@ -2780,6 +3170,36 @@ paths: application/json: schema: $ref: '#/components/schemas/v1.SkillVersion' + '400': + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' + '404': + description: Not Found + content: + application/json: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' + '503': + description: Service Unavailable + content: + application/json: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' security: - BearerAuth: [] summary: Retrieve Skill version metadata @@ -2808,6 +3228,36 @@ paths: schema: type: string format: binary + '400': + description: Bad Request + content: + application/octet-stream: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' + '401': + description: Unauthorized + content: + application/octet-stream: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' + '404': + description: Not Found + content: + application/octet-stream: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' + '500': + description: Internal Server Error + content: + application/octet-stream: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' + '503': + description: Service Unavailable + content: + application/octet-stream: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' security: - BearerAuth: [] summary: Download immutable Skill version content @@ -2892,6 +3342,12 @@ paths: application/json: schema: $ref: '#/components/schemas/v1.ErrorResponse' + '503': + description: Service Unavailable + content: + application/json: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' security: - BearerAuth: [] summary: List Vaults @@ -2937,6 +3393,12 @@ paths: application/json: schema: $ref: '#/components/schemas/v1.ErrorResponse' + '503': + description: Service Unavailable + content: + application/json: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' security: - BearerAuth: [] summary: Create a Vault @@ -3002,6 +3464,12 @@ paths: application/json: schema: $ref: '#/components/schemas/v1.ErrorResponse' + '503': + description: Service Unavailable + content: + application/json: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' security: - BearerAuth: [] summary: Delete a Vault and all its Credentials @@ -3053,6 +3521,12 @@ paths: application/json: schema: $ref: '#/components/schemas/v1.ErrorResponse' + '503': + description: Service Unavailable + content: + application/json: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' security: - BearerAuth: [] summary: Retrieve a Vault @@ -3143,6 +3617,12 @@ paths: application/json: schema: $ref: '#/components/schemas/v1.ErrorResponse' + '503': + description: Service Unavailable + content: + application/json: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' security: - BearerAuth: [] summary: List safe Vault Credential metadata @@ -3277,6 +3757,12 @@ paths: application/json: schema: $ref: '#/components/schemas/v1.ErrorResponse' + '503': + description: Service Unavailable + content: + application/json: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' security: - BearerAuth: [] summary: Delete a Vault Credential @@ -3334,6 +3820,12 @@ paths: application/json: schema: $ref: '#/components/schemas/v1.ErrorResponse' + '503': + description: Service Unavailable + content: + application/json: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' security: - BearerAuth: [] summary: Retrieve safe Vault Credential metadata diff --git a/apps/docs/openapi/runtime-api.yaml b/apps/docs/openapi/runtime-api.yaml index 18835818d..a5fad6961 100644 --- a/apps/docs/openapi/runtime-api.yaml +++ b/apps/docs/openapi/runtime-api.yaml @@ -30,6 +30,12 @@ paths: application/json: schema: $ref: '#/components/schemas/api.CoreErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/api.CoreErrorResponse' '503': description: Service Unavailable content: @@ -63,6 +69,18 @@ paths: application/json: schema: $ref: '#/components/schemas/api.CoreErrorResponse' + '413': + description: Request Entity Too Large + content: + application/json: + schema: + $ref: '#/components/schemas/api.CoreErrorResponse' + '500': + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/api.CoreErrorResponse' '503': description: Service Unavailable content: @@ -169,6 +187,12 @@ paths: application/json: schema: $ref: '#/components/schemas/v1.ErrorResponse' + '413': + description: Request Entity Too Large + content: + application/json: + schema: + $ref: '#/components/schemas/v1.ErrorResponse' '500': description: Internal Server Error content: diff --git a/apps/docs/openapi/sources.json b/apps/docs/openapi/sources.json index e5ba3e4f7..89ecf1684 100644 --- a/apps/docs/openapi/sources.json +++ b/apps/docs/openapi/sources.json @@ -1,53 +1,226 @@ { "sources": { - "contracts/agents-api/openapi.yaml": "42ae2585b0abe60860de99a6958b639a495a0d9b7c3d0142b199a427fa77b5a5", - "contracts/agents-api/core.openapi.yaml": "f1b9278c3a4b1cb55127cf9471583d00f1ab13b6ceb64f8693a01c4cf03674eb", - "contracts/agents-api/runtime.openapi.yaml": "505286d5eacf94a14f9527fcf4e7beb4fba4f792681be26ba966254cbf49b4aa" + "contracts/agents-api/openapi.yaml": "8051d41d848957b487cc5f2b470a6ec3789110b5ced4ae90f7fbf96ac69ffb6f", + "contracts/agents-api/core.openapi.yaml": "2a351d8e305097853e5404484a8c0b8e9545eb17d72b42da72025273d5941637", + "contracts/agents-api/runtime.openapi.yaml": "d86fa523c6444b7292c06290800cee35dbc723d84dad5740c1d92776fb4165bc" }, "outputs": { - "content/docs/api-reference/agents.mdx": "1f7697959e9c52c9d24fbe70e116e807f49912b9a27ac638b86782e2f326af44", - "content/docs/api-reference/environments.mdx": "6a9e08a67479a745983c45b9711137617c13fdf7599a64533997b00a26ac7282", - "content/docs/api-reference/environment-templates.mdx": "68df9276e858e525e15bb88af624fc8adee8bcdcc03a788faaff56b560fd038c", - "content/docs/api-reference/sessions.mdx": "68a839427c3ff380644fd79e7876fd8fac7a6792179eb3cb9ed376f5953e6e46", - "content/docs/api-reference/artifacts.mdx": "8df8d008126b49b1df88f28a676c4b237ccffc45a470b35ec30eab2daf1c0f7f", - "content/docs/api-reference/events.mdx": "fa509794f3c208c0cdcdaa68615c26b7e400ea6c892922a4e0a6a833e42fe5dd", - "content/docs/api-reference/items.mdx": "fa4d248ac5623beb3f00a4ebb5a6c4ff477865ebee351e0c543a970a7ec3654d", - "content/docs/api-reference/subagents.mdx": "90e2a1a9129111332e36715de2078ee595590c4c25c7b355962e4185bdeb5388", - "content/docs/api-reference/turns.mdx": "46ee9e43aae4ec85b3ee335939dc1e0a238cfda0fb996c6af4d2831bef3377f1", - "content/docs/api-reference/files.mdx": "531c835c66b194ab8876c7663b79e42f0090e12420ae32fafeda24e3143740f4", - "content/docs/api-reference/skills.mdx": "774ea05a7a8250fe5af5164388b98dafca99d56dc2eae686e8f628acb4e7c10b", - "content/docs/api-reference/vaults.mdx": "d80eade1c2f8100030866abbb0fb6b7a09c94250a859c97cdf1abce32fdfdf1e", - "content/docs/api-reference/credentials.mdx": "f129a51f74a3c7021c016600518e2350023f8d29571666ac5d64b7584cd7c7d0", - "openapi/public-api.yaml": "3cdee54523822cd19766771dae4c13a64d6e318ca8e9d5fabe8339e975c8ac25", - "content/docs/api-reference/meta.json": "56bf1dc145ccc8adde38c5f956f1a06f18ef18b646122250d01a294c516f8f83", - "content/docs/api-reference/index.mdx": "9fd6b1c54149874d2999235067c101326f9e8a2e707a70b6672c81eb3ebfe63f", - "content/docs/api-reference/core/core-administration.mdx": "5fc3ada51d2190a141f13738151e4d513390cc3bd66ce6f5013994bda68569b0", - "content/docs/api-reference/core/deployment-model-providers.mdx": "fb15ed2075e256a3fe0222641f95c48c962563325668817ac7cb2a940d9b125d", - "content/docs/api-reference/core/administrator-projects.mdx": "8fd687bb2a7119fa16e938d7c71710c2816afb9cf959eb6849ef5e6300c5419b", - "content/docs/api-reference/core/agents.mdx": "b6c089fbea4b07bc4249e7c7ca5699d47f1512a4fc2d8ee01cb26910ae541a84", - "content/docs/api-reference/core/environment-templates.mdx": "05907f35d7f02d66af9da8b1efaa3765badb4cdf7b94d0f6c3ab0413a2cfa1a9", - "content/docs/api-reference/core/executor-credentials.mdx": "352dc9cb02cceab6a7fa4fe13356e9532c329277224e7e01d18ae0c02cad1a3e", - "content/docs/api-reference/core/native-installation.mdx": "4399eb6c36a221c9459d6773b0bd3b49ce92df120fbca86f99377bcbb1f77811", - "content/docs/api-reference/core/files.mdx": "05ce1d2296dbb3fc76cf4cf98d24dff249114c73529335214cee97363229f384", - "content/docs/api-reference/core/write-audit.mdx": "1298590ab7037077e56f6ab8adb020277763f7a670be796d24142323b2f95411", - "content/docs/api-reference/core/sessions.mdx": "52db14e7c88cb0521a12a9b3d19b14dd38583b97e716b261a44b2bd6bf05140a", - "content/docs/api-reference/core/artifacts.mdx": "620fe72cd41d19b9694fe7080eb8935ef44292852400c7be1c03a893613ca89c", - "content/docs/api-reference/core/execution-configuration.mdx": "f6a9ed4cdb73e87f5f4ce16b4f6fa14b756d07c97f2741bd5cade34a3472c548", - "content/docs/api-reference/core/items.mdx": "7c7b006536d155d003097a504e9931e3dc4d9fd0426852573244453634729250", - "content/docs/api-reference/core/runtime-history.mdx": "eec6384c6fd5a2bf223ec7dc7ee19332440936e18fc67f782fe81b96e299f634", - "content/docs/api-reference/core/runtime-observations.mdx": "db3a238ba77d1fcb887835d51b6f3f8f2b6bdf9cc5e14ac6dd11074a1c75ed48", - "content/docs/api-reference/core/turns.mdx": "53f9472de3e0958c06db7e69d7e8f10119e6540b7f05683915248e08d5284b16", - "content/docs/api-reference/core/skills.mdx": "ed899ade7b032b1732b3097d81419a8fdbb9ead0594fca9f2107da644b97031f", - "content/docs/api-reference/core/vaults.mdx": "12d0aac96cd4a3472ef4eaa287f7945f78862017956e79bfc3ed0ef8e772e78a", - "content/docs/api-reference/core/credentials.mdx": "27d586b9a8fd738b9947802f32c80458195370252886bc26abedccf2125ee981", - "content/docs/api-reference/core/sandbox-manager.mdx": "45e65afffb25e5b6ee2ab0853d7a84dee164e0d44ea384675fbd7ffcbd6c1a58", - "openapi/core-api.yaml": "dc8e80ada4ef8bd93635cab2c5d337b9d7661991a6baa1f69dc4258ebe434ef9", - "content/docs/api-reference/core/meta.json": "d0aef1f54c4cfc30b4e1d974119ae1cdce1c87d5ecba723afbeb4599119482a7", - "content/docs/api-reference/core/index.mdx": "57cf9ea947ef45e79575c25a0a3d4e5e856dde6d14698ccc2c51b86201c249e9", - "content/docs/api-reference/machine/native-installation.mdx": "421a858685b79fdcf8d7eff308c5768d1b62385c3988c6089f380afe80aaed69", - "content/docs/api-reference/machine/sandbox-node.mdx": "5b367a08d43cea82686345d2ba1c75cc90627a7b2970fe42a0df9d77fb3e1e80", - "openapi/runtime-api.yaml": "00be7da2088c0660ec27e656063a0b74eafe97716426ce6aec756e9e942986e8", - "content/docs/api-reference/machine/meta.json": "aa7e1045fb250535d77cdf54b4d2de12a1403e12439e74ce0e16890aadcd93dc", - "content/docs/api-reference/machine/index.mdx": "335881803f4603a759ab88085e8c46754d6b2450da9b1d9338a87968af5871a2" + "content/docs/api-reference/agents/list-reusable-agents.mdx": "7088580883b9c0cb1b010459fe63b30d6a1bc454e541873d3892b381e95fe03b", + "content/docs/api-reference/agents/create-a-reusable-agent.mdx": "ae47d91ea3740c2cd4b3d66e5af57c8229b1bb9c2862522f14f00472e678d315", + "content/docs/api-reference/agents/retrieve-a-reusable-agent.mdx": "3e80c8726b91b6728b8dc5b69e05ab5ccf02ac0ec4f6a5bba57bd8cf2fc848d4", + "content/docs/api-reference/agents/update-a-reusable-agent.mdx": "a01a16c30fab72ce70e7e3afe03e872f92a571ebd7cdad8b327b44ea30ded6a7", + "content/docs/api-reference/agents/delete-a-reusable-agent.mdx": "e4b450ecd9252e0fbe9136bd3513fe4b4aa8b2fb7231f43bf316cd64486693c8", + "content/docs/api-reference/environments/retrieve-an-execution-environment.mdx": "faff964554b886027e40295a6faa8dd3606201083b1f2c0ba76fc9ba121a35c9", + "content/docs/api-reference/environments/list-live-environment-files.mdx": "eda89a737d5c099eb3f04025b76a3ece49e9bf318910860808455ba19c1f2c97", + "content/docs/api-reference/environments/create-an-environment-file-from-inline-bytes-or-a-source-file.mdx": "7e2d083779c52478096eb53c9cac760463fd8577502d042c70bc673dda33eda8", + "content/docs/api-reference/environment-templates/list-environment-templates.mdx": "200027af50cfae5c6a2b39bdde4e75b33513c3fe88d07310fa5bd243039ff08b", + "content/docs/api-reference/environment-templates/create-an-environment-template.mdx": "58761a1881f4d435b9dbdc2e2f41634c6b95fe287b8a76f40845f52ba2485e63", + "content/docs/api-reference/environment-templates/retrieve-an-environment-template.mdx": "146532b416c09fae087a1439244e38f29409da4bee4b354f2d3198fd88598b3c", + "content/docs/api-reference/environment-templates/update-an-environment-template.mdx": "4b1ea639682fdce2bce063cea68cf2928fff646d59235a5d4e17c657193fa7d9", + "content/docs/api-reference/environment-templates/delete-an-environment-template.mdx": "c6f10446d1ca50e0a490c0296aca5d01f39c8ce96423732a271f729575dc278c", + "content/docs/api-reference/sessions/list-execution-sessions.mdx": "fbd004c1385d827feb7c4d9398c3b91297b10c42588186b6e7125b5a38e09b0b", + "content/docs/api-reference/sessions/create-an-execution-session.mdx": "af343c0296b6cc47d1a3f220a63b8b1423afc1c6fd68684d6e71f66ee9e408bb", + "content/docs/api-reference/sessions/retrieve-an-execution-session.mdx": "538ec687302c904eb47f6fc00f760a5f6964782d835ab4262ebc531b27c75161", + "content/docs/api-reference/sessions/update-execution-session-metadata.mdx": "f3ad7c0fa0bdb9c6e2afb9382aaa0370fd523a7363904416d12ecebf1e3c8e86", + "content/docs/api-reference/sessions/delete-an-execution-session.mdx": "51afc3a526d6f457df3690119e6771dafcf420850a067ba9a420c712bef85aa3", + "content/docs/api-reference/artifacts/list-immutable-session-artifacts.mdx": "3d586e17f19e24844712bee7aa0515d3fe3e6c9b3452927b3a07953771b94fb9", + "content/docs/api-reference/artifacts/retrieve-immutable-artifact-metadata.mdx": "3bbd8a04508bd0e557f99fda389d19d29f2dd5eddb325f5dc7f5876b2fb79a03", + "content/docs/api-reference/artifacts/delete-a-published-artifact.mdx": "7f45066a7d4ca2db500625a22f14116bd1ef8a77fb15fbecf51a45ce4b6dcee8", + "content/docs/api-reference/artifacts/download-immutable-artifact-bytes.mdx": "e5f842289d785399eb2e6b43a3740f34a170cd771574e2eadc02bde57a0607b7", + "content/docs/api-reference/events/stream-live-session-events.mdx": "dfb350eda50b6349a15394359de6f95e534d43b2f521da070836d0fae23ed013", + "content/docs/api-reference/sessions/submit-session-input-events.mdx": "5005034faa3d33d5133a4081c13827d33981f82af2313650639fdbdb2b089413", + "content/docs/api-reference/items/list-persisted-execution-items.mdx": "a94e0c89918ec26d5964e731abf06f9ed7ad58168757df5660975855e63f8ec0", + "content/docs/api-reference/subagents/list-session-subagents.mdx": "bed7a780c8b4e75f2cb32b56fb95d502c4ba02ad8646dc4748c0f1bd5fb4943f", + "content/docs/api-reference/subagents/retrieve-a-session-subagent.mdx": "a203ebd474073bb78b249a52a4cf9c3359725e4a6b8580db41f488fd0daec7d0", + "content/docs/api-reference/subagents/list-a-subagent-s-items.mdx": "02f4ed5cb16ca85536909ce14eee2d2eccfc0740366497cb59db76f1394663d4", + "content/docs/api-reference/subagents/list-a-subagent-s-turns.mdx": "87e788c70ac3641827b5c7fd77d55dc33aad0cf14f21b8610377f764964a4261", + "content/docs/api-reference/subagents/retrieve-a-subagent-turn.mdx": "bd1c1ec67c42af99763e10f1d3d2934fc552a5425d23952116182d9d275a9268", + "content/docs/api-reference/subagents/list-a-subagent-turn-s-items.mdx": "0b135b5740efa2eb7426786b272cb029ffcbf075e4f1b73179d49d2d94dc131e", + "content/docs/api-reference/turns/list-execution-turns.mdx": "999a793dce64a548a4d135103a5f14017dc847c8cce3a984dd1a0444e0917e56", + "content/docs/api-reference/turns/retrieve-an-execution-turn.mdx": "79d8954705d11926a24423bbcd227b123cd4b5668ee21cd2c7554b2f7501b071", + "content/docs/api-reference/files/list-source-files.mdx": "a9928c05c70ff7202c69bab3b11fc047aa04520784fa1c41c8e47566fcd66591", + "content/docs/api-reference/files/upload-a-source-file.mdx": "2e8d8e4210f6f209927ce05f6aa2e785a85d151ea23f3a59c9f2ba664ad6b2cf", + "content/docs/api-reference/files/retrieve-source-file-metadata.mdx": "1325fbf3250d93ff76c414922a217de131433fe0c53bf4418cd357cf5cdf5084", + "content/docs/api-reference/files/delete-a-source-file.mdx": "9df0b10380b32baf8e9ffb3ee3ef28480f87090e83f9d828cb68f71ceb287f71", + "content/docs/api-reference/files/download-source-file-bytes.mdx": "cbd88af502663e0156d06d72ac9556b8659ac158b22c62336310cd3e01450c01", + "content/docs/api-reference/skills/list-skills.mdx": "949fc0878718db896b51ffbf532503d6eb438805e404ec07b63d2e66bc713da5", + "content/docs/api-reference/skills/upload-a-skill.mdx": "856e6f4bacb63695bf2ea39df4065f06d20a766f238387b82e4e0e170cc23e74", + "content/docs/api-reference/skills/retrieve-skill-metadata.mdx": "7800ad04ef8d1d9d8440e7f7ad8935bce9f7eb2aad0e37a30f00bfac5535cd7a", + "content/docs/api-reference/skills/update-the-default-skill-version.mdx": "155cd416b020eacbaf58e57f7e65bb1aef51d781aa741704af4530a9c7c6533a", + "content/docs/api-reference/skills/delete-a-skill-and-its-versions.mdx": "f575472b8c5ef0bd0478b1ba487c3a6b513f1f46a327894c853abda02c3496b9", + "content/docs/api-reference/skills/download-skill-content.mdx": "f88343647df91f1d61d84dd6936e2965c7184858336ea24098f5e810812fbcf9", + "content/docs/api-reference/skills/list-skill-versions.mdx": "a5a9e1ac821229f091c09974213adbea86704745da2d8230212bf65657b37a09", + "content/docs/api-reference/skills/upload-an-immutable-skill-version.mdx": "f3175fc7daa600f8ff631cad2901d4cf77d8614a6b190d7259a1d66c555f6dbf", + "content/docs/api-reference/skills/retrieve-skill-version-metadata.mdx": "c31a6cc117e2241fc0cb374e2ba9012702ed7913de6bb50fb928392881583121", + "content/docs/api-reference/skills/delete-a-skill-version.mdx": "ae04aace77dfd22e8f78cd00c854dd166868f1271311f34ce917e8379737e222", + "content/docs/api-reference/skills/download-immutable-skill-version-content.mdx": "3a99d20833a4260256122c21ae422e9704670c249e0db382272a4de00fcec298", + "content/docs/api-reference/vaults/list-vaults.mdx": "940b525048730c26cca42c1d2c1def11153e14560a5e3f1ea8296aff2580cb5a", + "content/docs/api-reference/vaults/create-a-vault.mdx": "ea89b1d5db6c43e1634a9d96cad5b5a746e28f0502799c86b5c7692c21909cc3", + "content/docs/api-reference/vaults/retrieve-a-vault.mdx": "41f6a66ed3d67e908bbb62df2b3b198dba49b52402c44b27f8e3c3057df39c1c", + "content/docs/api-reference/vaults/delete-a-vault-and-all-its-credentials.mdx": "223b9f22a7667d2048ae4053f0786b34f68b07f2433654f277b60b8f2141a4f1", + "content/docs/api-reference/credentials/list-safe-vault-credential-metadata.mdx": "a5c6111261defed35c369fd843eeaaa7f66f7b19a83c1d991237fc9ab506a5a4", + "content/docs/api-reference/credentials/create-a-vault-credential.mdx": "1a2125f543f33f65eee95dd3d7c6c71d63cf2bf9cafbf7d279434ff56cd1d340", + "content/docs/api-reference/credentials/retrieve-safe-vault-credential-metadata.mdx": "26422a11f99cbf28e9c2726c25f9e53bbc37e4d9f629afb88bbe7250ed9a8d42", + "content/docs/api-reference/credentials/replace-vault-credential-authentication-secrets.mdx": "148ac1190942da3e966cbcd2b3d8a5e7751f9f0cc732520a7026b17e216cb3a6", + "content/docs/api-reference/credentials/delete-a-vault-credential.mdx": "e4c6d9673fdc956e017a086496f63ae555afc4db0993f5c817cdc1bb31f6f9d0", + "content/docs/api-reference/agents/index.mdx": "ba75fecd1f307bc18d193cfe11ce839275cdf26535317e1e5db52b5ba43cbc44", + "content/docs/api-reference/agents/meta.json": "2ddb2be361a2ab20777e1dceb0587626496ab2a1183bcc07b2a960c61ba13215", + "content/docs/api-reference/environments/index.mdx": "39dd4d122a40ff25f33313c2e5af18f777a1efb52cae8985a31cfb825f4b4baa", + "content/docs/api-reference/environments/meta.json": "f7146efe4d037368088a0dd457f8083f8916aa6068fe3b6551c8354dff9dbb2a", + "content/docs/api-reference/environment-templates/index.mdx": "c9e4a8444966cad4904114e91259519c05cd78d9f15d6d47bd80a636d56ac570", + "content/docs/api-reference/environment-templates/meta.json": "7e654f6d3579d0acc7bca8346d208d062ba6edb6a2e4516f34caa4e586a400db", + "content/docs/api-reference/sessions/index.mdx": "065928161cda6cada14ed8f31c10fe35a0a1533654ef7d67acbfc96bc5e82c24", + "content/docs/api-reference/sessions/meta.json": "396d8ca196ef13796b3a3a348ed1d26c2cb426cff2ce081e7789d5a2ed61d507", + "content/docs/api-reference/artifacts/index.mdx": "813b5b893b53215e066cb0c4217215338db4697b58598182f0cdde084164a812", + "content/docs/api-reference/artifacts/meta.json": "e6d319d32e5d220489961fa04ad396bb0682c20e1dc1a3a78be2612cf0f258ba", + "content/docs/api-reference/events/index.mdx": "7d888f6482e454f0b635d7dc1dcca1c8999cab454eabc8fdaf5810a540ca2a48", + "content/docs/api-reference/events/meta.json": "83e461ec66ed11c32f91093e4e0441cf9c13890c8eab9ea0914754d345187e88", + "content/docs/api-reference/items/index.mdx": "68e3d8c5f91c14af9a8cb0df710bc77b1f9621105e2e11012e6ee7b28924c756", + "content/docs/api-reference/items/meta.json": "b6771959fd8245eebd4f709a25497a73761b9bb4f0007f846c05fcbf3c3d3694", + "content/docs/api-reference/subagents/index.mdx": "7ba58cd5f54152effb1b68056d00f90fbe385c3f848c36d7393fa582e3c0b143", + "content/docs/api-reference/subagents/meta.json": "b0eda839cbd12c09f7269936b48c18407a9179807ec0c3b03572ae071ff1957f", + "content/docs/api-reference/turns/index.mdx": "dbd5ff0b9936a7c659d20066666aee449065942b6f68fbbab542653b57147d7d", + "content/docs/api-reference/turns/meta.json": "3907409967b3bf58d7d98a5f5228bb2094563b602d21db5dde6fc865fa852795", + "content/docs/api-reference/files/index.mdx": "2c55201787c2a8f5f3b281599181cdfaf4c25749a7aa53adbc4ade783dc05658", + "content/docs/api-reference/files/meta.json": "aa5843ddc46be26d2056e6c8e08f1057c0ab6411e7f12e32aeffce26fb87b91e", + "content/docs/api-reference/skills/index.mdx": "2b8a389523151ffbe5b7d2ac56bbc304eed349a01c547983507c0e6e6e47f514", + "content/docs/api-reference/skills/meta.json": "7247dd6590eda42d9f93af3672b07e2fe1a98b70f5fbc728f4cd63e16eda6553", + "content/docs/api-reference/vaults/index.mdx": "2296f2c171c320300ae47950d490946e0537dc777f42375fd44904ebda27291c", + "content/docs/api-reference/vaults/meta.json": "2cc123f3d126020773a12642bbb867bb789e1f311dcd901a61873fa4f4e09cd5", + "content/docs/api-reference/credentials/index.mdx": "e4a08a3907dac0023900b44090f6ad665b508cb620b71a932ca788705dd9a780", + "content/docs/api-reference/credentials/meta.json": "5e3368b7f365590f31c245fb326fe25c8d3ab82ee4e79e03df10ea016e7b3da3", + "content/docs/api-reference/meta.json": "d8d58d48c955a9b161d880805bc3634617566fe3f1780ee170878358412cafe4", + "content/docs/api-reference/index.mdx": "b32be3060e86fefc5f6b32a67353a2621ea2e7cfd88a69fa19caf67e6ab28d00", + "openapi/public-api.yaml": "3f034ebe892b200f06fb44cb265c244456527fe04811d2c3e1a0e2bf14b7d0f8", + "content/docs/api-reference/core/core-administration/query-committed-administrator-mutations.mdx": "bab0589c4dd5944b24594eb2cab6e2266075ce77b7e224cf57a63b9c8e0c89af", + "content/docs/api-reference/core/deployment-model-providers/list-harnesses-and-their-deployment-default-model-providers.mdx": "05a4ef8d4d41c97221a805a4184242b32bd25754223984f36552cf44ec0a7332", + "content/docs/api-reference/core/deployment-model-providers/retrieve-a-harness-s-deployment-default-model-provider.mdx": "7a4aeeb7603fd1328b3145dada0a0778cf9929f91b25938399c465de916b87d6", + "content/docs/api-reference/core/deployment-model-providers/remove-a-harness-s-deployment-default-model-provider.mdx": "b97841a689bb5b72628407068c7b21fd38a75e166b064f29197688bc02f60a73", + "content/docs/api-reference/core/deployment-model-providers/replace-a-harness-s-deployment-default-model-provider.mdx": "99441d2e0a4ed78a1d77307bd9aea008945d97ab0309a81bbb04374ea2dc9025", + "content/docs/api-reference/core/core-administration/retrieve-installation-facts-and-process-settings.mdx": "ece8508bb649e402094dbbf1a8ab1ccdf1549f11b495ff12f15f9ea4f9c00db9", + "content/docs/api-reference/core/core-administration/retrieve-core-operational-metrics.mdx": "183a16362287ab903c10869d7648869ab59da9dbb4d34d66092f9401baca006e", + "content/docs/api-reference/core/administrator-projects/list-projects-and-active-key-counts.mdx": "520c6b56eaa1bf4145ee76f638e36b117dfb3375ab55cafa8512d2d76f59ce51", + "content/docs/api-reference/core/administrator-projects/create-an-empty-independent-project.mdx": "e0c2a3365fb3649e143376ecd55d873f28f98eb4d454453721262483d8690a96", + "content/docs/api-reference/core/administrator-projects/rename-a-project.mdx": "3d0465c69c5594658d9865b1a8b537bf0643ffb1ab66415803baab2550c02f49", + "content/docs/api-reference/core/agents/list-reusable-agents-in-a-project.mdx": "caa598d66b189b3a23d205ff336674acd73aaab6083d3e6c341908d6b7c61627", + "content/docs/api-reference/core/agents/retrieve-a-reusable-agent-in-a-project.mdx": "01c0ccc9997e59205813269138faaaaf8b1f6dd6bb9c88334b1137f8e43f6327", + "content/docs/api-reference/core/agents/delete-a-reusable-agent-in-a-project.mdx": "5c422ab853e48f57d40daf0e4c10168a44ff6814cb471b51ea1255a8dc1273e3", + "content/docs/api-reference/core/administrator-projects/archive-a-project-and-revoke-all-its-keys-while-retaining-assets.mdx": "4773be3ad0ef73fffab399a69513fc8481f231a2afdab510834a59d5f933bf5d", + "content/docs/api-reference/core/environment-templates/list-environment-templates-in-a-project.mdx": "f3fce306cc91afbd870e48b1fd5cc1ba81e3a676e8c45f48edefac39b78855a4", + "content/docs/api-reference/core/environment-templates/retrieve-an-environment-template-in-a-project.mdx": "e17f5f71ccb2af707c4d28887800e974512c33c9ef5999d6a27494879d897938", + "content/docs/api-reference/core/environment-templates/delete-an-environment-template-in-a-project.mdx": "c644d843f6b2b267277cd7af86517a363295d8381f62a623ecf4d030e23bf520", + "content/docs/api-reference/core/executor-credentials/list-a-self-hosted-environment-s-executor-credentials.mdx": "30e4317bcf933a8610b7004dea19ddca82fb168abd0c687bda36bbfd2d6f3870", + "content/docs/api-reference/core/executor-credentials/issue-or-explicitly-rotate-a-self-hosted-environment-executor-credential.mdx": "2ae6b0b5dfd335ea17382e7e12295b1114258dac2d2cf4d3ab9d750ebed062bd", + "content/docs/api-reference/core/executor-credentials/revoke-a-self-hosted-environment-executor-credential.mdx": "4bf944aae82e26c8dec50b2db343fd817871eb1408365d45e8e3a5655970e5c8", + "content/docs/api-reference/core/native-installation/get-a-self-hosted-session-s-installation-commands.mdx": "3ab39864a402e89ccf6ffd7bbed4d32a2ef6a741fb6da3662354d85a4da2aa1e", + "content/docs/api-reference/core/files/list-source-files-in-a-project.mdx": "66f506d01fec625a85252cdaf5b18a6bb0aa3f829b43115db4a6518e40532f5d", + "content/docs/api-reference/core/files/retrieve-source-file-metadata-in-a-project.mdx": "60ec69fc6a5a0b94e94cd9ea3a98784433dd7dd9743d01d0c26e3ab20cd4a5a8", + "content/docs/api-reference/core/files/delete-a-source-file-in-a-project.mdx": "3c1bd990656b421c530c65a8588a1bc7550ac1b1ecd8fa6ef6d283e6918fcae8", + "content/docs/api-reference/core/administrator-projects/list-safe-key-metadata-for-a-project.mdx": "8d3d8218225bd9b89e62cf16598409bd6be5f4e16da6f414b7386b6bb5b7aee7", + "content/docs/api-reference/core/administrator-projects/issue-an-independent-secret-in-an-existing-project.mdx": "a9897229218a8ab0ff8ea1398a6e38bfc1582de32065b00ad0e9345c37a8d265", + "content/docs/api-reference/core/administrator-projects/revoke-one-project-key-while-retaining-shared-assets.mdx": "d83bee4021b2613c4286898ecd9c166ca2e8f44af6ffd376fbec482abaf8370f", + "content/docs/api-reference/core/write-audit/batch-lookup-resource-creation-keys.mdx": "764359c2e06f6401a370a1a49f900e28fc3a9a899eaa373b633afb7ec4fb708d", + "content/docs/api-reference/core/sessions/list-execution-sessions-in-a-project.mdx": "62a212d40d375d3c008a476e8496a00471213182159cec631be4d2290f38cd0b", + "content/docs/api-reference/core/sessions/retrieve-an-execution-session-in-a-project.mdx": "eaa87cf0858ccc581d10c084a92c043bb0b642be25c86bd8a8f95d82acb814b1", + "content/docs/api-reference/core/sessions/delete-an-execution-session-in-a-project.mdx": "217f97912fd65d3d2787832532d98ed41237ef6a916b33077a206d598161b961", + "content/docs/api-reference/core/core-administration/retrieve-a-managed-session-s-resource-cleanup-state.mdx": "7ccf1479a9bd847ca8b22d86aea6869847f1e0e8db0aea60fff1bf74c20e4421", + "content/docs/api-reference/core/core-administration/release-a-managed-session-s-execution-resources-while-retaining-history.mdx": "9bfd710a716c1cb998ae7533f9677cfec458db1c9972a242dc3f72553206311c", + "content/docs/api-reference/core/artifacts/list-immutable-session-artifacts-in-a-project.mdx": "dea6f358bc70ee1ed34ed3b8260792d6442b7809c6b279a62726465a6ccb5f02", + "content/docs/api-reference/core/artifacts/retrieve-immutable-artifact-metadata-in-a-project.mdx": "81ee1652348de1ef10719d3236f3d00c98fe5a6b4e213977898ad1a9cb3d3334", + "content/docs/api-reference/core/artifacts/delete-a-published-artifact-in-a-project.mdx": "d52aa4ae83e48de4c12756af06c6923ea5ae89682f758e02a73696906f43cdfc", + "content/docs/api-reference/core/artifacts/download-immutable-artifact-bytes-in-a-project.mdx": "817f6ff7b1159dcb2088bcbb61ccc46132fa56e7cdec89e009a5b2247e89dc0f", + "content/docs/api-reference/core/sessions/retrieve-root-session-diagnostics.mdx": "3d5320afcc3baf5d87e155f56f1004d60396684e257443c03dedede706e27cb0", + "content/docs/api-reference/core/execution-configuration/retrieve-a-session-s-frozen-execution-configuration-in-a-project.mdx": "8c1d75bcc6055a08d7ae2e4c04d4636541fc04763590fdfbaa453e874ffed379", + "content/docs/api-reference/core/items/list-persisted-execution-items-in-a-project.mdx": "b0880a19798c58b23d4449b4b10bd6df1230946b7db7e27fe3761bf7e5135b4c", + "content/docs/api-reference/core/runtime-history/retrieve-session-runtime-history-in-a-project.mdx": "a116e130dbfe9cf3a867071a3438e7b3a8a90dca91c8e71494a4088eccbd2755", + "content/docs/api-reference/core/runtime-observations/retrieve-a-session-runtime-observation-in-a-project.mdx": "eec44212e62f594cdeedc8de9ba578e7e17895e9f7e6c12f5c641d5138eafa60", + "content/docs/api-reference/core/turns/list-execution-turns-in-a-project.mdx": "b04ce4228c0831a38728a2142da728604191ccf9e52e63848fda3a99c32cad57", + "content/docs/api-reference/core/turns/retrieve-an-execution-turn-in-a-project.mdx": "e2b15095ab033cd24ee5db17cbc65c7b552cbcaf26574eb54bec9b87dd2aa50d", + "content/docs/api-reference/core/turns/retrieve-root-turn-diagnostics.mdx": "c9150f082128cadf9cb88b48f34794acfda64305f8c51d6ed3d87de423d1dffb", + "content/docs/api-reference/core/skills/list-skills-in-a-project.mdx": "0187c18ddab336ccffb170d6307198c0d3f51c89356910ef8a4eb3aa98007a03", + "content/docs/api-reference/core/skills/retrieve-skill-metadata-in-a-project.mdx": "e3fb7136d3066b1263a2d237e2374ae50bda4b001d3bc95fbaadc2078afa3951", + "content/docs/api-reference/core/skills/delete-a-skill-and-its-versions-in-a-project.mdx": "11cf37d2e8ba426de8f666d721a5c9f5928e0767a7b91f601af5a409a9b30f38", + "content/docs/api-reference/core/skills/download-skill-content-in-a-project.mdx": "c34dbd6c95b72a4e6c687f52af95e2111e9ab9984f1cc9d24709e476e51c8e4d", + "content/docs/api-reference/core/skills/list-skill-versions-in-a-project.mdx": "7cbd5bdebc2daacf431d7d81bb8648b4ed039fb4755ee07b829e41cf1824d5c9", + "content/docs/api-reference/core/skills/retrieve-skill-version-metadata-in-a-project.mdx": "b7fd7dfaee3a7bce2c224be1b2db07cf7dc37ca40d48205c93d7ce257c9b6866", + "content/docs/api-reference/core/skills/delete-a-skill-version-in-a-project.mdx": "9c6c0134ae53867d2fba1e9650176806af6a50eeab4c1013f6e5d3a01bf5f722", + "content/docs/api-reference/core/skills/download-immutable-skill-version-content-in-a-project.mdx": "ab97f631cc92affa5465f336b75020bf1c16777f2bc5d6830c3e4e37803bfaf0", + "content/docs/api-reference/core/vaults/list-vaults-in-a-project.mdx": "da26e807ae9c7a0e59d7e12e406b7b8e57e4d766685ec6698e5da031ebb43639", + "content/docs/api-reference/core/vaults/retrieve-a-vault-in-a-project.mdx": "ad23cdfa3e157deb83de633da42b8fa0c8a6c4e73b19b4598912f5040487797d", + "content/docs/api-reference/core/vaults/delete-a-vault-and-all-its-credentials-in-a-project.mdx": "9120d5145bb6a7203371e43c9403ffbb57421cdd8856546652a93ac3914c825c", + "content/docs/api-reference/core/credentials/list-safe-vault-credential-metadata-in-a-project.mdx": "3eb26152100e40b2001f4ade4528df05f9349bf48071389991420cce74503a36", + "content/docs/api-reference/core/credentials/retrieve-safe-vault-credential-metadata-in-a-project.mdx": "a5c0632b8b6e943ac1f33b8c0e3f7eb9cc80cb739ee049d44817f27f95ed4e6e", + "content/docs/api-reference/core/credentials/delete-a-vault-credential-in-a-project.mdx": "c68abf123cb34a91070a8c5fa061fc5cf00f0ec0e5b1ab6c3fe2a6578fe49416", + "content/docs/api-reference/core/write-audit/query-api-key-write-operations.mdx": "d911082ab5d82d439980a165c1a2ad5afc276975592d2a6641211639d19806b9", + "content/docs/api-reference/core/sandbox-manager/retrieve-sandbox-deployment.mdx": "bdd6d6aacc76943e58c09f7be23ed7c3c3cc5914b79f215c45a55b27fcd6e5ab", + "content/docs/api-reference/core/sandbox-manager/initialize-the-deployment-sandbox-provider.mdx": "39ece85872e2ab283ea6be293cd3e97a39a83bdcb25b0dbf45cf4f78510ec31c", + "content/docs/api-reference/core/sandbox-manager/change-the-sandbox-deployment-configuration.mdx": "4647c631def4ec5b48a736fca7dade8e80857f9af44685c42f96ac09a4337763", + "content/docs/api-reference/core/sandbox-manager/start-or-escalate-a-durable-sandbox-deployment-reset.mdx": "136ce44903b0efef94454e738c8f23f8ca2d2ef3aecb567e9afdec4c2e1ec923", + "content/docs/api-reference/core/sandbox-manager/cancel-a-sandbox-deployment-reset.mdx": "858bb0ea9a0bc5a7840ec8d5b5ed44fe85f930f8045596a0ab1fddefc9ce04b1", + "content/docs/api-reference/core/sandbox-manager/list-templates-visible-to-an-e2b-credential.mdx": "8da8d150b5db59630d426824592cb41bc31f7ee83f5a77dc27934b14717a4977", + "content/docs/api-reference/core/sandbox-manager/list-ready-builds-for-an-e2b-template.mdx": "2b6df60778df1fe40cdb0d7659ce47ba227142b7c484e635672a2a3b7daef001", + "content/docs/api-reference/core/sandbox-manager/create-a-ten-minute-one-use-node-enrollment-token.mdx": "49f4cfe9bbf67cbf51790f82186877802a76c4e18bb36e163a9693d1072704b6", + "content/docs/api-reference/core/sandbox-manager/list-deployment-sandbox-nodes.mdx": "f1cf29d0830b91659401440eab87741bac5984bb0eb95de2f5d5ed11aec78e18", + "content/docs/api-reference/core/sandbox-manager/retrieve-sandbox-node-and-host-history.mdx": "a2bac2f358b3c9926e6eef3f8ffa31e701d0afcb3afe07d43fa1ca4a68320f09", + "content/docs/api-reference/core/sandbox-manager/update-sandbox-node-name-and-capacity.mdx": "03446b3e04907e7771138337720efe7e8165bee423b3c0fbe2c7834fdcba30cf", + "content/docs/api-reference/core/sandbox-manager/remove-a-sandbox-node-with-no-retained-resources.mdx": "c2eae5faff754e2202f995ce6e2ddded98671f6cf1d89298df0996081e4be15d", + "content/docs/api-reference/core/sandbox-manager/list-retained-allocations-on-a-sandbox-node.mdx": "311af4031f237c35804192de31e7d0fa9fda816ea81405e6244f528bd70633c4", + "content/docs/api-reference/core/core-administration/list-runtime-observations-across-managed-projects.mdx": "bf540d3dc5314b87e78df676372576538450e2cfaf9f52dc34acad19cbf513f5", + "content/docs/api-reference/core/core-administration/summarize-resource-counts-and-session-usage-by-project-agent-or-creator-key.mdx": "8fb652245d65e3b4e095faf49af34b7337e43ccb3195d0be4588f571d3b14501", + "content/docs/api-reference/core/core-administration/index.mdx": "88db7e7d59cc6dfed471da887ddff69b29ea17534f9a1f6294c231d653b26ec6", + "content/docs/api-reference/core/core-administration/meta.json": "a169f612d45e3199b45b3b958fa20a389a9fd472583f12fa69f050e9bb834478", + "content/docs/api-reference/core/deployment-model-providers/index.mdx": "54392959ade32ca8f2e1589ac3c5aa72f959b881a3e491f0fd25c731e89f78c1", + "content/docs/api-reference/core/deployment-model-providers/meta.json": "e195e58454f75bc989d571a5339474052e63f8be97b0f38bdcf3e353eaffc87e", + "content/docs/api-reference/core/administrator-projects/index.mdx": "13166281b709e899fcd0856267ed41c4ade308006a2987fdc46fdda8bbb98e98", + "content/docs/api-reference/core/administrator-projects/meta.json": "de60495ce59bc605e78b423e64605ad43dcba3af4a05172afa35f57a63107b53", + "content/docs/api-reference/core/agents/index.mdx": "6517e71facb1398d3b9372e92c2533474c849f5ea6db1a7fe6604428bd549f4a", + "content/docs/api-reference/core/agents/meta.json": "60bc344e4e410f6e136bfca2b98a0e08bfdb0b40cbadb46f6623b784b5f78522", + "content/docs/api-reference/core/environment-templates/index.mdx": "7ba91b3d7aa77e7ef216e692d4787ce15e5fad0f07a3d1e4c8b9dbc2add33c51", + "content/docs/api-reference/core/environment-templates/meta.json": "a60bd3832822f4244f9a6175e4eb794b72c15977241df6910a523265e01037b7", + "content/docs/api-reference/core/executor-credentials/index.mdx": "966bd24d0c491b6f062ca2eff33498028ab8b39e00533ff60647fb97a41a41c3", + "content/docs/api-reference/core/executor-credentials/meta.json": "7456cda60ecbe86562ca5438b9228f516e172e5ce562541640b3158ef7770dc9", + "content/docs/api-reference/core/native-installation/index.mdx": "3da7f4bc6761428aa9650fca00c9e639cb0f83757f4137ff7e496f7c0bad5ba7", + "content/docs/api-reference/core/native-installation/meta.json": "754723b59187015842343b5bdae1347bcee9945401c78bcd898db6d8587f5e9c", + "content/docs/api-reference/core/files/index.mdx": "3a0274fb0beec16190a1f709956aae68bb2d392fceeebae724520a437c55dda0", + "content/docs/api-reference/core/files/meta.json": "4e78b79f585a12d311d23429d56bb36a84e0478482fc4209e022594d1fddd5af", + "content/docs/api-reference/core/write-audit/index.mdx": "cdc02ebdf46223737b52bf50ffc67fc2fdc214a1058253281cd77c0739dc50bb", + "content/docs/api-reference/core/write-audit/meta.json": "4c17b5a06c99c634be9d05916c84486af639deb47f2a3d5eb3153771fe7c7d3f", + "content/docs/api-reference/core/sessions/index.mdx": "89d71bfa7cb78b0ad6236212646c9240ebf259be72cbab129d970c7e6dc220c5", + "content/docs/api-reference/core/sessions/meta.json": "f01061753eb3db2ffe052e9422dfa1b4e709d235cb076833ecbe11b90bdd757f", + "content/docs/api-reference/core/artifacts/index.mdx": "5ef849b7f353b246c5137fb5305a1387b99298ddd777389e02d5cebcf4deb68d", + "content/docs/api-reference/core/artifacts/meta.json": "5156b8a414eb6da113960abe09d30e255e21891820669fdcba49f295a7bcf31c", + "content/docs/api-reference/core/execution-configuration/index.mdx": "fc60df970294ce9ac8e9750888897e5e9fe5f5b525d5d8f3eecbf5bb2f25c5a2", + "content/docs/api-reference/core/execution-configuration/meta.json": "d971206ad0f78bb0f093ae33b8488f6eaf8ef1a04a8e7882f2f3edc9a096c0e3", + "content/docs/api-reference/core/items/index.mdx": "58d86426566aa71263eac72b5704ae4352a9ed237b80576e3dbd653ca52501a1", + "content/docs/api-reference/core/items/meta.json": "c6a1139633e0fe14c323a7bf3d8797e794368065ce5c0761755d621576d71c0d", + "content/docs/api-reference/core/runtime-history/index.mdx": "8898722b8da575d848651f8991d5e6aad0ac4302dbc78d926d964c4a02af915b", + "content/docs/api-reference/core/runtime-history/meta.json": "d24b260c692975497824f328cfb5e2101ac426a149684317778f50645ba01584", + "content/docs/api-reference/core/runtime-observations/index.mdx": "16ca7ff79d12dbe951b2b1fa70554a530580d1c7415475affd7287fa209365de", + "content/docs/api-reference/core/runtime-observations/meta.json": "8907d72be08e84d600eabac93603d6e0c27d1c2e672e1ceff04cd7b856ad1b0c", + "content/docs/api-reference/core/turns/index.mdx": "bc156b3e6ee689be1418977abb1f6f19e4801473d4f4ff09aea862898852ba36", + "content/docs/api-reference/core/turns/meta.json": "40cfaaad239a43ab7de78b0eef7418646a037bb6e5faf978b6d27f92cf714ca3", + "content/docs/api-reference/core/skills/index.mdx": "66a8f52dc19846c779b320d4b254bd717b1df368ab9f0706dc4d489ae888acb1", + "content/docs/api-reference/core/skills/meta.json": "29f1b629fe626cdbf3de7c345cdd0b5821a5ff3363c6cf71c549435a1f9a7cf6", + "content/docs/api-reference/core/vaults/index.mdx": "1b6f1523318a96f178ae7110acc1afe8ec4878a1acb7a773cc7ea941fa463deb", + "content/docs/api-reference/core/vaults/meta.json": "0596db6fdcaebcb360fd9e6f0cb3720b822287cd66aea6fd4798deb9713dacb3", + "content/docs/api-reference/core/credentials/index.mdx": "d6bafc16421923fd5fc5b570677136b3623e84bd431a2c635f0259553d758b46", + "content/docs/api-reference/core/credentials/meta.json": "fe7cedd70a4785dc222748e7d2846e92fccea58dd01d47e2e054df23e83f45ee", + "content/docs/api-reference/core/sandbox-manager/index.mdx": "66b38e9c267134171f4296b41665f93c66ede0c3cfbc512987082b08297850f7", + "content/docs/api-reference/core/sandbox-manager/meta.json": "87c4a3068098b5b4c764a8a75bec5699be5a5edd3231e9dcd991ad197d0a9190", + "content/docs/api-reference/core/meta.json": "5d449afad9a6c3eb73a691a549bb7c2410cd2a2257177dc0cc9008cb42c855c1", + "content/docs/api-reference/core/index.mdx": "abfa13ae8ed90793b018ec3a70e4afdb15bd98dc55fabc56b8b9417283e72e3b", + "openapi/core-api.yaml": "dceafefddca3b2a5d2c61a3b4a82b00b5961fd550eeb4e9d8c637d4e381bd265", + "content/docs/api-reference/machine/native-installation/resolve-a-native-installation-authorization.mdx": "5c9d983c7a97e92d4c541d9ebbdb5e869eb3d52d32870709f979583305ffbd25", + "content/docs/api-reference/machine/native-installation/claim-an-environment-s-installation-credential.mdx": "45223298aa8ec65cdfbe8e2685306ba14c39db898e534fca205e9a658cf7f344", + "content/docs/api-reference/machine/sandbox-node/read-the-active-configuration-for-node-installation.mdx": "7aa907f1b00b82a4d6cc7ba50f11fd19558baf5deddbcf34c0d1e7aecf577efc", + "content/docs/api-reference/machine/sandbox-node/enroll-a-sandbox-node.mdx": "90e7d27beda3286aab3d29d161b6f89158c410f0ad8121449f52b456d22b2601", + "content/docs/api-reference/machine/sandbox-node/recover-an-enrolled-sandbox-node-identity-and-observe-its-readiness.mdx": "ffb74feabb887e0f9a69635acf7213286b56e2aa6d164162c1fc81ddb1bb9624", + "content/docs/api-reference/machine/native-installation/index.mdx": "bf953a4061664ca40d2c66f5335bb756cbe07bc1ebd7882bc8ba52f44f222bf7", + "content/docs/api-reference/machine/native-installation/meta.json": "dc8871ae2e6637eef5b0506eeb1dc582f4b41d019ae7301ad79f3001e8970d81", + "content/docs/api-reference/machine/sandbox-node/index.mdx": "dfecdf0e1f1b7dd9baea4018f8b26b5c688cf7d230f508803aff236ccb236a80", + "content/docs/api-reference/machine/sandbox-node/meta.json": "1e84da2499923fe60e436a53b0983f8926400522ffe3719eede69890b06a329d", + "content/docs/api-reference/machine/meta.json": "8c5c7c9c6a16185475a42ecce327313c0f8662731b307a8d648075038fea6eb0", + "content/docs/api-reference/machine/index.mdx": "c0dcc9631ff6a3736b8ee71274d33c9fce86f91d9ceedf52012db06a41c78069", + "openapi/runtime-api.yaml": "154291666d72eb5b8d844080ce3f7f5f4966b21b89260e66a1e46cefb03e2711" } } diff --git a/contracts/agents-api/core.openapi.yaml b/contracts/agents-api/core.openapi.yaml index decee3473..c4d3b261a 100644 --- a/contracts/agents-api/core.openapi.yaml +++ b/contracts/agents-api/core.openapi.yaml @@ -3618,7 +3618,7 @@ paths: name: harness required: true type: string - - description: Complete model provider bundle + - description: Complete model configuration in: body name: body required: true @@ -3792,6 +3792,10 @@ paths: description: Conflict schema: $ref: '#/definitions/api.CoreErrorResponse' + "413": + description: Request Entity Too Large + schema: + $ref: '#/definitions/api.CoreErrorResponse' "500": description: Internal Server Error schema: @@ -3840,6 +3844,10 @@ paths: description: Conflict schema: $ref: '#/definitions/api.CoreErrorResponse' + "413": + description: Request Entity Too Large + schema: + $ref: '#/definitions/api.CoreErrorResponse' "500": description: Internal Server Error schema: @@ -4247,6 +4255,10 @@ paths: description: Conflict schema: $ref: '#/definitions/api.CoreErrorResponse' + "413": + description: Request Entity Too Large + schema: + $ref: '#/definitions/api.CoreErrorResponse' "500": description: Internal Server Error schema: @@ -4326,6 +4338,10 @@ paths: description: Conflict schema: $ref: '#/definitions/api.CoreErrorResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/api.CoreErrorResponse' security: - DeploymentAdminAuth: [] summary: Get a self_hosted Session's installation commands @@ -4572,6 +4588,10 @@ paths: description: Conflict schema: $ref: '#/definitions/api.CoreErrorResponse' + "413": + description: Request Entity Too Large + schema: + $ref: '#/definitions/api.CoreErrorResponse' "500": description: Internal Server Error schema: @@ -5356,6 +5376,10 @@ paths: description: Conflict schema: $ref: '#/definitions/api.CoreErrorResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/api.CoreErrorResponse' "503": description: Service Unavailable schema: @@ -5579,10 +5603,10 @@ paths: name: after type: string - default: 20 - description: Page size; 0 returns an empty page + description: Page size, 1–100 in: query maximum: 100 - minimum: 0 + minimum: 1 name: limit type: integer - description: Creation order; omit for descending, explicit empty values are invalid @@ -5604,6 +5628,26 @@ paths: description: OK schema: $ref: '#/definitions/v1.SkillList' + "400": + description: Bad Request + schema: + $ref: '#/definitions/api.CoreErrorResponse' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/api.CoreErrorResponse' + "404": + description: Not Found + schema: + $ref: '#/definitions/api.CoreErrorResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/api.CoreErrorResponse' + "503": + description: Service Unavailable + schema: + $ref: '#/definitions/api.CoreErrorResponse' security: - DeploymentAdminAuth: [] summary: List Skills in a Project @@ -5630,6 +5674,26 @@ paths: description: OK schema: $ref: '#/definitions/v1.SkillDeleted' + "400": + description: Bad Request + schema: + $ref: '#/definitions/api.CoreErrorResponse' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/api.CoreErrorResponse' + "404": + description: Not Found + schema: + $ref: '#/definitions/api.CoreErrorResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/api.CoreErrorResponse' + "503": + description: Service Unavailable + schema: + $ref: '#/definitions/api.CoreErrorResponse' security: - DeploymentAdminAuth: [] summary: Delete a Skill and its versions in a Project @@ -5655,6 +5719,26 @@ paths: description: OK schema: $ref: '#/definitions/v1.Skill' + "400": + description: Bad Request + schema: + $ref: '#/definitions/api.CoreErrorResponse' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/api.CoreErrorResponse' + "404": + description: Not Found + schema: + $ref: '#/definitions/api.CoreErrorResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/api.CoreErrorResponse' + "503": + description: Service Unavailable + schema: + $ref: '#/definitions/api.CoreErrorResponse' security: - DeploymentAdminAuth: [] summary: Retrieve Skill metadata in a Project @@ -5681,6 +5765,26 @@ paths: description: OK schema: type: file + "400": + description: Bad Request + schema: + $ref: '#/definitions/api.CoreErrorResponse' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/api.CoreErrorResponse' + "404": + description: Not Found + schema: + $ref: '#/definitions/api.CoreErrorResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/api.CoreErrorResponse' + "503": + description: Service Unavailable + schema: + $ref: '#/definitions/api.CoreErrorResponse' security: - DeploymentAdminAuth: [] summary: Download Skill content in a Project @@ -5700,10 +5804,10 @@ paths: name: after type: string - default: 20 - description: Page size; 0 returns an empty page + description: Page size, 1–100 in: query maximum: 100 - minimum: 0 + minimum: 1 name: limit type: integer - description: Version order; omit for descending, explicit empty values are invalid @@ -5725,6 +5829,26 @@ paths: description: OK schema: $ref: '#/definitions/v1.SkillVersionList' + "400": + description: Bad Request + schema: + $ref: '#/definitions/api.CoreErrorResponse' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/api.CoreErrorResponse' + "404": + description: Not Found + schema: + $ref: '#/definitions/api.CoreErrorResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/api.CoreErrorResponse' + "503": + description: Service Unavailable + schema: + $ref: '#/definitions/api.CoreErrorResponse' security: - DeploymentAdminAuth: [] summary: List Skill versions in a Project @@ -5756,6 +5880,26 @@ paths: description: OK schema: $ref: '#/definitions/v1.SkillVersionDeleted' + "400": + description: Bad Request + schema: + $ref: '#/definitions/api.CoreErrorResponse' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/api.CoreErrorResponse' + "404": + description: Not Found + schema: + $ref: '#/definitions/api.CoreErrorResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/api.CoreErrorResponse' + "503": + description: Service Unavailable + schema: + $ref: '#/definitions/api.CoreErrorResponse' security: - DeploymentAdminAuth: [] summary: Delete a Skill version in a Project @@ -5786,6 +5930,26 @@ paths: description: OK schema: $ref: '#/definitions/v1.SkillVersion' + "400": + description: Bad Request + schema: + $ref: '#/definitions/api.CoreErrorResponse' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/api.CoreErrorResponse' + "404": + description: Not Found + schema: + $ref: '#/definitions/api.CoreErrorResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/api.CoreErrorResponse' + "503": + description: Service Unavailable + schema: + $ref: '#/definitions/api.CoreErrorResponse' security: - DeploymentAdminAuth: [] summary: Retrieve Skill version metadata in a Project @@ -5817,6 +5981,26 @@ paths: description: OK schema: type: file + "400": + description: Bad Request + schema: + $ref: '#/definitions/api.CoreErrorResponse' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/api.CoreErrorResponse' + "404": + description: Not Found + schema: + $ref: '#/definitions/api.CoreErrorResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/api.CoreErrorResponse' + "503": + description: Service Unavailable + schema: + $ref: '#/definitions/api.CoreErrorResponse' security: - DeploymentAdminAuth: [] summary: Download immutable Skill version content in a Project @@ -6287,6 +6471,10 @@ paths: description: Conflict schema: $ref: '#/definitions/api.CoreErrorResponse' + "413": + description: Request Entity Too Large + schema: + $ref: '#/definitions/api.CoreErrorResponse' "500": description: Internal Server Error schema: @@ -6330,6 +6518,10 @@ paths: description: Conflict schema: $ref: '#/definitions/api.CoreErrorResponse' + "413": + description: Request Entity Too Large + schema: + $ref: '#/definitions/api.CoreErrorResponse' "500": description: Internal Server Error schema: @@ -6414,6 +6606,10 @@ paths: description: Conflict schema: $ref: '#/definitions/api.CoreErrorResponse' + "413": + description: Request Entity Too Large + schema: + $ref: '#/definitions/api.CoreErrorResponse' "500": description: Internal Server Error schema: @@ -6454,6 +6650,10 @@ paths: description: Unauthorized schema: $ref: '#/definitions/api.CoreErrorResponse' + "413": + description: Request Entity Too Large + schema: + $ref: '#/definitions/api.CoreErrorResponse' "503": description: Service Unavailable schema: @@ -6495,6 +6695,10 @@ paths: description: Unauthorized schema: $ref: '#/definitions/api.CoreErrorResponse' + "413": + description: Request Entity Too Large + schema: + $ref: '#/definitions/api.CoreErrorResponse' "503": description: Service Unavailable schema: @@ -6539,6 +6743,10 @@ paths: description: Conflict schema: $ref: '#/definitions/api.CoreErrorResponse' + "413": + description: Request Entity Too Large + schema: + $ref: '#/definitions/api.CoreErrorResponse' "500": description: Internal Server Error schema: @@ -6723,6 +6931,10 @@ paths: description: Conflict schema: $ref: '#/definitions/api.CoreErrorResponse' + "413": + description: Request Entity Too Large + schema: + $ref: '#/definitions/api.CoreErrorResponse' "500": description: Internal Server Error schema: diff --git a/contracts/agents-api/openapi.yaml b/contracts/agents-api/openapi.yaml index f53cc5999..ff87fb80f 100644 --- a/contracts/agents-api/openapi.yaml +++ b/contracts/agents-api/openapi.yaml @@ -2223,6 +2223,10 @@ paths: description: Internal Server Error schema: $ref: '#/definitions/v1.ErrorResponse' + "503": + description: Service Unavailable + schema: + $ref: '#/definitions/v1.ErrorResponse' security: - BearerAuth: [] summary: List reusable Agents @@ -2293,6 +2297,10 @@ paths: description: Internal Server Error schema: $ref: '#/definitions/v1.ErrorResponse' + "503": + description: Service Unavailable + schema: + $ref: '#/definitions/v1.ErrorResponse' security: - BearerAuth: [] summary: Create a reusable Agent @@ -2342,6 +2350,10 @@ paths: description: Internal Server Error schema: $ref: '#/definitions/v1.ErrorResponse' + "503": + description: Service Unavailable + schema: + $ref: '#/definitions/v1.ErrorResponse' security: - BearerAuth: [] summary: Delete a reusable Agent @@ -2384,6 +2396,10 @@ paths: description: Internal Server Error schema: $ref: '#/definitions/v1.ErrorResponse' + "503": + description: Service Unavailable + schema: + $ref: '#/definitions/v1.ErrorResponse' security: - BearerAuth: [] summary: Retrieve a reusable Agent @@ -2444,6 +2460,10 @@ paths: description: Internal Server Error schema: $ref: '#/definitions/v1.ErrorResponse' + "503": + description: Service Unavailable + schema: + $ref: '#/definitions/v1.ErrorResponse' security: - BearerAuth: [] summary: Update a reusable Agent @@ -2494,6 +2514,10 @@ paths: description: Internal Server Error schema: $ref: '#/definitions/v1.ErrorResponse' + "503": + description: Service Unavailable + schema: + $ref: '#/definitions/v1.ErrorResponse' security: - BearerAuth: [] summary: Retrieve an execution Environment @@ -2710,6 +2734,10 @@ paths: description: Internal Server Error schema: $ref: '#/definitions/v1.ErrorResponse' + "503": + description: Service Unavailable + schema: + $ref: '#/definitions/v1.ErrorResponse' security: - BearerAuth: [] summary: List Environment Templates @@ -2764,6 +2792,10 @@ paths: description: Internal Server Error schema: $ref: '#/definitions/v1.ErrorResponse' + "503": + description: Service Unavailable + schema: + $ref: '#/definitions/v1.ErrorResponse' security: - BearerAuth: [] summary: Create an Environment Template @@ -2807,6 +2839,10 @@ paths: description: Internal Server Error schema: $ref: '#/definitions/v1.ErrorResponse' + "503": + description: Service Unavailable + schema: + $ref: '#/definitions/v1.ErrorResponse' security: - BearerAuth: [] summary: Delete an Environment Template @@ -2849,6 +2885,10 @@ paths: description: Internal Server Error schema: $ref: '#/definitions/v1.ErrorResponse' + "503": + description: Service Unavailable + schema: + $ref: '#/definitions/v1.ErrorResponse' security: - BearerAuth: [] summary: Retrieve an Environment Template @@ -2913,6 +2953,10 @@ paths: description: Internal Server Error schema: $ref: '#/definitions/v1.ErrorResponse' + "503": + description: Service Unavailable + schema: + $ref: '#/definitions/v1.ErrorResponse' security: - BearerAuth: [] summary: Update an Environment Template @@ -2978,6 +3022,10 @@ paths: description: Internal Server Error schema: $ref: '#/definitions/v1.ErrorResponse' + "503": + description: Service Unavailable + schema: + $ref: '#/definitions/v1.ErrorResponse' security: - BearerAuth: [] summary: List execution Sessions @@ -3221,6 +3269,10 @@ paths: description: Internal Server Error schema: $ref: '#/definitions/v1.ErrorResponse' + "503": + description: Service Unavailable + schema: + $ref: '#/definitions/v1.ErrorResponse' security: - BearerAuth: [] summary: Delete an execution Session @@ -3265,6 +3317,10 @@ paths: description: Internal Server Error schema: $ref: '#/definitions/v1.ErrorResponse' + "503": + description: Service Unavailable + schema: + $ref: '#/definitions/v1.ErrorResponse' security: - BearerAuth: [] summary: Retrieve an execution Session @@ -3325,6 +3381,10 @@ paths: description: Internal Server Error schema: $ref: '#/definitions/v1.ErrorResponse' + "503": + description: Service Unavailable + schema: + $ref: '#/definitions/v1.ErrorResponse' security: - BearerAuth: [] summary: Update execution Session metadata @@ -3768,6 +3828,10 @@ paths: description: Internal Server Error schema: $ref: '#/definitions/v1.ErrorResponse' + "503": + description: Service Unavailable + schema: + $ref: '#/definitions/v1.ErrorResponse' security: - BearerAuth: [] summary: List persisted execution Items @@ -4241,6 +4305,10 @@ paths: description: Internal Server Error schema: $ref: '#/definitions/v1.ErrorResponse' + "503": + description: Service Unavailable + schema: + $ref: '#/definitions/v1.ErrorResponse' security: - BearerAuth: [] summary: List execution Turns @@ -4290,6 +4358,10 @@ paths: description: Internal Server Error schema: $ref: '#/definitions/v1.ErrorResponse' + "503": + description: Service Unavailable + schema: + $ref: '#/definitions/v1.ErrorResponse' security: - BearerAuth: [] summary: Retrieve an execution Turn @@ -4572,6 +4644,26 @@ paths: description: OK schema: $ref: '#/definitions/v1.SkillList' + "400": + description: Bad Request + schema: + $ref: '#/definitions/v1.ErrorResponse' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/v1.ErrorResponse' + "404": + description: Not Found + schema: + $ref: '#/definitions/v1.ErrorResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/v1.ErrorResponse' + "503": + description: Service Unavailable + schema: + $ref: '#/definitions/v1.ErrorResponse' security: - BearerAuth: [] summary: List Skills @@ -4596,6 +4688,26 @@ paths: description: OK schema: $ref: '#/definitions/v1.Skill' + "400": + description: Bad Request + schema: + $ref: '#/definitions/v1.ErrorResponse' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/v1.ErrorResponse' + "413": + description: Request Entity Too Large + schema: + $ref: '#/definitions/v1.ErrorResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/v1.ErrorResponse' + "503": + description: Service Unavailable + schema: + $ref: '#/definitions/v1.ErrorResponse' security: - BearerAuth: [] summary: Upload a Skill @@ -4618,6 +4730,26 @@ paths: description: OK schema: $ref: '#/definitions/v1.SkillDeleted' + "400": + description: Bad Request + schema: + $ref: '#/definitions/v1.ErrorResponse' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/v1.ErrorResponse' + "404": + description: Not Found + schema: + $ref: '#/definitions/v1.ErrorResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/v1.ErrorResponse' + "503": + description: Service Unavailable + schema: + $ref: '#/definitions/v1.ErrorResponse' security: - BearerAuth: [] summary: Delete a Skill and its versions @@ -4639,6 +4771,26 @@ paths: description: OK schema: $ref: '#/definitions/v1.Skill' + "400": + description: Bad Request + schema: + $ref: '#/definitions/v1.ErrorResponse' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/v1.ErrorResponse' + "404": + description: Not Found + schema: + $ref: '#/definitions/v1.ErrorResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/v1.ErrorResponse' + "503": + description: Service Unavailable + schema: + $ref: '#/definitions/v1.ErrorResponse' security: - BearerAuth: [] summary: Retrieve Skill metadata @@ -4668,6 +4820,30 @@ paths: description: OK schema: $ref: '#/definitions/v1.Skill' + "400": + description: Bad Request + schema: + $ref: '#/definitions/v1.ErrorResponse' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/v1.ErrorResponse' + "404": + description: Not Found + schema: + $ref: '#/definitions/v1.ErrorResponse' + "413": + description: Request Entity Too Large + schema: + $ref: '#/definitions/v1.ErrorResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/v1.ErrorResponse' + "503": + description: Service Unavailable + schema: + $ref: '#/definitions/v1.ErrorResponse' security: - BearerAuth: [] summary: Update the default Skill version @@ -4691,6 +4867,26 @@ paths: description: OK schema: type: file + "400": + description: Bad Request + schema: + $ref: '#/definitions/v1.ErrorResponse' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/v1.ErrorResponse' + "404": + description: Not Found + schema: + $ref: '#/definitions/v1.ErrorResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/v1.ErrorResponse' + "503": + description: Service Unavailable + schema: + $ref: '#/definitions/v1.ErrorResponse' security: - BearerAuth: [] summary: Download Skill content @@ -4735,6 +4931,26 @@ paths: description: OK schema: $ref: '#/definitions/v1.SkillVersionList' + "400": + description: Bad Request + schema: + $ref: '#/definitions/v1.ErrorResponse' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/v1.ErrorResponse' + "404": + description: Not Found + schema: + $ref: '#/definitions/v1.ErrorResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/v1.ErrorResponse' + "503": + description: Service Unavailable + schema: + $ref: '#/definitions/v1.ErrorResponse' security: - BearerAuth: [] summary: List Skill versions @@ -4765,6 +4981,30 @@ paths: description: OK schema: $ref: '#/definitions/v1.SkillVersion' + "400": + description: Bad Request + schema: + $ref: '#/definitions/v1.ErrorResponse' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/v1.ErrorResponse' + "404": + description: Not Found + schema: + $ref: '#/definitions/v1.ErrorResponse' + "413": + description: Request Entity Too Large + schema: + $ref: '#/definitions/v1.ErrorResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/v1.ErrorResponse' + "503": + description: Service Unavailable + schema: + $ref: '#/definitions/v1.ErrorResponse' security: - BearerAuth: [] summary: Upload an immutable Skill version @@ -4793,6 +5033,26 @@ paths: description: OK schema: $ref: '#/definitions/v1.SkillVersionDeleted' + "400": + description: Bad Request + schema: + $ref: '#/definitions/v1.ErrorResponse' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/v1.ErrorResponse' + "404": + description: Not Found + schema: + $ref: '#/definitions/v1.ErrorResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/v1.ErrorResponse' + "503": + description: Service Unavailable + schema: + $ref: '#/definitions/v1.ErrorResponse' security: - BearerAuth: [] summary: Delete a Skill version @@ -4817,6 +5077,26 @@ paths: description: OK schema: $ref: '#/definitions/v1.SkillVersion' + "400": + description: Bad Request + schema: + $ref: '#/definitions/v1.ErrorResponse' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/v1.ErrorResponse' + "404": + description: Not Found + schema: + $ref: '#/definitions/v1.ErrorResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/v1.ErrorResponse' + "503": + description: Service Unavailable + schema: + $ref: '#/definitions/v1.ErrorResponse' security: - BearerAuth: [] summary: Retrieve Skill version metadata @@ -4842,6 +5122,26 @@ paths: description: OK schema: type: file + "400": + description: Bad Request + schema: + $ref: '#/definitions/v1.ErrorResponse' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/v1.ErrorResponse' + "404": + description: Not Found + schema: + $ref: '#/definitions/v1.ErrorResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/v1.ErrorResponse' + "503": + description: Service Unavailable + schema: + $ref: '#/definitions/v1.ErrorResponse' security: - BearerAuth: [] summary: Download immutable Skill version content @@ -4920,6 +5220,10 @@ paths: description: Internal Server Error schema: $ref: '#/definitions/v1.ErrorResponse' + "503": + description: Service Unavailable + schema: + $ref: '#/definitions/v1.ErrorResponse' security: - BearerAuth: [] summary: List Vaults @@ -4970,6 +5274,10 @@ paths: description: Internal Server Error schema: $ref: '#/definitions/v1.ErrorResponse' + "503": + description: Service Unavailable + schema: + $ref: '#/definitions/v1.ErrorResponse' security: - BearerAuth: [] summary: Create a Vault @@ -5023,6 +5331,10 @@ paths: description: Internal Server Error schema: $ref: '#/definitions/v1.ErrorResponse' + "503": + description: Service Unavailable + schema: + $ref: '#/definitions/v1.ErrorResponse' security: - BearerAuth: [] summary: Delete a Vault and all its Credentials @@ -5066,6 +5378,10 @@ paths: description: Internal Server Error schema: $ref: '#/definitions/v1.ErrorResponse' + "503": + description: Service Unavailable + schema: + $ref: '#/definitions/v1.ErrorResponse' security: - BearerAuth: [] summary: Retrieve a Vault @@ -5150,6 +5466,10 @@ paths: description: Internal Server Error schema: $ref: '#/definitions/v1.ErrorResponse' + "503": + description: Service Unavailable + schema: + $ref: '#/definitions/v1.ErrorResponse' security: - BearerAuth: [] summary: List safe Vault Credential metadata @@ -5276,6 +5596,10 @@ paths: description: Internal Server Error schema: $ref: '#/definitions/v1.ErrorResponse' + "503": + description: Service Unavailable + schema: + $ref: '#/definitions/v1.ErrorResponse' security: - BearerAuth: [] summary: Delete a Vault Credential @@ -5325,6 +5649,10 @@ paths: description: Internal Server Error schema: $ref: '#/definitions/v1.ErrorResponse' + "503": + description: Service Unavailable + schema: + $ref: '#/definitions/v1.ErrorResponse' security: - BearerAuth: [] summary: Retrieve safe Vault Credential metadata diff --git a/contracts/agents-api/runtime.openapi.yaml b/contracts/agents-api/runtime.openapi.yaml index 329d7fce1..d650c84dc 100644 --- a/contracts/agents-api/runtime.openapi.yaml +++ b/contracts/agents-api/runtime.openapi.yaml @@ -209,6 +209,10 @@ paths: description: Not Found schema: $ref: '#/definitions/api.CoreErrorResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/api.CoreErrorResponse' "503": description: Service Unavailable schema: @@ -243,6 +247,14 @@ paths: description: Conflict schema: $ref: '#/definitions/api.CoreErrorResponse' + "413": + description: Request Entity Too Large + schema: + $ref: '#/definitions/api.CoreErrorResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/api.CoreErrorResponse' "503": description: Service Unavailable schema: @@ -329,6 +341,10 @@ paths: description: Conflict schema: $ref: '#/definitions/v1.ErrorResponse' + "413": + description: Request Entity Too Large + schema: + $ref: '#/definitions/v1.ErrorResponse' "500": description: Internal Server Error schema: From 5a6d1494e3b846a44436dbabfbc614b00dc749c6 Mon Sep 17 00:00:00 2001 From: Yao Date: Wed, 30 Sep 2026 09:39:26 +0800 Subject: [PATCH 09/14] docs: guard the sidebar list and the registry Namespaces column Four fixes to the generated guide record and the checks around it. - The generated record in content/guide-sources.json no longer matched scripts/guides.json after the title escape was restored, so verify:docs failed and the two later verify steps never ran. Regenerated the guides. - The two new guides were absent from content/docs/meta.json, so fumadocs dropped them from the sidebar even though they were routable and linked. Listed them, and taught verify-docs-facts.mjs to fail when a page under content/docs is missing from that list. - docs/api/request-conventions.md claimed an operation page states only what differs from the conventions, although Files, Skills and Create a reusable Agent repeat a rule there. Stated the rule the pages follow. - The registry's Namespaces column was documentation only. A new conformance test rejects a cell that is empty, names something that is not a namespace or claims both "all" and a single namespace. --- apps/docs/content/docs/error-codes.mdx | 3 +- apps/docs/content/docs/meta.json | 2 + .../docs/content/docs/request-conventions.mdx | 4 +- apps/docs/content/guide-sources.json | 10 ++-- apps/docs/scripts/verify-docs-facts.mjs | 11 ++++ contracts/agents-api/error-codes.md | 3 +- docs/api/request-conventions.md | 4 +- .../internal/api/contract_conformance_test.go | 55 +++++++++++++++++++ 8 files changed, 83 insertions(+), 9 deletions(-) diff --git a/apps/docs/content/docs/error-codes.mdx b/apps/docs/content/docs/error-codes.mdx index dd9691547..0e1c8a114 100644 --- a/apps/docs/content/docs/error-codes.mdx +++ b/apps/docs/content/docs/error-codes.mdx @@ -16,7 +16,8 @@ statuses of the uncoded tables to equal the statuses their handlers write. `apps/docs/scripts/verify-error-codes.mjs` does the same for client-generated codes and for every code the client and Web compare against, and the Go test also compares the installation domain setup codes with the installer. The -Namespaces and Meaning columns are maintained by review. +Namespaces column tokens are checked in both files; which namespace a shared +writer reaches is maintained by review, as is the Meaning column. ## Which "code" is meant diff --git a/apps/docs/content/docs/meta.json b/apps/docs/content/docs/meta.json index 7ff7f2f37..f2ccee3a0 100644 --- a/apps/docs/content/docs/meta.json +++ b/apps/docs/content/docs/meta.json @@ -13,6 +13,7 @@ "quickstart", "user-guide", "public-api", + "request-conventions", "agents-and-tools", "sessions", "examples", @@ -24,6 +25,7 @@ "---Administration---", "console", "admin-api", + "error-codes", "observability", "troubleshooting", "api-reference", diff --git a/apps/docs/content/docs/request-conventions.mdx b/apps/docs/content/docs/request-conventions.mdx index 4f36beed5..03c8f3d0d 100644 --- a/apps/docs/content/docs/request-conventions.mdx +++ b/apps/docs/content/docs/request-conventions.mdx @@ -4,7 +4,9 @@ description: "Headers, JSON body checks, list parameters and errors shared by ev --- These rules apply to every `/v1` operation. Operation pages state only what differs -from them. +from them. Descriptions inherited verbatim from the pinned upstream contract are the +exception: they keep upstream's wording, so the Files and Skills operations repeat the +`OpenAI-Beta` rule above and Create a reusable Agent repeats the JSON body checks. ## Headers diff --git a/apps/docs/content/guide-sources.json b/apps/docs/content/guide-sources.json index 0fa2009d3..b57f55ded 100644 --- a/apps/docs/content/guide-sources.json +++ b/apps/docs/content/guide-sources.json @@ -10,7 +10,7 @@ "docs/web/core-connection.md": "861c75c32676fd17b84eb356b263096703af5750c1ceb71bb339e84607fffc56", "docs/getting-started/quickstart.md": "b989682ac2e58d59a794118fd371b37d1ea64c957d3512ff53739458a95d0f9a", "docs/api/README.md": "878a540c3876f703d5e1ded36a2cee7ca462f80b27627897135ac981246fe9f3", - "docs/api/request-conventions.md": "96c23f127aff348a71215ca2474dd15e4725910022b31e9ca1dc704595f3183d", + "docs/api/request-conventions.md": "7381e36fe84f730d6b2f43b1c4efa89ab058244254ad742512d5576f81caf01a", "contracts/agents-api/execution-tools.md": "e0b61f6c0c236c362186c5f6d0ad69a16dd8a8d9afabe1329a1fe22e5f4a71e9", "docs/api/public-agent-api.md": "00979732412a971013e8f01b4c74820ff51aafdded6b0f105d25a78af86a6627", "docs/examples.md": "0e1bdaeff51c9c36779f817be31ea9816b7d8cb2290cf8350d3c4801f436f4f9", @@ -21,7 +21,7 @@ "apps/web/public/onboarding/monitor-en.webp": "29dc220cb1250c7016b7c4bf7f30e9510b07c07b814a48c3aa9303b2d76f20b2", "docs/web/README.md": "47159689b2488f0a94a1af8488bcf98b465e0cca4003d64a4699d7b4db24e086", "docs/api/web-management.md": "fe24e883f5745d262d3bd88eb73ae2cbbb723297b9a237f28849f9e3b50dffd4", - "contracts/agents-api/error-codes.md": "fa28f8d34083b3e4ca7ba765280a913a525548d29211791ae8c2ca203d1ca57c", + "contracts/agents-api/error-codes.md": "dd631413ac7541aa3c24261f564cc739ac4af6795cac25558bd798d4ebe38036", "contracts/agents-api/runtime-observability-api.md": "cd46e777fe716a7e76374f4655c96dfbad9d8be1bfca6203ed6118ab87874c2b", "docs/getting-started/operations.md": "4069e89deed7ef619f28cc8d9779055669246eabe322089113ac3a786c3cb2d5", "docs/user-guide.md": "190bea5bfe23b71db3d9437065ee270e07226a89a6e98c668853e5c7f7555529", @@ -31,7 +31,7 @@ "docs/runtime-bootstrap.md": "0d49aed73b298039e04453e6f465b0e925fb2227fa35d4206820bb3acbd8df39", "docs/runtime-protocol.md": "79f6bf1597eb0c82b41074fd21a6617225ffb7d11572c156e1d56c4e8741f322", "docs/sandbox-provider.md": "4d47b234a457f874f3ff7e61a7f5da6fc8b75b0c6df0ce0ce9ead1c07afdfb3e", - "apps/docs/scripts/guides.json": "d786676bb21bd89554392015b530dbcb5bd5364894abf9fd365334d54a9ae0c9" + "apps/docs/scripts/guides.json": "e3a5d6794957728aa06ca4ef25c960e63f0bac0d4c670d35fbed8d400add087b" }, "outputs": { "content/docs/index.mdx": "432dd8f02f72edb9f39b92d272719b146c5c1bf5b0429191d0f4a56932b92353", @@ -43,7 +43,7 @@ "content/docs/bootstrap-projects-keys.mdx": "91a6f62cbe41737adfce9e8ec56e6dc3e2fb0ec8f6b677576f941cdfb378dc47", "content/docs/quickstart.mdx": "d0ab9537ab68f6dd3109353e937a29c5d58ec3894b56a52873c9a1d79dfa60a6", "content/docs/public-api.mdx": "051ea0082c9875431fd18a03764e38488fae9e79bb0c92291c0c4972042770df", - "content/docs/request-conventions.mdx": "3a81e0faf0e603709c6c59614caaa6a113000a89052e3e38366877219e4c22fc", + "content/docs/request-conventions.mdx": "0316971afd9e53b38f9254a63f27cc0888049eeff3754ccbb4c5dc58c4d564a1", "content/docs/agents-and-tools.mdx": "b8a85fe92e19a71b7ad7c9357ce7ad0595d50c9190edb748ca834df615b056cb", "content/docs/sessions.mdx": "bb63d799ed90038836d652f3f866d0309822425114c6b2aa36654b8a991947f6", "content/docs/examples.mdx": "587061e65ab2e841d14980539ba94e2216d4e8135c948a852b9a8bb0359c85d7", @@ -54,7 +54,7 @@ "public/images/source/apps/web/public/onboarding/monitor-en.webp": "29dc220cb1250c7016b7c4bf7f30e9510b07c07b814a48c3aa9303b2d76f20b2", "content/docs/console.mdx": "a930ce36035de74f0c2bef71bed067fc2287ba1c70a485758bf100d484f6adfd", "content/docs/admin-api.mdx": "f43f4f1cac887bc4baa4968d76542a87ba1a6ddeef9259299b53cd98a4aea5e1", - "content/docs/error-codes.mdx": "0f46873e8041b084996fb10c40f063a45d150e9d7a27def590426390e8630720", + "content/docs/error-codes.mdx": "9a6e25f0859f6ba7e3635506ac7c86dc31ec8b14b4a3b8aa85e5a15dfb4e666d", "content/docs/observability.mdx": "c81214e1865517a9163c48c7ce7c396f5490c9d162080dfa05fa5ebc147f6c8b", "content/docs/troubleshooting.mdx": "bccd725d2389a80b66caf1a1da80532bd68dd3d470bf851799d0114f84e0af25", "content/docs/user-guide.mdx": "7c099b2d787ce3d7876889c7cefd621840ec083f267eadf278214a83f11ba274", diff --git a/apps/docs/scripts/verify-docs-facts.mjs b/apps/docs/scripts/verify-docs-facts.mjs index ccf9b0b4c..2e7272594 100644 --- a/apps/docs/scripts/verify-docs-facts.mjs +++ b/apps/docs/scripts/verify-docs-facts.mjs @@ -26,5 +26,16 @@ for (const file of fs.readdirSync(path.join(app, 'content/docs')).filter(n => n. const text = fs.readFileSync(path.join(app, 'content/docs', file), 'utf8') for (const retired of ['/core/v1/admin', 'sandbox-manager.openapi.yaml']) assert.ok(!text.includes(retired), 'Obsolete claim in ' + file + ': ' + retired) } +// The sidebar is built from this list, so a page missing from it is reachable +// only by direct link. fumadocs adds unlisted files back only for the "..." +// placeholder, which this tree does not use. +const navigation = JSON.parse(fs.readFileSync(path.join(app, 'content/docs/meta.json'))).pages +const docsDir = path.join(app, 'content/docs') +for (const entry of fs.readdirSync(docsDir, { withFileTypes: true })) { + if (entry.name === 'meta.json') continue + const slug = entry.isDirectory() ? entry.name : entry.name.replace(/\.mdx$/, '') + if (!entry.isDirectory() && !entry.name.endsWith('.mdx')) continue + assert.ok(navigation.includes(slug), 'Page is missing from the sidebar (content/docs/meta.json): ' + slug) +} assert.deepEqual(fs.readFileSync(path.join(app, 'app/icon.svg')), fs.readFileSync(path.join(repo, 'apps/web/public/favicon.svg')), 'Docs favicon must match the approved Web asset') console.log('Guide copies, source authority and namespace/configuration facts are current.') diff --git a/contracts/agents-api/error-codes.md b/contracts/agents-api/error-codes.md index 601859b5a..3973feb27 100644 --- a/contracts/agents-api/error-codes.md +++ b/contracts/agents-api/error-codes.md @@ -13,7 +13,8 @@ statuses of the uncoded tables to equal the statuses their handlers write. `apps/docs/scripts/verify-error-codes.mjs` does the same for client-generated codes and for every code the client and Web compare against, and the Go test also compares the installation domain setup codes with the installer. The -Namespaces and Meaning columns are maintained by review. +Namespaces column tokens are checked in both files; which namespace a shared +writer reaches is maintained by review, as is the Meaning column. ## Which "code" is meant diff --git a/docs/api/request-conventions.md b/docs/api/request-conventions.md index c4e18b9ff..d6957a038 100644 --- a/docs/api/request-conventions.md +++ b/docs/api/request-conventions.md @@ -1,7 +1,9 @@ # Request conventions These rules apply to every `/v1` operation. Operation pages state only what differs -from them. +from them. Descriptions inherited verbatim from the pinned upstream contract are the +exception: they keep upstream's wording, so the Files and Skills operations repeat the +`OpenAI-Beta` rule above and Create a reusable Agent repeats the JSON body checks. ## Headers diff --git a/services/agents-api/internal/api/contract_conformance_test.go b/services/agents-api/internal/api/contract_conformance_test.go index 4058f7f4d..1d6f56695 100644 --- a/services/agents-api/internal/api/contract_conformance_test.go +++ b/services/agents-api/internal/api/contract_conformance_test.go @@ -865,3 +865,58 @@ func TestInstallationDomainCodesMatchRegistry(t *testing.T) { add(invalid, text[codes[4]:codes[5]], codes[0]) compareRegistry(t, "Installation domain setup codes", emitted) } + +// TestErrorCodeRegistryNamespacesAreValid reads the Namespaces column, which no +// other check touches. Reachability is not derived: a code emitted through the +// store dispatcher cannot be attributed to a namespace statically, so only the +// cell's form is checked. A token that is not a namespace, an empty cell or a +// row claiming both "all" and a single namespace is always wrong. +func TestErrorCodeRegistryNamespacesAreValid(t *testing.T) { + raw, err := os.ReadFile(filepath.Join(conformanceRepoRoot, "contracts/agents-api/error-codes.md")) + if err != nil { + t.Fatal(err) + } + row := regexp.MustCompile("^\\| *([0-9]{3}) *\\| *(`[a-z0-9_]+`|null) *\\| *([^|]*?) *\\|") + valid := map[string]bool{"all": true, "/v1": true, "/core/v1": true, "/api/v1": true} + inside, found, rows := false, false, 0 + for _, line := range strings.Split(string(raw), "\n") { + if strings.HasPrefix(line, "## ") { + inside = strings.TrimSpace(strings.TrimPrefix(line, "## ")) == "HTTP API codes" + found = found || inside + continue + } + if !inside { + continue + } + match := row.FindStringSubmatch(line) + if match == nil { + continue + } + rows++ + where := match[1] + " " + match[2] + var tokens []string + for _, token := range strings.Split(match[3], ",") { + token = strings.Trim(strings.TrimSpace(token), "`") + if token == "" { + t.Errorf("HTTP API codes: %s has an empty namespace", where) + continue + } + if !valid[token] { + t.Errorf("HTTP API codes: %s names %q, which is not a namespace", where, token) + } + tokens = append(tokens, token) + } + if len(tokens) == 0 { + t.Errorf("HTTP API codes: %s names no namespace", where) + } + if len(tokens) > 1 && valid[tokens[0]] && tokens[0] == "all" { + t.Errorf("HTTP API codes: %s claims both \"all\" and %s", where, strings.Join(tokens[1:], ", ")) + } + } + if !found { + t.Fatal("error-codes.md has no section \"HTTP API codes\"") + } + if rows == 0 { + t.Fatal("error-codes.md HTTP API codes has no rows with a Namespaces cell") + } +} From 83ac23759843acc67ababc5c6aec44e770c85a19 Mon Sep 17 00:00:00 2001 From: Yao Date: Wed, 30 Sep 2026 10:55:50 +0800 Subject: [PATCH 10/14] docs: describe the shared request rules and the Namespaces column --- apps/docs/content/docs/error-codes.mdx | 4 ++-- apps/docs/content/docs/request-conventions.mdx | 8 ++++---- apps/docs/content/guide-sources.json | 8 ++++---- contracts/agents-api/error-codes.md | 4 ++-- docs/api/request-conventions.md | 8 ++++---- 5 files changed, 16 insertions(+), 16 deletions(-) diff --git a/apps/docs/content/docs/error-codes.mdx b/apps/docs/content/docs/error-codes.mdx index 0e1c8a114..218ff055e 100644 --- a/apps/docs/content/docs/error-codes.mdx +++ b/apps/docs/content/docs/error-codes.mdx @@ -16,8 +16,8 @@ statuses of the uncoded tables to equal the statuses their handlers write. `apps/docs/scripts/verify-error-codes.mjs` does the same for client-generated codes and for every code the client and Web compare against, and the Go test also compares the installation domain setup codes with the installer. The -Namespaces column tokens are checked in both files; which namespace a shared -writer reaches is maintained by review, as is the Meaning column. +Namespaces column tokens are checked in both files: `all`, or the namespaces +whose routes can answer with the code. ## Which "code" is meant diff --git a/apps/docs/content/docs/request-conventions.mdx b/apps/docs/content/docs/request-conventions.mdx index 03c8f3d0d..547aef585 100644 --- a/apps/docs/content/docs/request-conventions.mdx +++ b/apps/docs/content/docs/request-conventions.mdx @@ -3,10 +3,10 @@ title: "Request conventions" description: "Headers, JSON body checks, list parameters and errors shared by every /v1 operation." --- -These rules apply to every `/v1` operation. Operation pages state only what differs -from them. Descriptions inherited verbatim from the pinned upstream contract are the -exception: they keep upstream's wording, so the Files and Skills operations repeat the -`OpenAI-Beta` rule above and Create a reusable Agent repeats the JSON body checks. +These rules apply to every `/v1` operation. An operation page adds only what that +operation does differently, and repeats a rule from above where the operation's own +description states it: the Files and Skills operations repeat the `OpenAI-Beta` rule, +and Create a reusable Agent repeats the JSON body checks. ## Headers diff --git a/apps/docs/content/guide-sources.json b/apps/docs/content/guide-sources.json index b57f55ded..bdf5191d8 100644 --- a/apps/docs/content/guide-sources.json +++ b/apps/docs/content/guide-sources.json @@ -10,7 +10,7 @@ "docs/web/core-connection.md": "861c75c32676fd17b84eb356b263096703af5750c1ceb71bb339e84607fffc56", "docs/getting-started/quickstart.md": "b989682ac2e58d59a794118fd371b37d1ea64c957d3512ff53739458a95d0f9a", "docs/api/README.md": "878a540c3876f703d5e1ded36a2cee7ca462f80b27627897135ac981246fe9f3", - "docs/api/request-conventions.md": "7381e36fe84f730d6b2f43b1c4efa89ab058244254ad742512d5576f81caf01a", + "docs/api/request-conventions.md": "3e5e96350ab6fcf24457ece52fb9a582479ddb157cebbf34cc1cf13a22b09ba8", "contracts/agents-api/execution-tools.md": "e0b61f6c0c236c362186c5f6d0ad69a16dd8a8d9afabe1329a1fe22e5f4a71e9", "docs/api/public-agent-api.md": "00979732412a971013e8f01b4c74820ff51aafdded6b0f105d25a78af86a6627", "docs/examples.md": "0e1bdaeff51c9c36779f817be31ea9816b7d8cb2290cf8350d3c4801f436f4f9", @@ -21,7 +21,7 @@ "apps/web/public/onboarding/monitor-en.webp": "29dc220cb1250c7016b7c4bf7f30e9510b07c07b814a48c3aa9303b2d76f20b2", "docs/web/README.md": "47159689b2488f0a94a1af8488bcf98b465e0cca4003d64a4699d7b4db24e086", "docs/api/web-management.md": "fe24e883f5745d262d3bd88eb73ae2cbbb723297b9a237f28849f9e3b50dffd4", - "contracts/agents-api/error-codes.md": "dd631413ac7541aa3c24261f564cc739ac4af6795cac25558bd798d4ebe38036", + "contracts/agents-api/error-codes.md": "89fcc0b2017d480eddf1474636d560a2fafabdd7cb7a5cb8cc7f1836fe7778a3", "contracts/agents-api/runtime-observability-api.md": "cd46e777fe716a7e76374f4655c96dfbad9d8be1bfca6203ed6118ab87874c2b", "docs/getting-started/operations.md": "4069e89deed7ef619f28cc8d9779055669246eabe322089113ac3a786c3cb2d5", "docs/user-guide.md": "190bea5bfe23b71db3d9437065ee270e07226a89a6e98c668853e5c7f7555529", @@ -43,7 +43,7 @@ "content/docs/bootstrap-projects-keys.mdx": "91a6f62cbe41737adfce9e8ec56e6dc3e2fb0ec8f6b677576f941cdfb378dc47", "content/docs/quickstart.mdx": "d0ab9537ab68f6dd3109353e937a29c5d58ec3894b56a52873c9a1d79dfa60a6", "content/docs/public-api.mdx": "051ea0082c9875431fd18a03764e38488fae9e79bb0c92291c0c4972042770df", - "content/docs/request-conventions.mdx": "0316971afd9e53b38f9254a63f27cc0888049eeff3754ccbb4c5dc58c4d564a1", + "content/docs/request-conventions.mdx": "c47b1c5a0785ec786e3d5619218a04a6841538ceefee891ce6e18d2c61a09858", "content/docs/agents-and-tools.mdx": "b8a85fe92e19a71b7ad7c9357ce7ad0595d50c9190edb748ca834df615b056cb", "content/docs/sessions.mdx": "bb63d799ed90038836d652f3f866d0309822425114c6b2aa36654b8a991947f6", "content/docs/examples.mdx": "587061e65ab2e841d14980539ba94e2216d4e8135c948a852b9a8bb0359c85d7", @@ -54,7 +54,7 @@ "public/images/source/apps/web/public/onboarding/monitor-en.webp": "29dc220cb1250c7016b7c4bf7f30e9510b07c07b814a48c3aa9303b2d76f20b2", "content/docs/console.mdx": "a930ce36035de74f0c2bef71bed067fc2287ba1c70a485758bf100d484f6adfd", "content/docs/admin-api.mdx": "f43f4f1cac887bc4baa4968d76542a87ba1a6ddeef9259299b53cd98a4aea5e1", - "content/docs/error-codes.mdx": "9a6e25f0859f6ba7e3635506ac7c86dc31ec8b14b4a3b8aa85e5a15dfb4e666d", + "content/docs/error-codes.mdx": "25eb59da9f87ecc451142a036022e3269465eabd903d19604099d7fa3512e8e4", "content/docs/observability.mdx": "c81214e1865517a9163c48c7ce7c396f5490c9d162080dfa05fa5ebc147f6c8b", "content/docs/troubleshooting.mdx": "bccd725d2389a80b66caf1a1da80532bd68dd3d470bf851799d0114f84e0af25", "content/docs/user-guide.mdx": "7c099b2d787ce3d7876889c7cefd621840ec083f267eadf278214a83f11ba274", diff --git a/contracts/agents-api/error-codes.md b/contracts/agents-api/error-codes.md index 3973feb27..e9dd98b2e 100644 --- a/contracts/agents-api/error-codes.md +++ b/contracts/agents-api/error-codes.md @@ -13,8 +13,8 @@ statuses of the uncoded tables to equal the statuses their handlers write. `apps/docs/scripts/verify-error-codes.mjs` does the same for client-generated codes and for every code the client and Web compare against, and the Go test also compares the installation domain setup codes with the installer. The -Namespaces column tokens are checked in both files; which namespace a shared -writer reaches is maintained by review, as is the Meaning column. +Namespaces column tokens are checked in both files: `all`, or the namespaces +whose routes can answer with the code. ## Which "code" is meant diff --git a/docs/api/request-conventions.md b/docs/api/request-conventions.md index d6957a038..a925c9520 100644 --- a/docs/api/request-conventions.md +++ b/docs/api/request-conventions.md @@ -1,9 +1,9 @@ # Request conventions -These rules apply to every `/v1` operation. Operation pages state only what differs -from them. Descriptions inherited verbatim from the pinned upstream contract are the -exception: they keep upstream's wording, so the Files and Skills operations repeat the -`OpenAI-Beta` rule above and Create a reusable Agent repeats the JSON body checks. +These rules apply to every `/v1` operation. An operation page adds only what that +operation does differently, and repeats a rule from above where the operation's own +description states it: the Files and Skills operations repeat the `OpenAI-Beta` rule, +and Create a reusable Agent repeats the JSON body checks. ## Headers From 677f8c5f1a93b139263b60ec03543b13c6f25d81 Mon Sep 17 00:00:00 2001 From: Yao Date: Wed, 30 Sep 2026 10:55:53 +0800 Subject: [PATCH 11/14] docs: render the architecture overview on the documentation site The execution-model page rendered docs/web/architecture.md, which carries a Mermaid fence the site cannot draw. It now renders docs/architecture.md, the architecture overview, so the page shows its three diagrams and no Mermaid fence is left anywhere on the site. --- apps/docs/content/docs/console.mdx | 2 +- apps/docs/content/docs/development.mdx | 2 +- apps/docs/content/docs/error-codes.mdx | 2 +- apps/docs/content/docs/execution-model.mdx | 211 +++++++++--------- apps/docs/content/docs/index.mdx | 2 +- apps/docs/content/docs/public-api.mdx | 2 +- apps/docs/content/guide-sources.json | 22 +- .../docs/assets/architecture-api-surfaces.png | Bin 0 -> 196135 bytes .../docs/assets/architecture-overview.png | Bin 0 -> 334655 bytes .../docs/assets/architecture-session-flow.png | Bin 0 -> 145288 bytes apps/docs/scripts/generate-guides.mjs | 2 +- apps/docs/scripts/guides.json | 6 +- 12 files changed, 125 insertions(+), 126 deletions(-) create mode 100644 apps/docs/public/images/source/docs/assets/architecture-api-surfaces.png create mode 100644 apps/docs/public/images/source/docs/assets/architecture-overview.png create mode 100644 apps/docs/public/images/source/docs/assets/architecture-session-flow.png diff --git a/apps/docs/content/docs/console.mdx b/apps/docs/content/docs/console.mdx index 76b682aa4..addbf0dee 100644 --- a/apps/docs/content/docs/console.mdx +++ b/apps/docs/content/docs/console.mdx @@ -52,7 +52,7 @@ through the management API. The browser signs in to the console with the Core ke only the console server sends it to Core. - [Connection and authentication](/bootstrap-projects-keys) -- [Architecture and ownership](/execution-model) +- [Architecture and ownership](https://github.com/MiniMax-AI/parsar-core/blob/f6d258735fc601c521dd990e6f9e1ed261f4ef2d/docs/web/architecture.md) - [Management interface coverage](https://github.com/MiniMax-AI/parsar-core/blob/f6d258735fc601c521dd990e6f9e1ed261f4ef2d/docs/web/protocol-coverage.md) - [Frontend handoff and acceptance](https://github.com/MiniMax-AI/parsar-core/blob/f6d258735fc601c521dd990e6f9e1ed261f4ef2d/docs/web/roadmap.md) - [React application](https://github.com/MiniMax-AI/parsar-core/blob/f6d258735fc601c521dd990e6f9e1ed261f4ef2d/apps/web/README.md) diff --git a/apps/docs/content/docs/development.mdx b/apps/docs/content/docs/development.mdx index 7173802e1..2fa4bc7eb 100644 --- a/apps/docs/content/docs/development.mdx +++ b/apps/docs/content/docs/development.mdx @@ -93,7 +93,7 @@ site; `pnpm dev:docs` starts its development server. | `apps/parsar-daemon/internal/dispatch` | Runtime preparation, Executor reuse, Turn and cleanup ownership | [Harness lifecycle](/harness-onboarding#required-adapter-interfaces) | | `apps/parsar-daemon/internal/agent` | Native harness adapters | [Native references](/harness-onboarding#native-references) | | `services/agents-api/internal/sandbox` | Provider interfaces and managed compute lifecycle | [Provider onboarding](/sandbox-provider) | -| `services/core-console` | Console login and the server-side management proxy | [Web architecture](/execution-model) | +| `services/core-console` | Console login and the server-side management proxy | [Web architecture](https://github.com/MiniMax-AI/parsar-core/blob/f6d258735fc601c521dd990e6f9e1ed261f4ef2d/docs/web/architecture.md) | | `apps/web` and `packages/agents-client` | Console UI and typed clients | [Web guide](https://github.com/MiniMax-AI/parsar-core/blob/f6d258735fc601c521dd990e6f9e1ed261f4ef2d/apps/web/README.md) | | `deploy/install` and `scripts` | Distribution, installation and validation tools | [Maintainers](https://github.com/MiniMax-AI/parsar-core/blob/f6d258735fc601c521dd990e6f9e1ed261f4ef2d/docs/maintainers.md) | | `contracts/agents-api` | Pinned schema, local semantic contracts and qualification evidence | [Coverage ledger](https://github.com/MiniMax-AI/parsar-core/blob/f6d258735fc601c521dd990e6f9e1ed261f4ef2d/contracts/agents-api/README.md) | diff --git a/apps/docs/content/docs/error-codes.mdx b/apps/docs/content/docs/error-codes.mdx index 218ff055e..015b4c698 100644 --- a/apps/docs/content/docs/error-codes.mdx +++ b/apps/docs/content/docs/error-codes.mdx @@ -155,7 +155,7 @@ null `param`, and the Environment state `error` of Web's server writes these for `/core/*` requests it rejects before forwarding, and for the console-local `POST /console/installation/domain` HTTPS setup request. See [Core errors](https://github.com/MiniMax-AI/parsar-core/blob/f6d258735fc601c521dd990e6f9e1ed261f4ef2d/contracts/agents-api/core-errors.md#console-generated-failures) and -[Web request boundaries](/execution-model#request-boundaries). +[Web request boundaries](https://github.com/MiniMax-AI/parsar-core/blob/f6d258735fc601c521dd990e6f9e1ed261f4ef2d/docs/web/architecture.md#request-boundaries). | Status | Code | Meaning | | --- | --- | --- | diff --git a/apps/docs/content/docs/execution-model.mdx b/apps/docs/content/docs/execution-model.mdx index 003336f41..68647b2c9 100644 --- a/apps/docs/content/docs/execution-model.mdx +++ b/apps/docs/content/docs/execution-model.mdx @@ -1,112 +1,105 @@ --- -title: "Execution and API architecture" -description: "Applications call the public API; the administrator browser calls Web; Runtime connects to Core." +title: "Architecture" +description: "Core, the Runtime daemon and the native harness: the three namespaces, replaceable parts and a Session end to end." --- -![Application, administration and machine credential boundaries](/images/architecture.svg) - -Core Web manages a Core deployment. Applications, including Parsar, use the public -Agents API independently with their own Project keys. The management backend, -`AdminClient` and the React console built on them are implemented. - -The [design principles](/concepts) define identity and authority. -The [administrator contract](https://github.com/MiniMax-AI/parsar-core/blob/f6d258735fc601c521dd990e6f9e1ed261f4ef2d/contracts/agents-api/admin-api.md) defines exact -routes, payloads, pagination and audit records. - -## Request boundaries - -```mermaid -flowchart LR - browser["Administrator browser"] - console["Core console service"] - core["Core API"] - database[("PostgreSQL")] - application["Application / official SDK"] - runtime["Runtime and native adapters"] - - browser -->|"Same-origin management requests; console login"| console - console -->|"/core/v1/* by prefix, including sandbox; Core key"| core - application -->|"/v1; Project API key"| core - core <--> database - core <--> runtime -``` - -React management code must use the Core clients from `packages/agents-client`: -`AdminClient` for `/core/v1`, `CoreMetricsClient` for `/core/v1/metrics` and the -sandbox management client for `/core/v1/sandbox`. The console service -returns 404 for `/v1` and `/api/v1`, including requests with an explicit Bearer -token. It has no application key and does not impersonate the selected Project. - -The console signs the browser in with the Core key, checks the host and origin, and -forwards every signed-in `/core/v1/*` request to Core by prefix; Core alone decides -whether the route exists. It strips the browser's Authorization, Cookie, Origin and -Referer headers and supplies the Core key as its private upstream credential. Core -rejects application keys on management routes and the Core key on `/v1`. -The audit actor label is declared by the caller and is display only, never Core authorization: the console server declares `console`, and operator scripts calling Core with the Core key directly leave it empty. - -`GET` and `POST /console/installation/domain` are the scoped installation-management -exception: the console authenticates the same browser session and origin, then -calls the installer's private Unix socket with its server-held Core key. This is -not a Core `/core/v1` route and does not use `AdminClient`. It can configure only -the managed domain; it cannot submit shell commands or arbitrary process settings. -The [installer rules](https://github.com/MiniMax-AI/parsar-core/blob/f6d258735fc601c521dd990e6f9e1ed261f4ef2d/docs/maintainers.md#managed-https-ownership) own application, -certificates and recovery. Before a domain is configured, the console accepts -same-origin HTTP requests at literal IP addresses; after apply, only the configured -HTTPS origin is accepted. - -Node and daemon connections use `/api/v1` with their own credentials. The reverse -proxy sends them directly to Core; the console never forwards them, and they do not -grant a browser execution authority. - -## Ownership - -| Component | Responsibility | -| --- | --- | -| React frontend | Project selection, permitted management actions and operational views; cached reads (TanStack Query) that keep the last data on screen while refreshing | -| `AdminClient` | Typed management requests and validation, sharing resource parsers with the public client | -| `services/core-console` | Core key login, host/origin checks, and prefix forwarding of `/core/v1/*` with the Core key as the private upstream credential | -| Core API and PostgreSQL | Project isolation, resource state, deletion preconditions, audit and scheduling | -| Runtime and native adapters | Existing allocation, process lifecycle and execution protocols | - -Projects, keys and administrator authority follow the -[design principles](/concepts#projects-own-assets). The console adds -no execution path: a deletion conflict is never resolved by an implicit cancellation. - -Secret fields remain write-only; Skill source and Artifact content have explicit -read routes, while Source File content does not have an administrator download -route. - -## Deployment and application Runtime paths - -Deployment sandbox management selects one provider at a time: E2B, Docker or -microsandbox. E2B uses the deployment's provider integration; Docker and microsandbox -use operator-managed machines. Provider setup, reset and node administration -belong to the existing sandbox management surface. - -An application's `self_hosted` Runtime, including one it provisions in its own E2B -account, is a separate caller-managed path. It does not choose or reconfigure the -deployment provider. This console contract changes neither native Runtime protocols -nor application Session creation semantics. - -## Frontend state and validation - -Session inspection uses paginated durable history and bounded polling. There is no -management Session SSE endpoint. Project changes must discard stale reads and -pending operation state before displaying results in another Project. - -The client sends each write once per explicit action. An uncertain result stays -visible until the administrator checks state and decides how to proceed. Issued -key plaintext must not enter browser storage or logs. Key issuance recovery -follows the administrator contract. - -The sandbox deployment read (`GET /core/v1/sandbox/deployment`) describes the saved -selection. It does not prove a reachable model, valid provider credentials or -execution readiness. Runtime observations, usage coverage and audit history must -retain the distinctions defined by Core. In E2B views, the running sandbox count -comes from the deployment's allocations; the hosted Runtime total counts hosted -observation records across projects and reported lifecycle states. These sources -have different coverage and refresh independently, so the console does not infer -resource retention or cleanup from their difference. -Native execution ownership remains governed by [CONTRIBUTING.md](https://github.com/MiniMax-AI/parsar-core/blob/f6d258735fc601c521dd990e6f9e1ed261f4ef2d/CONTRIBUTING.md). - -[Repository source](https://github.com/MiniMax-AI/parsar-core/blob/f6d258735fc601c521dd990e6f9e1ed261f4ef2d/docs/web/architecture.md) +OpenAgentCore separates control, runtime and execution. Core owns durable state +and the API; the Runtime daemon runs work inside an Environment; the native harness +keeps its own model and tool loop. Each connection between them is a defined +protocol, so any part can be replaced without changing Core orchestration. + +This page is a map. Each section names a component, its boundary and the document +that owns its rules. + +![OpenAgentCore architecture](/images/source/docs/assets/architecture-overview.png) + +The diagram has four tiers: + +1. **Callers.** Applications, including your product and the official OpenAI SDK, + call the Agents API. Operators use Core Web, which calls the Core API. +2. **Core.** The control plane: public and administrator APIs, resources, + orchestration, PostgreSQL, the Runtime gateway and the Sandbox Provider + interface. +3. **Environment.** Where the agent works: a Core-managed sandbox or your own + machine. The Runtime daemon prepares capabilities and starts the native harness, + which works on the workspace and tools. +4. **Outside Core.** The model API and remote MCP servers, called by the harness + with the Session's model provider. + +## Two APIs, and a machine channel + +![Three namespaces and their credentials](/images/source/docs/assets/architecture-api-surfaces.png) + +Core serves three namespaces: the Agents API (`/v1`) for applications, the Core +API (`/core/v1`) for operators, and a machine API (`/api/v1`) for nodes and Runtime +daemons. Each has its own credential; one used elsewhere gets 401. The +[API index](/public-api) owns the full matrix of callers, credentials and routes. + +## Core + +Core is the only owner of durable execution facts: Projects and keys, Agents, +Sessions, Turns, Items, Environments, files and audit records, all in PostgreSQL. +It schedules Turns, handles cancellation and pending interactions, and checks that +a requested harness, Environment and capability combination is supported before +starting work. + +Core does not isolate tools, run a model or talk to a vendor SDK directly. It +selects implementations through interfaces and never branches on a harness, +operating system or provider name. See +[the decoupling principle](https://github.com/MiniMax-AI/parsar-core/blob/f6d258735fc601c521dd990e6f9e1ed261f4ef2d/CONTRIBUTING.md#decoupling-principle) and the +[repository map](/development#repository-map). + +## Replaceable parts + +| Part | Responsibility | Connects through | Current implementations | Add one | +| --- | --- | --- | --- | --- | +| Sandbox Provider | Creates, bootstraps, renews and reclaims the outer Environment | `SandboxProvider` interface | Docker, microsandbox, E2B, sandbox nodes | [Sandbox Provider guide](/sandbox-provider) | +| Runtime | Prepares Skills, MCP and files, runs executors, owns local cleanup | Core–Runtime protocol over `/api/v1` | `oac-daemon`: managed Linux; self-hosted Linux, macOS and Windows | [Core–Runtime protocol](/runtime-protocol) | +| Harness | Runs the native model and tool loop | Harness adapter (`Executor` and `Turn`) | Codex, Claude Code, MiniMax Code | [Harness onboarding](/harness-onboarding) | +| Model Provider | Serves inference for the harness | Responses, Anthropic or Chat Completions protocol | Any endpoint speaking one of those protocols | [Model execution](https://github.com/MiniMax-AI/parsar-core/blob/f6d258735fc601c521dd990e6f9e1ed261f4ef2d/contracts/agents-api/model-execution.md) | + +Replaceability does not mean every combination works. Supported combinations are +declared as capabilities and validated explicitly; see +[Harness selection](https://github.com/MiniMax-AI/parsar-core/blob/f6d258735fc601c521dd990e6f9e1ed261f4ef2d/contracts/agents-api/harness-selection.md) and the +[coverage record](https://github.com/MiniMax-AI/parsar-core/blob/f6d258735fc601c521dd990e6f9e1ed261f4ef2d/contracts/agents-api/README.md). + +## A Session, end to end + +![A managed Session from creation to result](/images/source/docs/assets/architecture-session-flow.png) + +For a Core-managed (`openai_hosted`) Session: + +1. The application creates a Session through the Agents API. +2. Core asks the Sandbox Provider for an Environment. +3. The provider starts the Runtime using the [bootstrap contract](/runtime-bootstrap). +4. The daemon dials into Core and advertises its capabilities. +5. Core sends the preparation request; Runtime prepares Skills, MCP declarations + and initial files inside the Environment. +6. The application sends input. +7. Core prepares and starts execution on the daemon. +8. The daemon's harness adapter starts a native Turn. +9. The harness runs its model and tool loop against the model provider. +10. The daemon streams events, output and usage back to Core, then `done`. +11. The application reads Items and events from Core. + +A `self_hosted` Session skips steps 2 and 3: an administrator issues an executor +credential and you start the daemon on your own machine +([self-hosted guide](/self-hosted-execution)). A `none` Session uses an +existing device connection. Everything from step 4 onward is the same protocol. +The [Environment contract](/environments-and-files) covers +placement and expiry; the [Core–Runtime protocol](/runtime-protocol) defines +message order, receipts and failure ownership. + +## Boundaries to keep in mind + +- **Isolation belongs to the outer Environment.** The daemon is not a sandbox + ([Runtime and outer isolation](/concepts#runtime-and-outer-isolation)). +- **Execution and compute have separate lifetimes.** Closing an executor does not + release its allocation, destroy its Environment or delete its workspace. + Reclamation is an explicit Sandbox Provider operation. +- **Model keys stay with the compute that owns them.** A self-hosted Session brings + its own model provider ([why](/user-guide#which-model-provider-a-session-uses)). +- **Core Web is an administrator console.** It calls only `/core/v1` and cannot + start Sessions or send input ([Web architecture](https://github.com/MiniMax-AI/parsar-core/blob/f6d258735fc601c521dd990e6f9e1ed261f4ef2d/docs/web/architecture.md)). + +[Repository source](https://github.com/MiniMax-AI/parsar-core/blob/f6d258735fc601c521dd990e6f9e1ed261f4ef2d/docs/architecture.md) diff --git a/apps/docs/content/docs/index.mdx b/apps/docs/content/docs/index.mdx index 9c86b0981..48195accc 100644 --- a/apps/docs/content/docs/index.mdx +++ b/apps/docs/content/docs/index.mdx @@ -5,7 +5,7 @@ description: "Install Core and Web, create a Project API key, and add execution OpenAgentCore runs AI agents on your own infrastructure behind the OpenAI Agents API. Pick the path that matches your role. New here? Read the -[architecture overview](https://github.com/MiniMax-AI/parsar-core/blob/f6d258735fc601c521dd990e6f9e1ed261f4ef2d/docs/architecture.md) first. +[architecture overview](/execution-model) first. ## Operators: install and run diff --git a/apps/docs/content/docs/public-api.mdx b/apps/docs/content/docs/public-api.mdx index 297887921..bb8da4d74 100644 --- a/apps/docs/content/docs/public-api.mdx +++ b/apps/docs/content/docs/public-api.mdx @@ -147,7 +147,7 @@ ownership and platform rules. The console-local `GET`/`POST /console/installation/domain` surface uses the signed-in browser session and same-origin checks. It delegates only domain setup to the installer, with the server-held Core key over a private Unix socket; it is not part -of the Agents API or Core management API. See [Web request boundaries](/execution-model#request-boundaries). +of the Agents API or Core management API. See [Web request boundaries](https://github.com/MiniMax-AI/parsar-core/blob/f6d258735fc601c521dd990e6f9e1ed261f4ef2d/docs/web/architecture.md#request-boundaries). Core administration failures use the [Core error envelope](https://github.com/MiniMax-AI/parsar-core/blob/f6d258735fc601c521dd990e6f9e1ed261f4ef2d/contracts/agents-api/core-errors.md), including typed optional safe details and distinct console proxy rejection codes. diff --git a/apps/docs/content/guide-sources.json b/apps/docs/content/guide-sources.json index bdf5191d8..2872544e3 100644 --- a/apps/docs/content/guide-sources.json +++ b/apps/docs/content/guide-sources.json @@ -3,7 +3,10 @@ "sources": { "docs/getting-started/README.md": "d46e1b6cd0693a282f504297c87df6ddf26b99ce8c7afdb613666acd836767f5", "docs/design-principles.md": "21a05fb089804db6fab5674ec9a6cf849a3affedad2ca927a38d9b46eeec9a50", - "docs/web/architecture.md": "7d5daf7745d2a25bf1113eea48512b085137f4f806c3fa0b6b16af63f7b18c4e", + "docs/assets/architecture-overview.png": "c6103e2a8730796a15d6c4ae7165f3b9e60dbd09075b459d34821a3ee0d2d49f", + "docs/assets/architecture-api-surfaces.png": "37c0d0d4f42c37ec41f8d4931ef10f182287d94d0928da195bf8b9e377c942e5", + "docs/assets/architecture-session-flow.png": "0f0a78c43d3dfd235f3994421708c65347863665278bd39e79d19b52e13fab7a", + "docs/architecture.md": "dff0924e6f9212f781b44b92e40a3359f68ffed86ab4885557d053df75c0829e", "docs/getting-started/install.md": "84b21002136acd4f006392685b7a071323336e87c1aac6e3c23ca56acb40833c", "docs/getting-started/install-options.md": "e03487bb6d978f84c596467028e25fd99fdc21cf2060af24ceb68df885084798", "docs/configuration.md": "7dc0031145bb5811bf22cab15270b511b1c43b1bd1ee2b71175d3bc848751bd6", @@ -31,18 +34,21 @@ "docs/runtime-bootstrap.md": "0d49aed73b298039e04453e6f465b0e925fb2227fa35d4206820bb3acbd8df39", "docs/runtime-protocol.md": "79f6bf1597eb0c82b41074fd21a6617225ffb7d11572c156e1d56c4e8741f322", "docs/sandbox-provider.md": "4d47b234a457f874f3ff7e61a7f5da6fc8b75b0c6df0ce0ce9ead1c07afdfb3e", - "apps/docs/scripts/guides.json": "e3a5d6794957728aa06ca4ef25c960e63f0bac0d4c670d35fbed8d400add087b" + "apps/docs/scripts/guides.json": "05fa34e2bdddfabb2bb1c6f620323e672e9261e358d04784b8c8331f2c315d9f" }, "outputs": { - "content/docs/index.mdx": "432dd8f02f72edb9f39b92d272719b146c5c1bf5b0429191d0f4a56932b92353", + "content/docs/index.mdx": "ac36f1536e558acd741cdf4986519a5d6098088aa5bc07d3f8a0ccbef3799e75", "content/docs/concepts.mdx": "88ba65e1ba902921d6cd5da2866620a6dbef52c041db991312a138884fb43a4e", - "content/docs/execution-model.mdx": "50133f3911c5ad801868e695ad52651e83809b80cbc887ee0bca25769ad32065", + "public/images/source/docs/assets/architecture-overview.png": "c6103e2a8730796a15d6c4ae7165f3b9e60dbd09075b459d34821a3ee0d2d49f", + "public/images/source/docs/assets/architecture-api-surfaces.png": "37c0d0d4f42c37ec41f8d4931ef10f182287d94d0928da195bf8b9e377c942e5", + "public/images/source/docs/assets/architecture-session-flow.png": "0f0a78c43d3dfd235f3994421708c65347863665278bd39e79d19b52e13fab7a", + "content/docs/execution-model.mdx": "2c06f4fce7bafdae0e0c2acbc587ab3ece38e473019cef6222f7168fe2429c30", "content/docs/install.mdx": "6c3ec01d1b80cbce35d58e3f141b0fa832d6294a2ecc07c3b286ecc56ba66919", "content/docs/install-options.mdx": "aaafc209293a905d5b433511149aa1f0cc422bd31d5bb5b6cd7eec0d532ab8eb", "content/docs/configure.mdx": "02d1eee789646fdf65ed2ec48b6fe954c81107d6ff5891536ec6ac2df0a8c4dc", "content/docs/bootstrap-projects-keys.mdx": "91a6f62cbe41737adfce9e8ec56e6dc3e2fb0ec8f6b677576f941cdfb378dc47", "content/docs/quickstart.mdx": "d0ab9537ab68f6dd3109353e937a29c5d58ec3894b56a52873c9a1d79dfa60a6", - "content/docs/public-api.mdx": "051ea0082c9875431fd18a03764e38488fae9e79bb0c92291c0c4972042770df", + "content/docs/public-api.mdx": "d5a218219d79f3875a02702257e361b866a5137393b2b8f39aca4be4763be87d", "content/docs/request-conventions.mdx": "c47b1c5a0785ec786e3d5619218a04a6841538ceefee891ce6e18d2c61a09858", "content/docs/agents-and-tools.mdx": "b8a85fe92e19a71b7ad7c9357ce7ad0595d50c9190edb748ca834df615b056cb", "content/docs/sessions.mdx": "bb63d799ed90038836d652f3f866d0309822425114c6b2aa36654b8a991947f6", @@ -52,14 +58,14 @@ "content/docs/self-hosted-execution.mdx": "eeed4c6b3646927ccc3c7ac2d20b2c0f9c8a65e42d734310fe3959e016324e57", "content/docs/self-hosted-native.mdx": "671451580dfb4f5c134221991f68292a4f992008174d23190b1da3742046571f", "public/images/source/apps/web/public/onboarding/monitor-en.webp": "29dc220cb1250c7016b7c4bf7f30e9510b07c07b814a48c3aa9303b2d76f20b2", - "content/docs/console.mdx": "a930ce36035de74f0c2bef71bed067fc2287ba1c70a485758bf100d484f6adfd", + "content/docs/console.mdx": "a942877466f672fcad297568800ee297f3c969ead0d87d22bc2d5039829241c5", "content/docs/admin-api.mdx": "f43f4f1cac887bc4baa4968d76542a87ba1a6ddeef9259299b53cd98a4aea5e1", - "content/docs/error-codes.mdx": "25eb59da9f87ecc451142a036022e3269465eabd903d19604099d7fa3512e8e4", + "content/docs/error-codes.mdx": "192e3c4a960fa8a3ce3b2e35bf68eeadad14a598ef007fa00a685a3235291605", "content/docs/observability.mdx": "c81214e1865517a9163c48c7ce7c396f5490c9d162080dfa05fa5ebc147f6c8b", "content/docs/troubleshooting.mdx": "bccd725d2389a80b66caf1a1da80532bd68dd3d470bf851799d0114f84e0af25", "content/docs/user-guide.mdx": "7c099b2d787ce3d7876889c7cefd621840ec083f267eadf278214a83f11ba274", "public/images/source/docs/assets/development-architecture.png": "24e6d0145d4f16ad70b07b6bc643808a6455aaf6398434d199cf74def200fca6", - "content/docs/development.mdx": "2e5249ddfca571d264e93fd1e0e390a4bd5b0b623bda100cd02f2982929850bb", + "content/docs/development.mdx": "3a53e2a8d4c91897e160ce01f07f1609fa101b254bdfa1b0e53ac21f108db342", "content/docs/harness-onboarding.mdx": "d9c9dcbd339ba9b278b133816c1d905bdbd849f44e2ff27882090cd39002e1c8", "content/docs/runtime-bootstrap.mdx": "58982955811c9ad46a9fc04d8d2aef5a762fc9d25d5833f88aa75ee3fc46523f", "content/docs/runtime-protocol.mdx": "fed94a899e953c486d8560a21a2eb15a8c41c173d020e21b57cd207c08c272b7", diff --git a/apps/docs/public/images/source/docs/assets/architecture-api-surfaces.png b/apps/docs/public/images/source/docs/assets/architecture-api-surfaces.png new file mode 100644 index 0000000000000000000000000000000000000000..a4b997d2102d414359d0dcb32f80b055b2759cf0 GIT binary patch literal 196135 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%0DG;Ztw;{w9~M;i?8_$?71}$g8-^oHiEqs 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 z

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 DB8^EV literal 0 HcmV?d00001 diff --git a/apps/docs/public/images/source/docs/assets/architecture-overview.png b/apps/docs/public/images/source/docs/assets/architecture-overview.png new file mode 100644 index 0000000000000000000000000000000000000000..7d2cccf5d697ca8ac6c5448b232e9cfb5fd8af44 GIT binary patch literal 334655 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,A)GBUg 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 z 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 z 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 literal 0 HcmV?d00001 diff --git a/apps/docs/public/images/source/docs/assets/architecture-session-flow.png b/apps/docs/public/images/source/docs/assets/architecture-session-flow.png new file mode 100644 index 0000000000000000000000000000000000000000..660755ac8bdd90c5f84738d17fe379405faaf6d7 GIT binary patch literal 145288 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 Date: Wed, 30 Sep 2026 11:05:02 +0800 Subject: [PATCH 12/14] docs: regenerate after the Runtime MCP binding change Upstream's Runtime MCP binding and workspace execution capabilities change edits the public contract, so two Session operation pages and the generated source records follow it. --- .../sessions/create-an-execution-session.mdx | 137 +++++++++--------- .../sessions/submit-session-input-events.mdx | 20 +-- apps/docs/content/guide-sources.json | 16 +- apps/docs/openapi/sources.json | 8 +- 4 files changed, 91 insertions(+), 90 deletions(-) diff --git a/apps/docs/content/docs/api-reference/sessions/create-an-execution-session.mdx b/apps/docs/content/docs/api-reference/sessions/create-an-execution-session.mdx index c57e6f95d..4f3bcfddd 100644 --- a/apps/docs/content/docs/api-reference/sessions/create-an-execution-session.mdx +++ b/apps/docs/content/docs/api-reference/sessions/create-an-execution-session.mdx @@ -62,71 +62,72 @@ _openapi: roots reject admission with the same errors, and execution limits keep unsupported_or_invalid_configuration. Hosted network policy rejections return invalid_request_error with a null param. Initial input accepts a string or ordered - user-message array. Codex and Claude SDK on none and qualified openai_hosted also accept - inline PNG/JPEG image content; other image combinations and remote URLs are unsupported. - None initial input atomically starts a Turn; self_hosted initial input is reserved while - returning its Environment connection target, with execution deferred to native readiness - and Session failure on initial timeout. Initial input is required for none and for - streamed creation outside self_hosted. Omitted/null input remains valid for non-streaming - hosted and self_hosted creation. With stream=true, returns live Session events starting - with the committed creation snapshot and closes right after the first agent.session.idle - recorded when a Turn ends or an input reservation stops being pending, or any - agent.session.failed, without sending later events. A creation that admitted nothing - closes after the snapshot; a settlement that records no event closes after events up to - the cursor read with a settled Session projection. Required actions keep it open; - disconnect does not cancel execution. The GET events stream remains live-only. New - Sessions retain their authenticated creator; all creation retries require the same typed - subject, including across key rotation. Saved-Agent retries and inline requests using - Vault attachments or credential references retain caller intent independently of later - resource changes; new hosted inline requests also freeze caller intent before deployment - defaults resolve; unrelated non-hosted inline retries preserve resolved/default - equivalences, and their resolved hash leaves out any deployment default. Provider keys - enter retry hashes only as fingerprints keyed by the credential key. Unknown historical - creators reject retries; known creators without recorded intent retain resolved-snapshot - retry rules. These conflict policies are local and not verified hosted parity. A same-key - stream=true retry of an existing creation returns 201 with no events and closes at once; - retry with stream=false or use the GET events stream to recover. Claude SDK on none and - Core-managed Docker openai_hosted supports qualified object-root json_schema output with - medium verbosity, single-Agent execution and ordinary functions. Hosted execution reuses - native workspace tools and Files/Artifacts; Skills, Plugins, capability directories, HTTP - MCP, Subagent and tool_search combinations remain unqualified, including inherited - template contents. Other non-text initial input remains unsupported. Basic Codex and - Claude SDK openai_hosted creation requires an explicitly configured managed provider. The - Claude workspace profile supports non-deferred function tools with text or successful - inline PNG/JPEG results alongside native workspace tools; HTTP MCP remains unsupported. - Idle Sessions provision automatically; initial provisioning has no caller connection - action. Network defaults to enabled; disabled and restricted policies reject before - compute allocation because the current Runtime cannot enforce them. The - x_agents_core.environment extension accepts common preparation fields for either hosted or - self-hosted placement: environment_template_id, files, env, packages, setup_commands, - skills, plugins and capability_directories. Duplicate fields in environment and the - extension reject. Confidential env, npm/Python packages and ordered setup commands use the - same Environment-owned initialization lifecycle; compute allocation does not own - preparation. Unknown side effects are not replayed after disconnect or restart. System - dependencies must be preinstalled in the sandbox image or template, or on the host - machine; packages.system is rejected. Initial inline and tenant-owned file_id files freeze - encrypted bytes before provisioning, then install through the common Core lifecycle before - native execution or live Files access. With a template reference, omitted/null files, env, - packages and setup_commands inherit. Non-null files and command lists replace; env - overlays by key; each package manager inherits on omission/null and otherwise replaces its - list. Empty lists clear their selected field. Tenant-owned environment_template_id - references inherit omitted/null network and allow only narrowing overrides. Inline hosted - network:null retains the enabled default; updating a Template with network:null resets its - saved policy to enabled. Core freezes effective configuration; template updates/deletion - do not alter Session snapshots or same-intent creation retries. Inline or tenant-owned - skill_reference Skills share initialization. Templates preserve default/latest/explicit - selectors; Session creation freezes concrete metadata and encrypted content atomically. - Skill, Plugin and capability-directory list omission/null inherit; a non-null list - replaces, including empty-list clearing. Omitted/null Skill version selectors resolve the - default version. Source deletion/default updates cannot change committed Session Skill - contents. Deferred function discovery uses type-only tool_search and per-function - defer_loading in the qualified single-agent Claude environment:none function profile, - including qualified inline image messages and text results. Explicit web_search mode - disabled and programmatic_tool_calling enabled false use frozen common Runtime controls. - Enabled forms, including those saved on an Agent, remain unqualified and reject before any - write unless the Session replaces tools. Omitted programmatic configuration preserves - native behavior, a documented difference from the official default-on behavior. Other - combinations remain unqualified; see the operation coverage. + user-message array. Codex and Claude SDK on none and qualified managed or self_hosted + workspace profiles also accept inline PNG/JPEG image content; other image combinations and + remote URLs are unsupported. None initial input atomically starts a Turn; self_hosted + initial input is reserved while returning its Environment connection target, with + execution deferred to native readiness and Session failure on initial timeout. Initial + input is required for none and for streamed creation outside self_hosted. Omitted/null + input remains valid for non-streaming hosted and self_hosted creation. With stream=true, + returns live Session events starting with the committed creation snapshot and closes right + after the first agent.session.idle recorded when a Turn ends or an input reservation stops + being pending, or any agent.session.failed, without sending later events. A creation that + admitted nothing closes after the snapshot; a settlement that records no event closes + after events up to the cursor read with a settled Session projection. Required actions + keep it open; disconnect does not cancel execution. The GET events stream remains + live-only. New Sessions retain their authenticated creator; all creation retries require + the same typed subject, including across key rotation. Saved-Agent retries and inline + requests using Vault attachments or credential references retain caller intent + independently of later resource changes; new hosted inline requests also freeze caller + intent before deployment defaults resolve; unrelated non-hosted inline retries preserve + resolved/default equivalences, and their resolved hash leaves out any deployment default. + Provider keys enter retry hashes only as fingerprints keyed by the credential key. Unknown + historical creators reject retries; known creators without recorded intent retain + resolved-snapshot retry rules. These conflict policies are local and not verified hosted + parity. A same-key stream=true retry of an existing creation returns 201 with no events + and closes at once; retry with stream=false or use the GET events stream to recover. + Claude SDK on none, Core-managed Docker openai_hosted and self_hosted supports qualified + object-root json_schema output with medium verbosity, single-Agent execution and ordinary + functions. Hosted execution reuses native workspace tools and Files/Artifacts; Skills, + Plugins, capability directories, HTTP MCP, Subagent and tool_search combinations remain + unqualified, including inherited template contents. Other non-text initial input remains + unsupported. Basic Codex and Claude SDK openai_hosted creation requires an explicitly + configured managed provider. The Claude workspace profile supports non-deferred function + tools with text or successful inline PNG/JPEG results alongside native workspace tools; + HTTP MCP remains unsupported. Idle Sessions provision automatically; initial provisioning + has no caller connection action. Network defaults to enabled; disabled and restricted + policies reject before compute allocation because the current Runtime cannot enforce them. + The x_agents_core.environment extension accepts common preparation fields for either + hosted or self-hosted placement: environment_template_id, files, env, packages, + setup_commands, skills, plugins and capability_directories. Duplicate fields in + environment and the extension reject. Confidential env, npm/Python packages and ordered + setup commands use the same Environment-owned initialization lifecycle; compute allocation + does not own preparation. Unknown side effects are not replayed after disconnect or + restart. System dependencies must be preinstalled in the sandbox image or template, or on + the host machine; packages.system is rejected. Initial inline and tenant-owned file_id + files freeze encrypted bytes before provisioning, then install through the common Core + lifecycle before native execution or live Files access. With a template reference, + omitted/null files, env, packages and setup_commands inherit. Non-null files and command + lists replace; env overlays by key; each package manager inherits on omission/null and + otherwise replaces its list. Empty lists clear their selected field. Tenant-owned + environment_template_id references inherit omitted/null network and allow only narrowing + overrides. Inline hosted network:null retains the enabled default; updating a Template + with network:null resets its saved policy to enabled. Core freezes effective + configuration; template updates/deletion do not alter Session snapshots or same-intent + creation retries. Inline or tenant-owned skill_reference Skills share initialization. + Templates preserve default/latest/explicit selectors; Session creation freezes concrete + metadata and encrypted content atomically. Skill, Plugin and capability-directory list + omission/null inherit; a non-null list replaces, including empty-list clearing. + Omitted/null Skill version selectors resolve the default version. Source deletion/default + updates cannot change committed Session Skill contents. Deferred function discovery uses + type-only tool_search and per-function defer_loading in the qualified single-agent Claude + function profile on none or a managed/user-owned workspace, including qualified inline + image messages and text results. Explicit web_search mode disabled and + programmatic_tool_calling enabled false use frozen common Runtime controls. Enabled forms, + including those saved on an Agent, remain unqualified and reject before any write unless + the Session replaces tools. Omitted programmatic configuration preserves native behavior, + a documented difference from the official default-on behavior. Other combinations remain + unqualified; see the operation coverage. --- {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} @@ -150,7 +151,7 @@ An attached Vault with no matching credential may remain anonymous; missing keys The inline agent uses the Agent create configuration validation with agent.-prefixed params, reported before the input requirement and saved-Agent lookup; saved configurations with conflicting tools or schema roots reject admission with the same errors, and execution limits keep unsupported_or_invalid_configuration. Hosted network policy rejections return invalid_request_error with a null param. Initial input accepts a string or ordered user-message array. -Codex and Claude SDK on none and qualified openai_hosted also accept inline PNG/JPEG image content; other image combinations and remote URLs are unsupported. None initial input atomically starts a Turn; self_hosted initial input is reserved while returning its Environment connection target, with execution deferred to native readiness and Session failure on initial timeout. Initial input is required for none and for streamed creation outside self_hosted. +Codex and Claude SDK on none and qualified managed or self_hosted workspace profiles also accept inline PNG/JPEG image content; other image combinations and remote URLs are unsupported. None initial input atomically starts a Turn; self_hosted initial input is reserved while returning its Environment connection target, with execution deferred to native readiness and Session failure on initial timeout. Initial input is required for none and for streamed creation outside self_hosted. Omitted/null input remains valid for non-streaming hosted and self_hosted creation. With stream=true, returns live Session events starting with the committed creation snapshot and closes right after the first agent.session.idle recorded when a Turn ends or an input reservation stops being pending, or any agent.session.failed, without sending later events. A creation that admitted nothing closes after the snapshot; a settlement that records no event closes after events up to the cursor read with a settled Session projection. @@ -158,7 +159,7 @@ Required actions keep it open; disconnect does not cancel execution. The GET eve Saved-Agent retries and inline requests using Vault attachments or credential references retain caller intent independently of later resource changes; new hosted inline requests also freeze caller intent before deployment defaults resolve; unrelated non-hosted inline retries preserve resolved/default equivalences, and their resolved hash leaves out any deployment default. Provider keys enter retry hashes only as fingerprints keyed by the credential key. Unknown historical creators reject retries; known creators without recorded intent retain resolved-snapshot retry rules. -These conflict policies are local and not verified hosted parity. A same-key stream=true retry of an existing creation returns 201 with no events and closes at once; retry with stream=false or use the GET events stream to recover. Claude SDK on none and Core-managed Docker openai_hosted supports qualified object-root json_schema output with medium verbosity, single-Agent execution and ordinary functions. +These conflict policies are local and not verified hosted parity. A same-key stream=true retry of an existing creation returns 201 with no events and closes at once; retry with stream=false or use the GET events stream to recover. Claude SDK on none, Core-managed Docker openai_hosted and self_hosted supports qualified object-root json_schema output with medium verbosity, single-Agent execution and ordinary functions. Hosted execution reuses native workspace tools and Files/Artifacts; Skills, Plugins, capability directories, HTTP MCP, Subagent and tool_search combinations remain unqualified, including inherited template contents. Other non-text initial input remains unsupported. Basic Codex and Claude SDK openai_hosted creation requires an explicitly configured managed provider. @@ -174,7 +175,7 @@ Tenant-owned environment_template_id references inherit omitted/null network and Inline or tenant-owned skill_reference Skills share initialization. Templates preserve default/latest/explicit selectors; Session creation freezes concrete metadata and encrypted content atomically. Skill, Plugin and capability-directory list omission/null inherit; a non-null list replaces, including empty-list clearing. -Omitted/null Skill version selectors resolve the default version. Source deletion/default updates cannot change committed Session Skill contents. Deferred function discovery uses type-only tool_search and per-function defer_loading in the qualified single-agent Claude environment:none function profile, including qualified inline image messages and text results. +Omitted/null Skill version selectors resolve the default version. Source deletion/default updates cannot change committed Session Skill contents. Deferred function discovery uses type-only tool_search and per-function defer_loading in the qualified single-agent Claude function profile on none or a managed/user-owned workspace, including qualified inline image messages and text results. Explicit web_search mode disabled and programmatic_tool_calling enabled false use frozen common Runtime controls. Enabled forms, including those saved on an Agent, remain unqualified and reject before any write unless the Session replaces tools. Omitted programmatic configuration preserves native behavior, a documented difference from the official default-on behavior. diff --git a/apps/docs/content/docs/api-reference/sessions/submit-session-input-events.mdx b/apps/docs/content/docs/api-reference/sessions/submit-session-input-events.mdx index dc44ebc63..c9d942063 100644 --- a/apps/docs/content/docs/api-reference/sessions/submit-session-input-events.mdx +++ b/apps/docs/content/docs/api-reference/sessions/submit-session-input-events.mdx @@ -15,8 +15,8 @@ _openapi: An empty events array is a resource-authorized no-op; it creates no execution retry identity, Turn, Item or input receipt. For environment none, atomically accepts text messages, cancellation and function results. Messages steer active work or start a queued - Turn. The supported self_hosted profile accepts text-only messages; qualified Codex and - Claude SDK openai_hosted profiles also accept inline PNG/JPEG. Under the Session lock, + Turn. Qualified Codex and Claude SDK workspace profiles accept text and inline PNG/JPEG + messages, independently of managed or self_hosted ownership. Under the Session lock, matching retries retain their original target; new active messages append to the current Turn, while idle messages reserve work and wait up to the original five-minute connection/admission deadline. Return 202 only after durable admission, without claiming @@ -41,13 +41,13 @@ _openapi: Disconnecting the waiting HTTP request does not cancel retained work or restart its deadline. Retry keys identify the whole ordered batch. Function output accepts text or ordered text/image parts subject to engine support; Claude SDK accepts text results and, - on none and qualified openai_hosted, successful inline PNG/JPEG results, preserving + on none and qualified workspace profiles, successful inline PNG/JPEG results, preserving ordered content; error images and remote references reject before admission. Native image resizing may change bytes. Runtime image-result support is checked only for image-bearing - delivery. Codex and Claude SDK on none and qualified openai_hosted accept ordered inline - PNG/JPEG image messages. Self-hosted profiles and other engines remain text-only; remote - image URLs are unsupported. Image references are retained unchanged without service-side - downloads. + delivery. Codex and Claude SDK on none and qualified managed or self_hosted workspace + profiles accept ordered inline PNG/JPEG image messages. Other engines remain text-only; + remote image URLs are unsupported. Image references are retained unchanged without + service-side downloads. --- {/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */} @@ -55,7 +55,7 @@ _openapi:

Full description -For environment none, atomically accepts text messages, cancellation and function results. Messages steer active work or start a queued Turn. The supported self_hosted profile accepts text-only messages; qualified Codex and Claude SDK openai_hosted profiles also accept inline PNG/JPEG. +For environment none, atomically accepts text messages, cancellation and function results. Messages steer active work or start a queued Turn. Qualified Codex and Claude SDK workspace profiles accept text and inline PNG/JPEG messages, independently of managed or self_hosted ownership. Under the Session lock, matching retries retain their original target; new active messages append to the current Turn, while idle messages reserve work and wait up to the original five-minute connection/admission deadline. Return 202 only after durable admission, without claiming native application; active messages create no Turn or reservation. Cancellation-only prepared-environment batches use existing durable cancellation admission and return 202 without waiting for native exit; a new cancellation conflicts while a pre-Turn reservation is pending. @@ -65,9 +65,9 @@ New input on a Session whose hosted Environment failed to provision returns the Losing execution ownership returns 503. The response write deadline accommodates the admission window for either prepared Environment, independently of new-hosted-admission and executor URL settings. Disconnecting the waiting HTTP request does not cancel retained work or restart its deadline. -Retry keys identify the whole ordered batch. Function output accepts text or ordered text/image parts subject to engine support; Claude SDK accepts text results and, on none and qualified openai_hosted, successful inline PNG/JPEG results, preserving ordered content; error images and remote references reject before admission. Native image resizing may change bytes. +Retry keys identify the whole ordered batch. Function output accepts text or ordered text/image parts subject to engine support; Claude SDK accepts text results and, on none and qualified workspace profiles, successful inline PNG/JPEG results, preserving ordered content; error images and remote references reject before admission. Native image resizing may change bytes. -Runtime image-result support is checked only for image-bearing delivery. Codex and Claude SDK on none and qualified openai_hosted accept ordered inline PNG/JPEG image messages. Self-hosted profiles and other engines remain text-only; remote image URLs are unsupported. +Runtime image-result support is checked only for image-bearing delivery. Codex and Claude SDK on none and qualified managed or self_hosted workspace profiles accept ordered inline PNG/JPEG image messages. Other engines remain text-only; remote image URLs are unsupported. Image references are retained unchanged without service-side downloads. diff --git a/apps/docs/content/guide-sources.json b/apps/docs/content/guide-sources.json index 2872544e3..3404f0613 100644 --- a/apps/docs/content/guide-sources.json +++ b/apps/docs/content/guide-sources.json @@ -14,10 +14,10 @@ "docs/getting-started/quickstart.md": "b989682ac2e58d59a794118fd371b37d1ea64c957d3512ff53739458a95d0f9a", "docs/api/README.md": "878a540c3876f703d5e1ded36a2cee7ca462f80b27627897135ac981246fe9f3", "docs/api/request-conventions.md": "3e5e96350ab6fcf24457ece52fb9a582479ddb157cebbf34cc1cf13a22b09ba8", - "contracts/agents-api/execution-tools.md": "e0b61f6c0c236c362186c5f6d0ad69a16dd8a8d9afabe1329a1fe22e5f4a71e9", + "contracts/agents-api/execution-tools.md": "8cc0dbe207e8e80ac104bf482c37ea297cd64250b51d288ed4baf553756424d2", "docs/api/public-agent-api.md": "00979732412a971013e8f01b4c74820ff51aafdded6b0f105d25a78af86a6627", "docs/examples.md": "0e1bdaeff51c9c36779f817be31ea9816b7d8cb2290cf8350d3c4801f436f4f9", - "contracts/agents-api/environments.md": "d5fc16c904f751bd13e2af35c9e43c92ca39c6b86401f85cf7f9ee4093c156c9", + "contracts/agents-api/environments.md": "424dac4bfd63418afc314896dd6a3e4c5c4375dd0a8bb7579920c5dd9743da22", "docs/getting-started/nodes.md": "c1ad18c445990ea696625011cc3cfa0725779beefd379064d278656801d5578e", "docs/getting-started/self-hosted.md": "5ade597e09cbfa2e321f341693b47730b3696fe7bd4d6834eafbe6b279a55e6b", "docs/self-hosted-native.md": "b3cf736f88792e6925c50b81a4c33eba6b9ee86e195f9ed4e2187db7bed71d88", @@ -30,9 +30,9 @@ "docs/user-guide.md": "190bea5bfe23b71db3d9437065ee270e07226a89a6e98c668853e5c7f7555529", "docs/assets/development-architecture.png": "24e6d0145d4f16ad70b07b6bc643808a6455aaf6398434d199cf74def200fca6", "docs/development.md": "f5c340253036a2cabc43e22aecdf70522d90280d6511e7649278ae93712ab8b6", - "contracts/agents-api/harness-onboarding.md": "234906652d381f4920d2245a795ad7f12f2f66577018db4dd5d545697d4f111b", + "contracts/agents-api/harness-onboarding.md": "874a80dc1ffc5e97b2783bea3f6b217893f997b38bb8180a29f09c6dbf75e622", "docs/runtime-bootstrap.md": "0d49aed73b298039e04453e6f465b0e925fb2227fa35d4206820bb3acbd8df39", - "docs/runtime-protocol.md": "79f6bf1597eb0c82b41074fd21a6617225ffb7d11572c156e1d56c4e8741f322", + "docs/runtime-protocol.md": "e8aa4cf862b5f63a4138cfeb25196a6bdb5c40a2e389e828b464585415dc6c45", "docs/sandbox-provider.md": "4d47b234a457f874f3ff7e61a7f5da6fc8b75b0c6df0ce0ce9ead1c07afdfb3e", "apps/docs/scripts/guides.json": "05fa34e2bdddfabb2bb1c6f620323e672e9261e358d04784b8c8331f2c315d9f" }, @@ -50,10 +50,10 @@ "content/docs/quickstart.mdx": "d0ab9537ab68f6dd3109353e937a29c5d58ec3894b56a52873c9a1d79dfa60a6", "content/docs/public-api.mdx": "d5a218219d79f3875a02702257e361b866a5137393b2b8f39aca4be4763be87d", "content/docs/request-conventions.mdx": "c47b1c5a0785ec786e3d5619218a04a6841538ceefee891ce6e18d2c61a09858", - "content/docs/agents-and-tools.mdx": "b8a85fe92e19a71b7ad7c9357ce7ad0595d50c9190edb748ca834df615b056cb", + "content/docs/agents-and-tools.mdx": "44dfde4e3b3906b30323c2e75a89650ae4837210c7ba425be2266edf87ce8ff8", "content/docs/sessions.mdx": "bb63d799ed90038836d652f3f866d0309822425114c6b2aa36654b8a991947f6", "content/docs/examples.mdx": "587061e65ab2e841d14980539ba94e2216d4e8135c948a852b9a8bb0359c85d7", - "content/docs/environments-and-files.mdx": "352ca1f2b0ab1b0853b890be694629bb47399ba6bc88905f68feaa3bfe401949", + "content/docs/environments-and-files.mdx": "6d8b2a5d5e95e3a5eff47ce93f0239c7cc38d4678bac53c58f5c8df016c23dc5", "content/docs/hosted-providers.mdx": "85696d88b76f1233db3d8db3266bb0ab4d297d795a44ede13cf34e5169524c68", "content/docs/self-hosted-execution.mdx": "eeed4c6b3646927ccc3c7ac2d20b2c0f9c8a65e42d734310fe3959e016324e57", "content/docs/self-hosted-native.mdx": "671451580dfb4f5c134221991f68292a4f992008174d23190b1da3742046571f", @@ -66,9 +66,9 @@ "content/docs/user-guide.mdx": "7c099b2d787ce3d7876889c7cefd621840ec083f267eadf278214a83f11ba274", "public/images/source/docs/assets/development-architecture.png": "24e6d0145d4f16ad70b07b6bc643808a6455aaf6398434d199cf74def200fca6", "content/docs/development.mdx": "3a53e2a8d4c91897e160ce01f07f1609fa101b254bdfa1b0e53ac21f108db342", - "content/docs/harness-onboarding.mdx": "d9c9dcbd339ba9b278b133816c1d905bdbd849f44e2ff27882090cd39002e1c8", + "content/docs/harness-onboarding.mdx": "17626e9f6256ddfffc95fd81dfa8d9c712d9ff16792ea5ef54bfe8c3ce1a2a9f", "content/docs/runtime-bootstrap.mdx": "58982955811c9ad46a9fc04d8d2aef5a762fc9d25d5833f88aa75ee3fc46523f", - "content/docs/runtime-protocol.mdx": "fed94a899e953c486d8560a21a2eb15a8c41c173d020e21b57cd207c08c272b7", + "content/docs/runtime-protocol.mdx": "d6b818edf2a0e0c4f2d3878f75805043c6dba3b09c6563f80faa4cecd05d40c7", "content/docs/sandbox-provider.mdx": "9db833fe9ff3f30a65451f80d7251348695a08e7830f9e95871739a710529818" } } diff --git a/apps/docs/openapi/sources.json b/apps/docs/openapi/sources.json index 89ecf1684..8fd11fd76 100644 --- a/apps/docs/openapi/sources.json +++ b/apps/docs/openapi/sources.json @@ -1,6 +1,6 @@ { "sources": { - "contracts/agents-api/openapi.yaml": "8051d41d848957b487cc5f2b470a6ec3789110b5ced4ae90f7fbf96ac69ffb6f", + "contracts/agents-api/openapi.yaml": "949acc918b75ceaf9daa102f69e039a42a090eca55b1e521988400d432b2c0d3", "contracts/agents-api/core.openapi.yaml": "2a351d8e305097853e5404484a8c0b8e9545eb17d72b42da72025273d5941637", "contracts/agents-api/runtime.openapi.yaml": "d86fa523c6444b7292c06290800cee35dbc723d84dad5740c1d92776fb4165bc" }, @@ -19,7 +19,7 @@ "content/docs/api-reference/environment-templates/update-an-environment-template.mdx": "4b1ea639682fdce2bce063cea68cf2928fff646d59235a5d4e17c657193fa7d9", "content/docs/api-reference/environment-templates/delete-an-environment-template.mdx": "c6f10446d1ca50e0a490c0296aca5d01f39c8ce96423732a271f729575dc278c", "content/docs/api-reference/sessions/list-execution-sessions.mdx": "fbd004c1385d827feb7c4d9398c3b91297b10c42588186b6e7125b5a38e09b0b", - "content/docs/api-reference/sessions/create-an-execution-session.mdx": "af343c0296b6cc47d1a3f220a63b8b1423afc1c6fd68684d6e71f66ee9e408bb", + "content/docs/api-reference/sessions/create-an-execution-session.mdx": "472beea09aa889ecf66701dd97b9c39be4726f4dc7a7ab471658b5c5e3036910", "content/docs/api-reference/sessions/retrieve-an-execution-session.mdx": "538ec687302c904eb47f6fc00f760a5f6964782d835ab4262ebc531b27c75161", "content/docs/api-reference/sessions/update-execution-session-metadata.mdx": "f3ad7c0fa0bdb9c6e2afb9382aaa0370fd523a7363904416d12ecebf1e3c8e86", "content/docs/api-reference/sessions/delete-an-execution-session.mdx": "51afc3a526d6f457df3690119e6771dafcf420850a067ba9a420c712bef85aa3", @@ -28,7 +28,7 @@ "content/docs/api-reference/artifacts/delete-a-published-artifact.mdx": "7f45066a7d4ca2db500625a22f14116bd1ef8a77fb15fbecf51a45ce4b6dcee8", "content/docs/api-reference/artifacts/download-immutable-artifact-bytes.mdx": "e5f842289d785399eb2e6b43a3740f34a170cd771574e2eadc02bde57a0607b7", "content/docs/api-reference/events/stream-live-session-events.mdx": "dfb350eda50b6349a15394359de6f95e534d43b2f521da070836d0fae23ed013", - "content/docs/api-reference/sessions/submit-session-input-events.mdx": "5005034faa3d33d5133a4081c13827d33981f82af2313650639fdbdb2b089413", + "content/docs/api-reference/sessions/submit-session-input-events.mdx": "e517a517e06778a55058347952c593fee7a1e2dd4fd1f75078b03e79a3a3da41", "content/docs/api-reference/items/list-persisted-execution-items.mdx": "a94e0c89918ec26d5964e731abf06f9ed7ad58168757df5660975855e63f8ec0", "content/docs/api-reference/subagents/list-session-subagents.mdx": "bed7a780c8b4e75f2cb32b56fb95d502c4ba02ad8646dc4748c0f1bd5fb4943f", "content/docs/api-reference/subagents/retrieve-a-session-subagent.mdx": "a203ebd474073bb78b249a52a4cf9c3359725e4a6b8580db41f488fd0daec7d0", @@ -91,7 +91,7 @@ "content/docs/api-reference/credentials/meta.json": "5e3368b7f365590f31c245fb326fe25c8d3ab82ee4e79e03df10ea016e7b3da3", "content/docs/api-reference/meta.json": "d8d58d48c955a9b161d880805bc3634617566fe3f1780ee170878358412cafe4", "content/docs/api-reference/index.mdx": "b32be3060e86fefc5f6b32a67353a2621ea2e7cfd88a69fa19caf67e6ab28d00", - "openapi/public-api.yaml": "3f034ebe892b200f06fb44cb265c244456527fe04811d2c3e1a0e2bf14b7d0f8", + "openapi/public-api.yaml": "2715e821e8c35a9580751b00c72fd5dbf7a8d4adc1332ee2be2bccab593b5842", "content/docs/api-reference/core/core-administration/query-committed-administrator-mutations.mdx": "bab0589c4dd5944b24594eb2cab6e2266075ce77b7e224cf57a63b9c8e0c89af", "content/docs/api-reference/core/deployment-model-providers/list-harnesses-and-their-deployment-default-model-providers.mdx": "05a4ef8d4d41c97221a805a4184242b32bd25754223984f36552cf44ec0a7332", "content/docs/api-reference/core/deployment-model-providers/retrieve-a-harness-s-deployment-default-model-provider.mdx": "7a4aeeb7603fd1328b3145dada0a0778cf9929f91b25938399c465de916b87d6", From fbcaa675169e530c127ed17bb5c0d7a5e2f2951d Mon Sep 17 00:00:00 2001 From: Yao Date: Wed, 30 Sep 2026 12:42:00 +0800 Subject: [PATCH 13/14] docs: serve the architecture guide at /architecture The guide's URL named the old page rather than the document it now renders, so the slug, the sidebar entry, the browser check and the generated-copy allowlist follow the new name. --- .../content/docs/{execution-model.mdx => architecture.mdx} | 0 apps/docs/content/docs/index.mdx | 2 +- apps/docs/content/docs/meta.json | 2 +- apps/docs/content/guide-sources.json | 6 +++--- apps/docs/scripts/check-browser.mjs | 4 ++-- apps/docs/scripts/guides.json | 2 +- scripts/name-allowlist.json | 4 ++-- 7 files changed, 10 insertions(+), 10 deletions(-) rename apps/docs/content/docs/{execution-model.mdx => architecture.mdx} (100%) diff --git a/apps/docs/content/docs/execution-model.mdx b/apps/docs/content/docs/architecture.mdx similarity index 100% rename from apps/docs/content/docs/execution-model.mdx rename to apps/docs/content/docs/architecture.mdx diff --git a/apps/docs/content/docs/index.mdx b/apps/docs/content/docs/index.mdx index 48195accc..538fc286a 100644 --- a/apps/docs/content/docs/index.mdx +++ b/apps/docs/content/docs/index.mdx @@ -5,7 +5,7 @@ description: "Install Core and Web, create a Project API key, and add execution OpenAgentCore runs AI agents on your own infrastructure behind the OpenAI Agents API. Pick the path that matches your role. New here? Read the -[architecture overview](/execution-model) first. +[architecture overview](/architecture) first. ## Operators: install and run diff --git a/apps/docs/content/docs/meta.json b/apps/docs/content/docs/meta.json index f2ccee3a0..9a05f29dd 100644 --- a/apps/docs/content/docs/meta.json +++ b/apps/docs/content/docs/meta.json @@ -4,7 +4,7 @@ "---Start here---", "index", "concepts", - "execution-model", + "architecture", "install", "install-options", "configure", diff --git a/apps/docs/content/guide-sources.json b/apps/docs/content/guide-sources.json index 3404f0613..8bfe65b3e 100644 --- a/apps/docs/content/guide-sources.json +++ b/apps/docs/content/guide-sources.json @@ -34,15 +34,15 @@ "docs/runtime-bootstrap.md": "0d49aed73b298039e04453e6f465b0e925fb2227fa35d4206820bb3acbd8df39", "docs/runtime-protocol.md": "e8aa4cf862b5f63a4138cfeb25196a6bdb5c40a2e389e828b464585415dc6c45", "docs/sandbox-provider.md": "4d47b234a457f874f3ff7e61a7f5da6fc8b75b0c6df0ce0ce9ead1c07afdfb3e", - "apps/docs/scripts/guides.json": "05fa34e2bdddfabb2bb1c6f620323e672e9261e358d04784b8c8331f2c315d9f" + "apps/docs/scripts/guides.json": "d85716ba38429a9f469b1bc1e972f33ed836e277f17636415fbfbb7d8b8a6ce5" }, "outputs": { - "content/docs/index.mdx": "ac36f1536e558acd741cdf4986519a5d6098088aa5bc07d3f8a0ccbef3799e75", + "content/docs/index.mdx": "5b31a67f14bd01c38321934e4d5ac941de190cb7a61c154feb218f3b0b201b1f", "content/docs/concepts.mdx": "88ba65e1ba902921d6cd5da2866620a6dbef52c041db991312a138884fb43a4e", "public/images/source/docs/assets/architecture-overview.png": "c6103e2a8730796a15d6c4ae7165f3b9e60dbd09075b459d34821a3ee0d2d49f", "public/images/source/docs/assets/architecture-api-surfaces.png": "37c0d0d4f42c37ec41f8d4931ef10f182287d94d0928da195bf8b9e377c942e5", "public/images/source/docs/assets/architecture-session-flow.png": "0f0a78c43d3dfd235f3994421708c65347863665278bd39e79d19b52e13fab7a", - "content/docs/execution-model.mdx": "2c06f4fce7bafdae0e0c2acbc587ab3ece38e473019cef6222f7168fe2429c30", + "content/docs/architecture.mdx": "2c06f4fce7bafdae0e0c2acbc587ab3ece38e473019cef6222f7168fe2429c30", "content/docs/install.mdx": "6c3ec01d1b80cbce35d58e3f141b0fa832d6294a2ecc07c3b286ecc56ba66919", "content/docs/install-options.mdx": "aaafc209293a905d5b433511149aa1f0cc422bd31d5bb5b6cd7eec0d532ab8eb", "content/docs/configure.mdx": "02d1eee789646fdf65ed2ec48b6fe954c81107d6ff5891536ec6ac2df0a8c4dc", diff --git a/apps/docs/scripts/check-browser.mjs b/apps/docs/scripts/check-browser.mjs index 0dbda2254..5de2d9fff 100644 --- a/apps/docs/scripts/check-browser.mjs +++ b/apps/docs/scripts/check-browser.mjs @@ -28,7 +28,7 @@ try { '/api-reference/core/sandbox-manager/retrieve-sandbox-deployment': 'Authorization', '/api-reference/machine/sandbox-node/enroll-a-sandbox-node': 'Authorization', } - for (const route of ['/', '/install', '/configure', '/console', '/execution-model', ...Object.keys(credentials), '/harness-onboarding']) { + for (const route of ['/', '/install', '/configure', '/console', '/architecture', ...Object.keys(credentials), '/harness-onboarding']) { const response = await page.goto(origin + route, { waitUntil: 'networkidle' }) assert.equal(response.status(), 200, route) assert.ok(await page.locator('h1').count(), 'Missing page title: ' + route) @@ -38,7 +38,7 @@ try { assert.equal(await page.locator('input, form, textarea').count(), 0, 'Reference exposes request controls: ' + route) assert.ok((await page.locator('body').innerText()).includes(credentials[route]), 'Missing credential documentation: ' + route) } - if (screenshots && ['/', '/console', '/execution-model', '/api-reference/core/sandbox-manager', '/harness-onboarding'].includes(route)) { + if (screenshots && ['/', '/console', '/architecture', '/api-reference/core/sandbox-manager', '/harness-onboarding'].includes(route)) { await page.screenshot({ path: path.join(screenshots, (route.replaceAll('/', '-') || 'home') + '.png'), fullPage: false }) } } diff --git a/apps/docs/scripts/guides.json b/apps/docs/scripts/guides.json index 2bd23b59a..991dd1562 100644 --- a/apps/docs/scripts/guides.json +++ b/apps/docs/scripts/guides.json @@ -12,7 +12,7 @@ "description": "Projects, credentials and the boundary between applications, administration and execution." }, { - "slug": "execution-model", + "slug": "architecture", "source": "docs/architecture.md", "title": "Architecture", "description": "Core, the Runtime daemon and the native harness: the three namespaces, replaceable parts and a Session end to end." diff --git a/scripts/name-allowlist.json b/scripts/name-allowlist.json index afe14e326..abd4cc930 100644 --- a/scripts/name-allowlist.json +++ b/scripts/name-allowlist.json @@ -765,9 +765,9 @@ "reason": "Generated copy of docs/design-principles.md: These exact phrases refer to the separate Parsar product, its ownership or historical source, not the OpenAgentCore brand." }, { - "path": "apps/docs/content/docs/execution-model.mdx", + "path": "apps/docs/content/docs/architecture.mdx", "regex": "including Parsar", - "reason": "Generated copy of docs/web/architecture.md: These exact phrases refer to the separate Parsar product, its ownership or historical source, not the OpenAgentCore brand." + "reason": "Generated copy of docs/architecture.md: These exact phrases refer to the separate Parsar product, its ownership or historical source, not the OpenAgentCore brand." }, { "path": "apps/docs/content/docs/install.mdx", From 448a2d2730b53e2916eefa4d0b048a344e615e9f Mon Sep 17 00:00:00 2001 From: Yao Date: Wed, 30 Sep 2026 12:42:00 +0800 Subject: [PATCH 14/14] docs: drop the unused architecture diagram asset Nothing renders this file: the guide it was added for now embeds the repository diagrams next to their source. --- apps/docs/public/images/architecture.svg | 10 ---------- 1 file changed, 10 deletions(-) delete mode 100644 apps/docs/public/images/architecture.svg diff --git a/apps/docs/public/images/architecture.svg b/apps/docs/public/images/architecture.svg deleted file mode 100644 index 9f8abb1de..000000000 --- a/apps/docs/public/images/architecture.svg +++ /dev/null @@ -1,10 +0,0 @@ - -OpenAgentCore API and execution boundariesApplications call Core with Project API keys. Administrator browsers sign into Web; Web holds the Core key. Nodes and Runtime daemons connect directly to Core using scoped machine credentials. Core owns execution and its PostgreSQL state. - - - -Application / SDKAdministrator browserWeb serverCoreExecution ownerPostgreSQLNode / Runtime / native harness - -/v1 · Project API keySession/core/v1Core key/api/v1Scoped machine credentials -Application API and administration API are separate. Machine connections never pass through Web. -