diff --git a/AGENTS.md b/AGENTS.md index a4f48b8e9..e6b9f919d 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -13,7 +13,7 @@ no credential works in another namespace. | --- | --- | --- | --- | | `/v1` | Applications | Project API key | Exactly the pinned OpenAI Agents API route set ([upstream.json](contracts/agents-api/upstream.json): SDK 3.13.0, `agents=v1`). Fields the official types lack live only in `x_agents_core` on Agents and Sessions (`harness`, `model_provider`). Nothing about deployment belongs here. | | `/core/v1` | Core Web's server and operator scripts | Core key; Core stores its digest | Everything about operating the deployment: Projects and keys, resource reads and deletion, Session archive, credential issuance (node enrollment tokens, executor credentials), observability, audit, sandbox deployment and nodes. | -| `/api/v1` | Nodes, Runtime daemons, self-hosted executors | Machine credentials issued through `/core/v1` | Machine connections only; each credential works only on its own routes. | +| `/api/v1` | Nodes, Runtime daemons, self-hosted executors | Machine credentials: enrollment tokens and executor credentials issued through `/core/v1`; nodes register their own credential with an enrollment token; Core writes daemon credentials into hosted sandboxes | Machine connections only; each credential works only on its own routes. | - Core Web calls only `/core/v1`, through the Core clients in `packages/agents-client` (`AdminClient`, `SandboxAdminClient`, diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index bda81a2e5..92ea32f82 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -51,11 +51,10 @@ Keep administrator target scope separate from caller principals. See Administrator writes and their audit record share one PostgreSQL transaction. Reuse existing resource deletion and serialization code. Cross-Project copying was -removed. `admin_resource_owners` alone feeds the historical `source:"admin_copy"` -provenance read; `admin_asset_copies` is retained only because tables are not -dropped. Unknown historical provenance remains unknown. No secrets or request -bodies enter logs. The console's fixed actor label (`console`) is only an audit -display label, never an authorization input. +removed; only the historical `source:"admin_copy"` provenance read remains, fed by +`admin_resource_owners`. Unknown historical provenance remains unknown. No secrets +or request bodies enter logs. The console's fixed actor label (`console`) is only +an audit display label, never an authorization input. When requirements conflict, object ownership is unclear, or a design would need parallel compatibility paths, raise the issue with a concrete recommendation and @@ -193,9 +192,9 @@ coverage ledgers and official SDK/raw HTTP tests when changing API behavior. Run `make openapi` after handler annotation changes. It reuses the original Core-only swaggo v1.16.4 generator, then splits the result by namespace: `/v1` into `openapi.yaml`, `/core/v1` into `core.openapi.yaml` and `/api/v1` into -`runtime.openapi.yaml` (the last two with base path `/`), each keeping only the -security schemes its operations use. All generated schemas remain free of product -routes. +`runtime.openapi.yaml`; the last two use base path `/`, and each document keeps +only the security schemes its operations use. All generated schemas remain free +of product routes. Core changes must retain the independent build and official-client workflow. Native adapter changes require their applicable build/check targets and live provider @@ -780,9 +779,9 @@ A locally unavailable provider dependency keeps hosted admission closed while th existing scan waits for repair; administrator recovery remains available, including on restart. Database and ownership errors remain failures. Unconfigured hosted admission creates no Session state. Derive Runtime bootstrap and daemon WebSocket -addresses from the saved validated origin, never inbound Host headers. Use the live -deployment API for selections made after startup; the startup configuration API -remains a startup snapshot. +addresses from the saved validated origin, never inbound Host headers. Read the +current selection from the live deployment API; there is no startup configuration +read. Provider, resources and Runtime changes require maintenance, the current generation and verified zero retained or pending resources. The Core origin remains unchanged @@ -1861,9 +1860,9 @@ Nodes and Core come from one distribution; older nodes using the removed `/core/v1/sandbox` node paths cannot connect and are replaced through the drained upgrade and re-enrollment workflow. -The Web manager offers no manual Core key entry outside sign-in. A console without -paired management configuration shows setup guidance; direct remote project API -connections do not silently administer the console's configured deployment. +The Web manager offers no manual Core key entry outside sign-in, and Web refuses +to start without its Core key file. It holds no Project API key and never calls +`/v1`. Chinese/English sandbox text, status and diagnostic formatting live in the shared `apps/web/src/lib/` locale modules. A persisted explicit language preference wins before the first browser language; unrelated product surfaces are outside this @@ -2237,9 +2236,9 @@ replaced; do not carry obsolete compatibility code forward to satisfy this secti written with provenance in the same creation transaction as Session resources. Read no credential ciphertext and never recompute sources from current Agents or operator defaults. Model/harness sources are independent; provider bundles - retain one source. Project reads redact all deployment provider details. Old - Sessions expose persisted model/harness with unknown sources and unavailable - provider metadata, without backfill. Projection metadata does not alter retry + retain one source. The read is Core-key only, under `/core/v1`; `/v1` has no + execution-configuration read. Old Sessions expose persisted model/harness with + unknown sources and unavailable provider metadata, without backfill. Projection metadata does not alter retry identity; retries cannot replace it. Keep this administrator query separate from runtime observations and do not touch activity or wake sandboxes. The versioned contract is `contracts/agents-api/execution-configuration.md`. @@ -2247,9 +2246,9 @@ replaced; do not carry obsolete compatibility code forward to satisfy this secti Keep one internal registry for protocol and token-limit validation; Core owns credential environment and endpoint admission policy. These rules are not a public discovery API or Runtime registration descriptor. Operation qualification - and live readiness retain their existing owners. The Core startup view keeps its - basic supported/configured deployment snapshot and accepts no query parameters. - Session frozen execution-configuration reads remain a separate administrator read. + and live readiness retain their existing owners. There is no startup + configuration read; Session frozen execution-configuration reads remain a + separate administrator read. - Public Agent updates use `POST /v1/agents/{agent_id}` with the same tenant/Beta boundary and shared saved-field validation. Preserve omission separately from null; only supplied fields replace saved values. Metadata is a separate whole-map @@ -2352,12 +2351,14 @@ replaced; do not carry obsolete compatibility code forward to satisfy this secti and verify supported behavior using the official client. Track current coverage in `contracts/agents-api/README.md`; SDK workflow objects are not this contract. - Shared supported wire types live in `contracts/agents-api/v1`. `make openapi` - separately generates the product spec and `contracts/agents-api/openapi.yaml`; - never mix their routes or authentication schemes. CI checks both for drift. + writes `openapi.yaml` (`/v1`), `core.openapi.yaml` (`/core/v1`) and + `runtime.openapi.yaml` (`/api/v1`); never mix their routes or authentication + schemes. Review the generated diffs; contract tests hold `openapi.yaml` to the + pinned routes and fields. - The standalone service uses `AGENTS_API_DATABASE_URL`. PostgreSQL stores Projects, their immutable execution scopes and API-key digests. Keys in the same Project resolve to one shared service-account principal and tenant. Project/key writes - are managed through deployment-authenticated APIs, not configuration files. + go through Core-key `/core/v1` routes, not configuration files. Optional `OpenAI-Organization` and `OpenAI-Project` headers must match the key; repeated/conflicting values fail authentication. Metadata, forwarded identities and product session cookies grant no access. Issue/revoke operations take effect @@ -3480,7 +3481,7 @@ queue. A failed audit must roll back the write. Internal lifecycle/refresh work not acquire public provenance. Retries never replace ownership. Environment uploads persist safe request origin before dispatch and record success with the confirmed receipt, not the native filesystem call. Never put payloads, paths or secrets in -audit metadata. Read models are deployment-authenticated `/core/v1` extensions; -keep `/v1` wire contracts unchanged. See +audit metadata. Read models are Core-key `/core/v1` routes; keep `/v1` wire +contracts unchanged. See [write-audit.md](contracts/agents-api/write-audit.md) for coverage, retention and console integration. Do not confuse key identity with Session creator identity. diff --git a/contracts/agents-api/harness-selection.md b/contracts/agents-api/harness-selection.md index 8da7ee586..ecf217592 100644 --- a/contracts/agents-api/harness-selection.md +++ b/contracts/agents-api/harness-selection.md @@ -40,38 +40,27 @@ adds comma-separated deployment-supported engines, for example remains enabled; unknown names fail startup. This setting does not install a harness or qualify a native deployment. -Hosted placement uses one provider per deployment. Set `provider` to `docker` or -`microsandbox` in `AGENTS_API_MANAGED_RUNTIMES_FILE`, with a stable -`installation_id`, a `maintenance` boolean and one matching backend object. -For example: - -```json -{ - "core_url": "http://core:8091/api/v1", - "provider": "docker", - "installation_id": "11111111-1111-4111-8111-111111111111", - "maintenance": false, - "docker": { - "host": "unix:///var/run/docker.sock", - "image": "sha256:", - "network": "bridge", - "seccomp_file": "/private/seccomp.json", - "nested_sandbox": true - } -} -``` +Hosted placement uses one provider per deployment, saved in PostgreSQL. Web or +`POST /core/v1/sandbox/deployment` with the Core key selects `docker`, +`microsandbox` or `e2b`, the per-sandbox resources and one immutable Runtime +release (an E2B template build for E2B); see the +[deployment configuration](sandbox-deployment.md). Core needs a stable +`AGENTS_API_SANDBOX_INSTALLATION_ID` for this; the installer generates it. Docker +and microsandbox sandboxes run on enrolled nodes, whose files hold only host paths +and an installed copy of that selection. The former +`AGENTS_API_MANAGED_RUNTIMES_FILE` is rejected at startup. There is no engine-to-provider routing or mixed-provider configuration. Enabling another harness does not choose another image or backend; the selected Runtime image must contain and qualify each enabled harness. Capability checks still -apply. Legacy `default_provider`, `engine_providers` and provider maps are rejected. +apply. -Before changing provider or backend namespace, restart the original configuration -with `maintenance: true`, explicitly settle or delete its hosted resources and -confirm cleanup is complete. Restart the new provider configuration in maintenance -to validate the switch, then disable maintenance without changing its identity. -Switching never migrates Sessions or deletes resources automatically. See the -[deployment procedure](../../services/agents-api/deploy/microsandbox/README.md#change-the-deployment-provider). +Before changing provider, resources or Runtime, enter maintenance at the current +generation, explicitly archive retained hosted Sessions and confirm cleanup is +complete. Then submit the replacement and explicitly resume with the returned +generation. Switching never migrates Sessions or deletes resources automatically. +See the +[deployment procedure](../../services/agents-api/HOSTED-SANDBOX-MANAGER.md#removal-and-maintenance). For multiple engines, use an exclusive `by_harness` object in the private `AGENTS_API_EXECUTION_OPTIONS_FILE`, with one existing adapter-options object per diff --git a/contracts/agents-api/node-host-history.md b/contracts/agents-api/node-host-history.md index 3cd5c7fcd..44406ca1e 100644 --- a/contracts/agents-api/node-host-history.md +++ b/contracts/agents-api/node-host-history.md @@ -1,8 +1,8 @@ # Administrator node host observations -`GET /core/v1/sandbox/nodes/{node_id}?range=1h|6h|24h` requires deployment -administrator authentication. Core Web forwards it through its authenticated -server; Project, enrollment and node credentials do not authorize this read. +`GET /core/v1/sandbox/nodes/{node_id}?range=1h|6h|24h` requires the Core key. +Core Web forwards it with the Core key after console sign-in; Project, enrollment +and node credentials do not authorize this read. The omitted range defaults to `1h`. Invalid, repeated or unknown query parameters return the existing invalid-input response; missing or removed nodes return 404. diff --git a/contracts/agents-api/openapi.yaml b/contracts/agents-api/openapi.yaml index 288a0c388..6671b1562 100644 --- a/contracts/agents-api/openapi.yaml +++ b/contracts/agents-api/openapi.yaml @@ -5360,16 +5360,4 @@ securityDefinitions: in: header name: Authorization type: apiKey - DeploymentAdminAuth: - in: header - name: Authorization - type: apiKey - NodeAuth: - in: header - name: Authorization - type: apiKey - NodeEnrollmentAuth: - in: header - name: Authorization - type: apiKey swagger: "2.0" diff --git a/contracts/agents-api/runtime-history-api.md b/contracts/agents-api/runtime-history-api.md index 5ee610c46..3aa6a2349 100644 --- a/contracts/agents-api/runtime-history-api.md +++ b/contracts/agents-api/runtime-history-api.md @@ -1,6 +1,6 @@ # Runtime history API -Status: public contract, strict TypeScript client, PostgreSQL history and Core Web +Status: Core-key contract, strict TypeScript client, PostgreSQL history and Core Web History ranges implemented. Core uses its existing database; the execution owner samples every 30 seconds by default. API-only processes without an execution worker collect only on read; their Session history read returns @@ -144,7 +144,7 @@ or malformed data reject the entire response with a 502 `invalid_admin_response` ## Explicit boundaries - The routes never sample a live provider, provision compute, or mutate lifecycle. -- The public contract does not expose a storage backend. +- The contract does not expose a storage backend. - History availability does not imply current Runtime readiness. - Current observations and Durable history have separate freshness and retention semantics and must remain separately labelled in Web. diff --git a/contracts/agents-api/runtime-observability-api.md b/contracts/agents-api/runtime-observability-api.md index b7b655ffe..9ced075e9 100644 --- a/contracts/agents-api/runtime-observability-api.md +++ b/contracts/agents-api/runtime-observability-api.md @@ -1,7 +1,7 @@ # Runtime observation API Status: Phase 2 and initial Core Web consumption implemented. The current-snapshot routes, strict -`packages/agents-client` projection, and generated `openapi.yaml` contract are +`packages/agents-client` projection, and generated `core.openapi.yaml` contract are implemented and consumed by the Dashboard through complete Session/observation identity joins. Durable history uses the separate optional [Runtime history API](runtime-history-api.md); lifecycle controls remain outside diff --git a/contracts/agents-api/runtime-observability-design.md b/contracts/agents-api/runtime-observability-design.md index 00e533aa2..c7575dd2e 100644 --- a/contracts/agents-api/runtime-observability-design.md +++ b/contracts/agents-api/runtime-observability-design.md @@ -4,7 +4,7 @@ Status: provider abstraction with Docker and microsandbox sampling, the current-snapshot API/client contract, and Core Web Live and capability-gated Durable Dashboard sources are implemented. Phase 4 includes the bounded sanitized exporter seam, optional OTLP/HTTP transport, execution-owner singleton background -sampling, PostgreSQL history, public history API, and 1h/6h/24h Web ranges. +sampling, PostgreSQL history, the Core-key history read, and 1h/6h/24h Web ranges. History uses the existing Core database by default. Other provider sources are not implemented. Microsandbox idle suspension is a separate durable lifecycle feature; it does not consume this telemetry as authority. @@ -51,7 +51,7 @@ evidence. They must not become execution or lifecycle authority. | Concern | Authority | Notes | | --- | --- | --- | -| Tenant and Session ownership | Core database | Every public read is tenant-scoped. | +| Tenant and Session ownership | Core database | Every read is scoped to the tenant of the Project in its `/core/v1` path. | | Environment placement | Session configuration and Environment row | `none`, `self_hosted`, or `openai_hosted`. | | Observation resource identity | Session ID | One current observation resource exists per tenant-owned Session. | | Managed Runtime identity | `runtime_allocations` | Allocation and provider key identify the compute incarnation. | @@ -258,8 +258,8 @@ Core reuses its PostgreSQL database for bounded recent Runtime history. The provider-neutral observation service hands each sanitized periodic result to a bounded asynchronous writer. One typed row contains the observation and optional measured Session usage snapshot (recorded root Turn snapshots, active Turns -included, not the public Session usage rule). The public API resolves caller ownership before -issuing bounded queries; Web never queries storage directly. +included, not the public Session usage rule). The `/core/v1` read resolves the Project's +Session before issuing bounded queries; Web never queries storage directly. External OTLP export remains optional. Each destination has an independent queue, so a Collector outage cannot delay local persistence. Neither history nor export diff --git a/contracts/agents-api/runtime-observability.md b/contracts/agents-api/runtime-observability.md index 15612e920..c1b3f2e98 100644 --- a/contracts/agents-api/runtime-observability.md +++ b/contracts/agents-api/runtime-observability.md @@ -127,7 +127,7 @@ PostgreSQL database. The execution owner samples every 30 seconds by default, using bounded pages, concurrency and source deadlines. Collection never wakes or mutates compute. The worker lease is checked during the sweep and before each handoff. Only periodic samples populate durable history; current API reads cannot -inflate cadence coverage. Retention is seven days; public queries span at most +inflate cadence coverage. Retention is seven days; history reads span at most 24 hours and have explicit input and output limits. `AGENTS_API_RUNTIME_HISTORY_FILE` optionally changes sampling and adds OTLP/HTTP diff --git a/contracts/agents-api/write-audit.md b/contracts/agents-api/write-audit.md index aa29a04e0..99ae9f3b2 100644 --- a/contracts/agents-api/write-audit.md +++ b/contracts/agents-api/write-audit.md @@ -9,8 +9,8 @@ replacement for a Session's creator identity. Authentication carries the issued key UUID and its Project's tenant/principal. Keys in one Project share assets and permissions; provenance records which key performed each write. All business keys live in PostgreSQL. Configuration contains -no business keys or Projects. Console credentials authenticate only management -operations and are never public API identities. Client headers cannot assert a +no business keys or Projects. The Core key authenticates only `/core/v1` and is +never a public API identity. Client headers cannot assert a key identity, and display names do not change an ID. True creation stores ownership in the same transaction as the resource and operation. diff --git a/docs/api/README.md b/docs/api/README.md index 151186b56..6e31401eb 100644 --- a/docs/api/README.md +++ b/docs/api/README.md @@ -7,7 +7,7 @@ no credential works in another namespace. | --- | --- | --- | --- | --- | | `/v1` | Applications (business systems, SDKs) | Project API key | Exactly the pinned official Agents API routes. Core-only fields live only in `x_agents_core` (`harness`, `model_provider`) | [Public API](public-agent-api.md) | | `/core/v1` | Core Web's server and operator scripts | [Core key](../getting-started/operations.md#core-key) | Projects and keys, resource reads and deletion, Session archive, credential issuance, metrics, audit, sandbox deployment and nodes | [Core API](#core-api), [Web API](web-management.md), [Core OpenAPI](../../contracts/agents-api/core.openapi.yaml) | -| `/api/v1` | Nodes, Runtime daemons, self-hosted executors | Machine credentials issued through `/core/v1` | Machine connections only: `/api/v1/sandbox-node/*` and `/api/v1/agent-daemon/*`, including WebSockets; each credential works only on its own routes | [Node operations](../../services/agents-api/HOSTED-SANDBOX-MANAGER.md#register-a-host), [executor credentials](../../contracts/agents-api/environment-executor-credentials.md), [machine OpenAPI](../../contracts/agents-api/runtime.openapi.yaml) | +| `/api/v1` | Nodes, Runtime daemons, self-hosted executors | Machine credentials: node enrollment tokens and executor credentials issued through `/core/v1`, node credentials registered with an enrollment token, and daemon credentials Core writes into hosted sandboxes | Machine connections only: `/api/v1/sandbox-node/*` and `/api/v1/agent-daemon/*`, including WebSockets; each credential works only on its own routes | [Node operations](../../services/agents-api/HOSTED-SANDBOX-MANAGER.md#register-a-host), [executor credentials](../../contracts/agents-api/environment-executor-credentials.md), [machine OpenAPI](../../contracts/agents-api/runtime.openapi.yaml) | A Project API key gets 401 on `/core/v1` and `/api/v1`; the Core key gets 401 on `/v1` and `/api/v1`. Projects own assets. Multiple equally privileged keys share @@ -27,9 +27,18 @@ The deployment's reverse proxy sends `/v1`, `/v1/*` and `/api/v1/*` to Core and every other path, including `/core/v1/*`, to Web. Operator scripts call `/core/v1` with the Core key on Core's loopback port, not through the public entry. +## Public API + +Applications call every `/v1` route with a Project API key. The routes are exactly +the 58 method and path pairs in +[upstream-routes.json](../../contracts/agents-api/upstream-routes.json); the +[Public API guide](public-agent-api.md) groups them by resource. `/v1` has no +Core-only route. + ## Core API -All routes are under `/core/v1` and require the Core key. +All routes are under `/core/v1`. Core Web's server and operator scripts call them +with the Core key. | Routes | Contents | Contract | | --- | --- | --- | @@ -43,6 +52,19 @@ All routes are under `/core/v1` and require the Core key. | `metrics` | Core's own process metrics | [Core metrics](../../contracts/agents-api/core-metrics.md) | | `sandbox/deployment[/maintenance]`, `sandbox/enrollment-tokens`, `sandbox/nodes[/{node_id}[/allocations]]` | Sandbox deployment, node enrollment tokens and nodes | [Sandbox deployment](../../contracts/agents-api/sandbox-deployment.md), [node operations](../../services/agents-api/HOSTED-SANDBOX-MANAGER.md), [node host history](../../contracts/agents-api/node-host-history.md) | +## Machine connection API + +These routes are under `/api/v1`. Each accepts only the credential listed, never +the Core key or a Project API key. + +| Routes | Caller | Credential | Contract | +| --- | --- | --- | --- | +| `POST sandbox-node/enroll` | Node installer | One-use enrollment token from `POST /core/v1/sandbox/enrollment-tokens` | [Node operations](../../services/agents-api/HOSTED-SANDBOX-MANAGER.md#register-a-host), [machine OpenAPI](../../contracts/agents-api/runtime.openapi.yaml) | +| `GET sandbox-node/configuration` | Node installer and node | Enrollment token, or node credential with `X-Parsar-Node-ID` | [Sandbox deployment](../../contracts/agents-api/sandbox-deployment.md), [machine OpenAPI](../../contracts/agents-api/runtime.openapi.yaml) | +| `GET sandbox-node/identity`, WebSocket `GET sandbox-node/connect` | Node | Node credential registered at enrollment | [Node operations](../../services/agents-api/HOSTED-SANDBOX-MANAGER.md#register-a-host) | +| `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) | + ## Contract sources - [Pinned upstream baseline](../../contracts/agents-api/upstream.json): OpenAI diff --git a/docs/api/public-agent-api.md b/docs/api/public-agent-api.md index f4c58a783..40e6c521f 100644 --- a/docs/api/public-agent-api.md +++ b/docs/api/public-agent-api.md @@ -54,12 +54,12 @@ SSE is live, not a historical replay service. After a disconnect, query the Sess Turns and Items to reconcile state. An accepted request is not proof of completed native execution. Do not automatically replay uncertain tool or file effects. -## Core extensions +## Core extension fields The `/v1` route set is exactly the pinned SDK's operations, listed in -[upstream-routes.json](../../contracts/agents-api/upstream-routes.json). Core adds -fields only inside `x_agents_core`, because it runs several harnesses and accepts -custom model access: +[upstream-routes.json](../../contracts/agents-api/upstream-routes.json); Core adds +no route. It adds fields only inside `x_agents_core`, because it runs several +harnesses and accepts custom model access: | Field | Where | Reference | | --- | --- | --- | @@ -70,14 +70,16 @@ Any other member of `x_agents_core` is rejected with 400. Deployment, placement, credential issuance and operational reads are not part of `/v1`; they belong to `/core/v1`, which only the Core key can call (see the [API index](README.md)). -An application creates a `self_hosted` Session with its Project key. The -deployment operator then issues the Environment's executor credential with the -Core key under `/core/v1/projects/{project_id}/environments/{environment_id}/executor-credentials` -and gives it to the executor host; see -[executor credentials](../../contracts/agents-api/environment-executor-credentials.md). +An application reads a Session's model from `agent.model` and an explicitly +selected harness from `agent.x_agents_core.harness`; a Session on the deployment +default harness omits `agent.x_agents_core`. `/v1` has no execution-configuration +read. `openai_hosted` keeps the official wire name and means Core-managed compute here. The deployment chooses E2B or its own Docker/microsandbox nodes. A public `self_hosted` Environment uses caller-owned compute and the same colocated -Runtime. Our daemon transport and the supported native harness differences are +Runtime. For a `self_hosted` Session, the deployment operator issues the +Environment's executor credential with the Core key; see +[executor credentials](../../contracts/agents-api/environment-executor-credentials.md). +Our daemon transport and the supported native harness differences are explicit; they do not imply interoperability with OpenAI's stock executor transport. diff --git a/docs/getting-started/install.md b/docs/getting-started/install.md index 492a67a7c..cb6e78e41 100644 --- a/docs/getting-started/install.md +++ b/docs/getting-started/install.md @@ -67,9 +67,6 @@ retains that URL for remote node downloads; it does not silently change mirrors. ## Sign in to Web -The management backend and client require the corresponding Web screen migration -before release. See [console integration status](../web/README.md). - Installation creates private configuration under `~/.parsar/core`, a dedicated PostgreSQL volume and a credential encryption key. Installation creates no Project or application API key. Projects and their keys are managed in the database; @@ -83,9 +80,9 @@ the example above) and sign in with the Core key from one role: administrator, with access to every console operation. The paired console already connects to Core with the same key on the server side. -Use the administrator API to create a Project, then issue a named API key within -it and save the one-time plaintext response privately. Core stores only its digest. -The corresponding Web management screens remain pending. Multiple keys in a Project +Use Web's **Projects and keys** page or the administrator API to create a Project, +then issue a named API key within it and save the one-time plaintext response +privately. Core stores only its digest. Multiple keys in a Project share its assets and execution principal; writes record the actual key separately. Rotate by issuing another key in that Project and revoking the old one. Archiving the Project disables all its keys and retains assets for inspection and deletion. @@ -109,8 +106,8 @@ Use exactly the displayed console address; the production proxy validates its configured origin. Sign-in sessions live in the console's memory. They expire after 12 hours, and you sign in again after a console restart or a Core key rotation. Sign-in, status and sign-out use private `/console/auth` routes and do not extend -the public Agent API. The console rejects every `/v1` request, including requests -carrying an explicit Bearer token; it holds no caller key. +the public Agent API. The console rejects every `/v1` and `/api/v1` request, +including requests carrying an explicit Bearer token; it holds no caller key. Core loads the Core key digest from `AGENTS_API_CORE_KEY_DIGESTS_FILE`. Only the Core container mounts the digest file, read-only. The bundled Web server reads the diff --git a/docs/getting-started/operations.md b/docs/getting-started/operations.md index e9b63af03..ee73b6964 100644 --- a/docs/getting-started/operations.md +++ b/docs/getting-started/operations.md @@ -149,6 +149,7 @@ replacement. Stop the services, then: | `admin/digests.json` | `admin/core-key-digests.json` | File; Core bind mount in `compose.json` | | `AGENTS_API_SANDBOX_ADMIN_DIGESTS_FILE` | `AGENTS_API_CORE_KEY_DIGESTS_FILE` | `config/core.env`; its value names the renamed file | | `CORE_CONSOLE_ADMIN_TOKEN_FILE` | `CORE_CONSOLE_CORE_KEY_FILE` | Web `environment` in `compose.json` | +| `--admin-token-file` | `--core-key-file` | `install.sh --web-only` flag; the installer rejects the old flag | Also remove `CORE_CONSOLE_AUTH_MODE`, `CORE_CONSOLE_STATE_DIR` and `CORE_CONSOLE_PASSWORD_FILE` from Web's environment, with their `state/console` @@ -161,8 +162,7 @@ backup. Then start the services and sign in with the Core key. Use Web, or the [Core API](../../contracts/agents-api/admin-api.md) under `/core/v1/projects` with the Core key, to create a Project and issue its first key -after installation. The Web management migration -is still pending; see [integration status](../web/README.md). No configuration file +after installation. No configuration file defines Projects or application keys. API-key plaintext is returned once at issuance, with only its digest stored in the database. diff --git a/docs/getting-started/quickstart.md b/docs/getting-started/quickstart.md index 43e26d1b7..477370dad 100644 --- a/docs/getting-started/quickstart.md +++ b/docs/getting-started/quickstart.md @@ -12,11 +12,10 @@ python3 -m venv .venv pip install openai==3.13.0 ``` -The deployment administrator first creates a Project through -`POST /core/v1/projects` with `{"name":"Default"}`, then issues a key through +The deployment administrator first creates a Project and issues a key within it, +on Web's **Projects and keys** page or with the [Core key](operations.md#core-key) +as Bearer credential: `POST /core/v1/projects` with `{"name":"Default"}`, then `POST /core/v1/projects/{project_id}/keys` with a descriptive `{"name":"..."}`. -These requests use the [Core key](operations.md#core-key) as their Bearer credential. The management UI has not -yet migrated; see [integration status](../web/README.md). Obtain that key through a private channel and supply it as `PARSAR_API_KEY` in your application configuration. Its plaintext appears only at issuance; Core stores a diff --git a/scripts/openapi-split/main.go b/scripts/openapi-split/main.go index bda8f1208..550c5baa7 100644 --- a/scripts/openapi-split/main.go +++ b/scripts/openapi-split/main.go @@ -54,7 +54,8 @@ func run(input, projectOutput, coreOutput, runtimeOutput string) error { pruneDefinitions(p) pruneDefinitions(m) pruneDefinitions(rt) - // The project document keeps the generator's complete scheme list unchanged. + // Each document keeps only the security schemes its operations require. + pruneSecurityDefinitions(p) pruneSecurityDefinitions(m) pruneSecurityDefinitions(rt) // Keep unrelated existing project definitions and the generator's formatting. @@ -197,7 +198,7 @@ func pruneSecurityDefinitions(root *yaml.Node) { func preserveProjectFormatting(raw []byte, original, filtered *yaml.Node) []byte { lines := bytes.SplitAfter(raw, []byte("\n")) removed := make([]bool, len(lines)) - for _, section := range []string{"paths", "definitions"} { + for _, section := range []string{"paths", "definitions", "securityDefinitions"} { source, target := field(original, section), field(filtered, section) if source == nil { continue diff --git a/scripts/openapi-split/main_test.go b/scripts/openapi-split/main_test.go index 20794049b..e3f944e52 100644 --- a/scripts/openapi-split/main_test.go +++ b/scripts/openapi-split/main_test.go @@ -23,6 +23,8 @@ info: paths: /agents/sessions: get: + security: + - BearerAuth: [] responses: "200": schema: @@ -97,9 +99,8 @@ securityDefinitions: t.Fatal("reference closure was not preserved") } } - // Generated surfaces keep only the schemes their operations use; the project - // document is left as generated. - for path, want := range map[string]string{project: "BearerAuth DeploymentAdminAuth NodeAuth", core: "DeploymentAdminAuth", machine: "NodeAuth"} { + // Every document keeps only the schemes its operations use. + for path, want := range map[string]string{project: "BearerAuth", core: "DeploymentAdminAuth", machine: "NodeAuth"} { raw, err := os.ReadFile(path) if err != nil { t.Fatal(err) diff --git a/services/agents-api/HOSTED-RELEASE.md b/services/agents-api/HOSTED-RELEASE.md index db3e8eb6f..0daa8ee2a 100644 --- a/services/agents-api/HOSTED-RELEASE.md +++ b/services/agents-api/HOSTED-RELEASE.md @@ -1,7 +1,8 @@ # Docker-hosted Agents API -This package runs Core on a Linux amd64 host and creates one colocated -Runtime per Session through Docker. Each Runtime contains the daemon, stock +This package adds a qualified Linux amd64 Runtime image for Core-managed +Sessions on Docker. A registered Docker sandbox node, not Core, creates one +colocated Runtime per Session. Each Runtime contains the daemon, stock Codex 0.153.4, local tools and workspace. Core, its PostgreSQL database and operator secrets stay outside the Runtime. No source checkout, compiler, Parsar service, product database, separate executor or manual daemon enrollment @@ -30,48 +31,39 @@ docker image inspect @RUNTIME_IMAGE@ --format '{{.Id}} {{.Os}}/{{.Architecture}} The result must be `@RUNTIME_IMAGE@ linux/amd64`. The image is selected by this immutable ID; no registry pull or mutable tag is required. Package checksums establish transferred bytes, not trust in their distributor or safety of another -image. Keep the package's `runtime/seccomp.json` available to Core. +image. Keep the package's `runtime/seccomp.json` available to the node service +(`seccomp_file` in its provider configuration). ## Configure Core -Run Core as an operator account with access to the explicit local Docker Unix -socket. Docker access is privileged host authority; keep Core and this socket -outside agent workspaces. The Provider never mounts it in a Runtime. Retain the -same Docker backend, provider UUID, database, caller identities and native volumes -across Core upgrades. Changing a backend needs a new provider UUID; keep the old -entry until its allocations are reclaimed. - -For a local deployment, the following uses the Docker bridge gateway so sandbox -connections can reach Core. Reserve port 8091 and restrict it to intended clients -and Runtime containers with the host firewall. For external access, terminate TLS -with your existing proxy and use its reachable HTTPS/WSS addresses instead. +Core no longer uses a Docker socket or a managed Runtime file; it rejects +`AGENTS_API_MANAGED_RUNTIMES_FILE` at startup. PostgreSQL owns the hosted +deployment: provider, per-sandbox resources and one immutable Runtime release, +selected with the Core key through `POST /core/v1/sandbox/deployment` (see the +[deployment contract](https://github.com/MiniMax-AI/parsar-core/blob/@SOURCE_REVISION@/contracts/agents-api/sandbox-deployment.md)). +A Docker node registered with `bin/parsar-sandbox-node` owns the host's Docker +socket and creates the Runtimes; see +[register a host](HOSTED-SANDBOX-MANAGER.md#register-a-host). + +A Docker Runtime release names all six identities of one matched distribution: +source commit, image ID, OCI manifest digest, microsandbox reference, Runtime and +firmware hashes. This package records only the image ID, so it cannot supply that +release by itself. Use the Core distribution and its +[installer](https://github.com/MiniMax-AI/parsar-core/blob/@SOURCE_REVISION@/docs/getting-started/install.md), +whose manifest carries the complete release and whose Web console adds Docker +nodes. + +For a manual deployment with a complete release, set these in addition to the +common configuration, using a stable installation UUID and the HTTPS origin that +nodes and sandbox guests reach through your TLS proxy: ```sh export AGENTS_API_ADDR=0.0.0.0:8091 -RUNTIME_GATEWAY="$(docker network inspect bridge --format '{{(index .IPAM.Config 0).Gateway}}')" -export AGENTS_API_DAEMON_WS_URL="ws://$RUNTIME_GATEWAY:8091/api/v1/agent-daemon/ws" -export AGENTS_API_MANAGED_RUNTIMES_FILE="$PARSAR_HOME/managed-runtimes.json" +export AGENTS_API_SANDBOX_INSTALLATION_ID="" +export AGENTS_API_DAEMON_WS_URL="wss://core.example/api/v1/agent-daemon/ws" export AGENTS_API_EXECUTION_OPTIONS_FILE="$PARSAR_HOME/execution-options.json" ``` -Create the private managed configuration with a fresh stable installation UUID. Replace -``, the gateway and the absolute package path: - -```json -{ - "core_url": "http://:8091/api/v1", - "provider": "docker", - "installation_id": "", - "maintenance": false, - "docker": { - "host": "unix:///var/run/docker.sock", - "image": "@RUNTIME_IMAGE@", - "network": "bridge", - "seccomp_file": "/runtime/seccomp.json" - } -} -``` - Create `execution-options.json` with your trusted native model configuration. For a Responses-compatible model endpoint, the existing Codex adapter accepts: @@ -86,19 +78,23 @@ For a Responses-compatible model endpoint, the existing Codex adapter accepts: } ``` -Keep both files mode 0600 outside the extracted package. The model endpoint must +Keep it mode 0600 outside the extracted package. The model endpoint must be reachable from the Runtime; a host loopback address is not the container's host. Core copies these options into trusted execution preparation without storing them in public Session configuration. Never put model credentials in Agent instructions, public requests, image layers or a workspace. Configuration changes -require a Core restart. Leave remote executor URLs unset for this hosted profile. +require a Core restart. ```sh -chmod 0600 "$AGENTS_API_CORE_KEY_DIGESTS_FILE" "$AGENTS_API_MANAGED_RUNTIMES_FILE" "$AGENTS_API_EXECUTION_OPTIONS_FILE" +chmod 0600 "$AGENTS_API_CORE_KEY_DIGESTS_FILE" "$AGENTS_API_EXECUTION_OPTIONS_FILE" "$AGENTS_API_BIN_DIR/agents-api-migrate" "$AGENTS_API_BIN_DIR/agents-api" ``` +Then select `docker` with `https://core.example` as `core_url`, the per-sandbox +resources and the complete Runtime release, and register a node on a host where +this image is loaded. Hosted admission starts when a ready node has capacity. + Use your existing service supervisor for long-running operation. Migrations are explicit. One Core execution worker owns each database; replicas do not provide execution HA. `GET /healthz` checks liveness, not successful sandbox preparation. @@ -161,16 +157,16 @@ workspace continuation. Do not turn an uncertain interrupted execution into a ne request or delete native history to make a retry succeed. When finished, `client.beta.agents.sessions.delete(session.id)` requests owned -Runtime cleanup. Core must remain running with the original Provider configured -until its labelled container and volumes are gone. Public deletion acknowledgment +Runtime cleanup. Core and the original node must remain running until its +labelled container and volumes are gone. Public deletion acknowledgment is not physical cleanup confirmation. Do not use broad Docker pruning. -To change providers, restart the old configuration with `maintenance: true`, -explicitly handle or delete old hosted resources and verify cleanup. Restart the -new provider configuration in maintenance to validate the empty deployment, then -restart the same identity with `maintenance: false`. Maintenance blocks new compute -without deleting retained resources. One deployment runs either Docker or -[microsandbox](deploy/microsandbox/README.md), with no mixed configuration, +To change providers, resources or Runtime, follow the +[maintenance procedure](HOSTED-SANDBOX-MANAGER.md#removal-and-maintenance): enter +maintenance at the current generation, archive retained hosted Sessions and verify +cleanup, submit the replacement, then resume. Maintenance blocks new compute +without deleting retained resources. One deployment runs exactly one provider, +E2B, Docker or [microsandbox](deploy/microsandbox/README.md), with no mixed configuration, engine-to-provider routing or automatic Session migration. Back up the independent PostgreSQL database @@ -182,13 +178,22 @@ recovery plan; the archive itself contains no deployment data. The qualified basic profile covers public creation, native execution, inline and source-file copies/listing, cancellation, retained-history restart and owned cleanup. Network access defaults to enabled; explicit disabled confines native -tools while the trusted harness retains model/Core connectivity. Restricted domains, -populated startup installations/templates, hosted MCP combinations, Artifacts and -complete protocol parity remain open. Files size and directory bounds are local -implementation limits, not verified upstream limits. - -User-managed deployment will reuse this Runtime, but installation/enrollment and -its official protocol mapping are separate work. It is not automatically official -`self_hosted`. This package does not install Docker/PostgreSQL/TLS/a supervisor, -publish an image, migrate product execution, add engines or introduce another -execution topology. See the [versioned coverage ledger](https://github.com/MiniMax-AI/parsar-core/blob/@SOURCE_REVISION@/contracts/agents-api/README.md). +tools while the trusted harness retains model/Core connectivity, and exact-host +restricted policies are supported. Environment Templates and inline +initialization are covered within their +[recorded limits](https://github.com/MiniMax-AI/parsar-core/blob/@SOURCE_REVISION@/contracts/agents-api/environment-templates.md), and Artifacts are captured on +accepted Docker profiles. Other hostname forms, service-origin hosted MCP and +complete protocol parity remain open. Files size and +directory bounds are local implementation limits, not verified upstream limits. + +The same Runtime also serves caller-managed `self_hosted` Sessions. The application +creates the Session with its Project API key, the deployment operator issues the +Environment's [executor credential](https://github.com/MiniMax-AI/parsar-core/blob/@SOURCE_REVISION@/contracts/agents-api/environment-executor-credentials.md) with +the Core key, and the executor host runs the daemon with it. That path is +[qualified](https://github.com/MiniMax-AI/parsar-core/blob/@SOURCE_REVISION@/contracts/agents-api/user-managed-runtime-v1.md) on user-managed Docker and E2B for all +three harnesses. It accepts only `/workspace` with empty capability directories, +rejects service-origin HTTP MCP and has no Environment Templates; the application +owns and cleans up its compute. This package does not install +Docker/PostgreSQL/TLS/a supervisor, publish an image, migrate product execution or +add engines. See the +[versioned coverage ledger](https://github.com/MiniMax-AI/parsar-core/blob/@SOURCE_REVISION@/contracts/agents-api/README.md). diff --git a/services/agents-api/HOSTED-SANDBOX-MANAGER.md b/services/agents-api/HOSTED-SANDBOX-MANAGER.md index 68e5e7987..e4d9397aa 100644 --- a/services/agents-api/HOSTED-SANDBOX-MANAGER.md +++ b/services/agents-api/HOSTED-SANDBOX-MANAGER.md @@ -8,15 +8,14 @@ Docker/microsandbox nodes must match its installation, generation and specificat are distinct from user-managed `self_hosted` Environments, whose provisioning remains the user's responsibility. -The Web console's **Hosted Sandbox Manager** page uses deployment administrator -authority, separate from project credentials. In a paired distribution, the -console server reads the Core key and forwards it only on sandbox management -routes after console login. The Core key never reaches the browser. There is no -second login or manual key form. Management uses the -same-origin paired console connection; direct remote project connections do not -grant deployment access. An unpaired console shows setup guidance. For manual or -Web-only deployments, an operator configures the matching private `0600` Core key -file server-side through `CORE_CONSOLE_CORE_KEY_FILE`. +The Web console's **Hosted Sandbox Manager** page uses the Core key, separate from +Project API keys. After console sign-in, the console server forwards the page's +`/core/v1/sandbox` requests, like every other `/core/v1` request, with the Core +key it reads from its private file. The Core key never reaches the browser. There +is no second login or manual key form. For manual or Web-only deployments, an +operator configures the matching private `0600` Core key file server-side through +`CORE_CONSOLE_CORE_KEY_FILE`; Web refuses to start without it. Core serves the +deployment and node routes only when `AGENTS_API_SANDBOX_INSTALLATION_ID` is set. The sandbox page and its setup, enrollment, status and diagnostic controls support Chinese and English. Choose a language in System navigation; the preference is @@ -40,11 +39,12 @@ then choose Docker or microsandbox. Supply the per-sandbox resources and matched Runtime release as part of initial setup. E2B takes an account API key, CPU/memory limits and a qualified immutable Runtime template build (`template-id:build-uuid`); its exact ready build must match those limits before the selection can be saved. The key is write-only, -encrypted by Core and never returned to the browser. E2B needs no node installation. It defaults to the -paired console origin, which forwards the required Core API and WebSocket routes. -Use advanced network settings only when nodes and guests need a different public -HTTPS origin. When the inferred address is loopback or is not HTTPS, setup -opens the network field and requires a non-loopback HTTPS origin before saving. +encrypted by Core and never returned to the browser. E2B needs no node installation. +The saved Core origin defaults to the paired console's public origin, where the +reverse proxy sends `/api/v1`, including WebSocket upgrades, directly to Core; Web +does not forward it. Use advanced network settings only when nodes and guests need +a different public HTTPS origin. When the inferred address is loopback or is not +HTTPS, setup opens the network field and requires a non-loopback HTTPS origin before saving. The API still accepts HTTP loopback for explicit local development; a guest's loopback address cannot reach its Core host. diff --git a/services/agents-api/README.md b/services/agents-api/README.md index aa62f80b0..79e8d55d5 100644 --- a/services/agents-api/README.md +++ b/services/agents-api/README.md @@ -79,7 +79,7 @@ configuration and a separately installed execution daemon are still required; these binaries do not establish full protocol coverage. For a standalone Linux container, see [Container deployment](CONTAINER.md). -`make build-agents-api-release` packages the same four commands in a versioned +`make build-agents-api-release` packages these commands and `parsar-sandbox-node` in a versioned Linux amd64 archive, with source/protocol identity, checksums, a license and [operator instructions](RELEASE.md). Build from a clean Git worktree with Go and Python 3.9+; output defaults to `~/.parsar/build/agents-api-release` (or @@ -93,9 +93,12 @@ AGENTS_API_RELEASE_RUNTIME_IMAGE=sha256: make build-agents-a The resulting `agents-api-docker--linux-amd64.tar.gz` also contains the Runtime image export, committed seccomp policy and [hosted guide](HOSTED-RELEASE.md). -Consumers load the included image and start the extracted Core; no source checkout -or compiler is needed. The builder records the selected image ID and file hashes; -the exact Core/Runtime combination still needs deployment acceptance. The ordinary +The builder records only the selected image ID and file hashes, not the complete +Runtime release (six distribution identities) that a Docker deployment requires, +so this package cannot configure hosted execution by itself. For Docker-hosted +deployments, the Core distribution and its +[installer](../../docs/getting-started/install.md) replace it: their manifest +carries the complete release, and Docker nodes are added from Web. The ordinary archive remains Docker-free. Database/Docker setup and publication remain separate. ## Database ownership @@ -157,19 +160,19 @@ incomplete. Durable acceptance is not an exactly-once side-effect guarantee. Run migrations first, then `go run ./services/agents-api/cmd/server`. The service uses `AGENTS_API_DATABASE_URL` for its dedicated database; it does not read the -product database or accept product login cookies. Configure the Core key digest -file through `AGENTS_API_CORE_KEY_DIGESTS_FILE` at startup to manage Projects and -keys. The Core key cannot authenticate `/v1`, and application API keys cannot -authenticate administrator routes. +product database or accept product login cookies. It requires the Core key digest +file named by `AGENTS_API_CORE_KEY_DIGESTS_FILE` at startup; the Core key +authenticates `/core/v1`, where Projects and keys are managed. The Core key cannot +authenticate `/v1`, and application API keys cannot authenticate `/core/v1`. Projects and API keys live only in the database. Configuration files contain infrastructure settings and deployment credentials, not business identities. Installation creates no Project or application key. Using the [administrator API](../../contracts/agents-api/admin-api.md), create a Project with `POST /core/v1/projects` and issue a named key with -`POST /core/v1/projects/{project_id}/keys`. Both requests accept a JSON object containing `name`; -Core generates the identifiers. The Web management screens still need migration; -see [integration status](../../docs/web/README.md). +`POST /core/v1/projects/{project_id}/keys`, or use Core Web's **Projects and +keys** page. Both requests accept a JSON object containing `name`; Core generates +the identifiers. A Project owns one tenant and one execution principal. All keys in it have equal access to its assets and share that principal; write provenance records the actual