diff --git a/apps/docs/content/docs/examples.mdx b/apps/docs/content/docs/examples.mdx index 4f91bf44b..d758b0eb1 100644 --- a/apps/docs/content/docs/examples.mdx +++ b/apps/docs/content/docs/examples.mdx @@ -51,8 +51,9 @@ Each feature maps to one part of the API. Read the code next to the guide sectio ### Not covered -Vaults and MCP authentication, OAuth, Session deletion, and MiniMax Code on your -own machine. +Vaults and MCP authentication, OAuth, Session deletion, MiniMax Code on your own +machine, and managed Skills or templates on your own machine +(`x_agents_core.environment`). ## Add an example diff --git a/apps/docs/content/docs/sessions.mdx b/apps/docs/content/docs/sessions.mdx index 59d2132e7..54d35dcab 100644 --- a/apps/docs/content/docs/sessions.mdx +++ b/apps/docs/content/docs/sessions.mdx @@ -146,6 +146,7 @@ only additions to the OpenAI shapes, and they sit inside `x_agents_core`: | `harness` | Agent, or a Session's inline `agent` | `codex`, `claude_sdk` or `mcode` | | `model_provider` | Agent, or Session creation (top level) | `protocol`, `base_url`, `api_key`, and for `mcode` also `context_window` and `max_output_tokens`. The protocol must be one the harness supports: Codex `responses`, Claude Code `anthropic`, MiniMax Code any of `anthropic`, `responses`, `chat_completions` | | `harness_config` | Agent, inline `agent`, or Session creation (top level, wins) | The harness's native model parameters, such as Codex's `model_reasoning_effort` | +| `environment` | Session creation (top level), any placement | Portable preparation: `environment_template_id`, `files`, `env`, `packages`, `setup_commands`, `skills`, `plugins`, `capability_directories`. A field may not also appear in `environment`; see [Environments](/environments-and-files#preparation-order) | | `installation` | Read-only, on `self_hosted` Sessions | Short-lived install commands for your machine; see [self-hosted execution](/self-hosted-execution) | Any other member is rejected with 400. `api_key` is write-only: reads return @@ -245,7 +246,7 @@ Returns 201 with the Session: | `environment.type` | Runs on | Notes | | --- | --- | --- | | `openai_hosted` | A sandbox Core creates (node or E2B) | Optional `network`, `packages`, `files`, `skills`, `plugins`, `setup_commands`, or a template | -| `self_hosted` | Your machine | Requires an absolute `workspace_directory`. The response carries install commands in `x_agents_core.installation`; see [self-hosted execution](/self-hosted-execution) | +| `self_hosted` | Your machine | Requires an absolute `workspace_directory`. Skills, packages, files or a template go in `x_agents_core.environment`. The response carries install commands in `x_agents_core.installation`; see [self-hosted execution](/self-hosted-execution) | | `none` | An existing device connection | `input` required; uses the default model only | ### Session status @@ -301,7 +302,8 @@ oac "/agents/sessions/$SESSION_ID/events" -H "Idempotency-Key: $KEY" -d '{ - **When idle,** a message starts a new Turn. **While a Turn runs,** it joins that Turn (steering); it does not start a parallel task. - **Content** is `input_text`, plus `input_image` as an inline PNG or JPEG data URI. - Images work with Codex and Claude Code, on `none` and Docker sandboxes only. The + Images work with Codex and Claude Code wherever the Runtime supports them; + MiniMax Code rejects them. The whole request is limited to 1 MiB. - Full rules: [message input](https://github.com/MiniMax-AI/parsar-core/blob/f6d258735fc601c521dd990e6f9e1ed261f4ef2d/contracts/agents-api/message-input.md). @@ -520,12 +522,12 @@ Details: [Source Files and Skills](https://github.com/MiniMax-AI/parsar-core/blo ## Environment Templates -A template saves workspace setup for reuse by `openai_hosted` Sessions: +A template saves workspace setup for reuse. `openai_hosted` Sessions reference it in +`environment`; `self_hosted` Sessions in `x_agents_core.environment`: ```python template = client.beta.agents.environments.templates.create( name="python-data", - network={"access": "restricted", "allowed_domains": ["pypi.org", "files.pythonhosted.org"]}, packages={"python": ["pandas"]}, setup_commands=[{"command": "mkdir -p /workspace/outputs"}], ) @@ -533,8 +535,8 @@ template = client.beta.agents.environments.templates.create( | Field | Meaning | | --- | --- | -| `network` | `access`: `enabled`, `disabled`, or `restricted` to 1–100 exact hosts in `allowed_domains`. A Session can only narrow it | -| `packages` | `npm` and `python` packages. `system` packages are rejected: bake them into the image | +| `network` | `access`: `enabled` (default), `disabled`, or `restricted` to 1–100 exact hosts in `allowed_domains`. A Session can only narrow it. Current Runtimes don't enforce `disabled` or `restricted`, so a Session that needs them is rejected; see [restricted network policy](https://github.com/MiniMax-AI/parsar-core/blob/f6d258735fc601c521dd990e6f9e1ed261f4ef2d/contracts/agents-api/environment-templates.md#restricted-network-policy) | +| `packages` | `npm` and `python` packages. `system` packages are rejected: preinstall them in the image or on the machine | | `setup_commands`, `env` | Run and set at preparation. Never returned by reads | | `files`, `skills`, `plugins` | Initial content. Up to 50 files, 10 MiB inline in total | @@ -557,8 +559,16 @@ session = client.beta.agents.sessions.create(environment={"type": "none"}, input The HTTP path is `/vaults`, with the Beta header. A credential is used when an MCP server's URL matches its `mcp_server_url` exactly, or when the tool names its -`credential_id`. Service-origin MCP works with Codex and Claude Code on `none` -Sessions only. +`credential_id`. + +An MCP tool's `connection_origin` decides who connects: + +| `connection_origin` | Connects from | Works with | +| --- | --- | --- | +| `service` (default) | Core's side, for `none` Sessions | Codex and Claude Code | +| `environment` | Inside the workspace (managed or your own machine) | Codex, Claude Code and MiniMax Code. MiniMax Code needs a null allowlist and `required: false` | + +Current rules: [public MCP connection origin](/environments-and-files#public-mcp-connection-origin). ## Limits and differences from OpenAI @@ -569,7 +579,7 @@ Sessions only. | Session create idempotency | Same key returns the original Session | | Event stream | Live only; no replay, `Last-Event-ID` ignored | | Tools | No enabled `web_search`; no multi-agent with functions; MiniMax Code has no public functions | -| Images | Inline PNG/JPEG only; Codex and Claude Code; `none` and Docker sandboxes | +| Images | Inline PNG/JPEG only; Codex and Claude Code; MiniMax Code rejects them | | Packages | `packages.system` rejected | Per-operation status and harness differences are in the diff --git a/apps/docs/content/docs/user-guide.mdx b/apps/docs/content/docs/user-guide.mdx index 9ec7f5346..69655bfc8 100644 --- a/apps/docs/content/docs/user-guide.mdx +++ b/apps/docs/content/docs/user-guide.mdx @@ -108,7 +108,7 @@ snapshot; editing the source later doesn't change a running Session. | To | Use | | --- | --- | | Upload a Skill and pick a version | [Skills](/sessions#skills) | -| Reuse packages, files, setup and network rules | [Environment Templates](/sessions#environment-templates) | +| Reuse packages, files and setup commands | [Environment Templates](/sessions#environment-templates) | | Call your own code from the agent | [Function tools](/sessions#function-tools) | | Connect an MCP server, with credentials | [Execution tools](/agents-and-tools) and [Vaults](/sessions#vaults) | | Use Skill or Plugin directories on your machine | [Local capability directories](/self-hosted-execution#local-capability-directories) | diff --git a/apps/docs/content/guide-sources.json b/apps/docs/content/guide-sources.json index 88522a088..7fa8a418c 100644 --- a/apps/docs/content/guide-sources.json +++ b/apps/docs/content/guide-sources.json @@ -11,8 +11,8 @@ "docs/getting-started/quickstart.md": "b989682ac2e58d59a794118fd371b37d1ea64c957d3512ff53739458a95d0f9a", "docs/api/README.md": "dbe3f172a997ee2fd3d2e5765d382b4fb7cf7c50f1dd17212ab9646f6959d63e", "contracts/agents-api/execution-tools.md": "fe1e3cf471fe9c7ef04afa7230e6b7742fbf2146c74bd944a7a22d5d4d4197da", - "docs/api/public-agent-api.md": "00979732412a971013e8f01b4c74820ff51aafdded6b0f105d25a78af86a6627", - "docs/examples.md": "0e1bdaeff51c9c36779f817be31ea9816b7d8cb2290cf8350d3c4801f436f4f9", + "docs/api/public-agent-api.md": "e1111aaf5215392178246969e281b930374b22ee380d529b08b2482836d6333d", + "docs/examples.md": "c12c34adc5b2fa57c81602b23d8ecc8317596f9c5a4aedbf1f1fe934a08a94f5", "contracts/agents-api/environments.md": "3ec73248afbc04e79e2fd0cb6cf4e6fbc0ff915722df2ee676d2537f30fd43ad", "docs/getting-started/nodes.md": "7c1b7e364ce85b5b5916358cafc618f29042b2125ac45653be665ba07e772fdb", "docs/getting-started/self-hosted.md": "5ade597e09cbfa2e321f341693b47730b3696fe7bd4d6834eafbe6b279a55e6b", @@ -22,7 +22,7 @@ "docs/api/web-management.md": "fe24e883f5745d262d3bd88eb73ae2cbbb723297b9a237f28849f9e3b50dffd4", "contracts/agents-api/runtime-observability-api.md": "cd46e777fe716a7e76374f4655c96dfbad9d8be1bfca6203ed6118ab87874c2b", "docs/getting-started/operations.md": "4069e89deed7ef619f28cc8d9779055669246eabe322089113ac3a786c3cb2d5", - "docs/user-guide.md": "190bea5bfe23b71db3d9437065ee270e07226a89a6e98c668853e5c7f7555529", + "docs/user-guide.md": "bd9049f1f5361dbb643d1174e9445c13a83eac02b17e24bb348f6c8a2ea53654", "docs/assets/development-architecture.png": "24e6d0145d4f16ad70b07b6bc643808a6455aaf6398434d199cf74def200fca6", "docs/development.md": "f5c340253036a2cabc43e22aecdf70522d90280d6511e7649278ae93712ab8b6", "contracts/agents-api/harness-onboarding.md": "e8fceb236e7fb0794eade26639d86b0622ec7dbb1fad90c30f41742c9d029232", @@ -42,8 +42,8 @@ "content/docs/quickstart.mdx": "d0ab9537ab68f6dd3109353e937a29c5d58ec3894b56a52873c9a1d79dfa60a6", "content/docs/public-api.mdx": "cd59f4a661f897d1a9dc6ff08a09f7b7504c355288bbf022eff9b70500a9865c", "content/docs/agents-and-tools.mdx": "3ca16d2e2ff1c759251fbdf6e071ff09a93d5efc7acaca36a48854597d4f9576", - "content/docs/sessions.mdx": "bb63d799ed90038836d652f3f866d0309822425114c6b2aa36654b8a991947f6", - "content/docs/examples.mdx": "587061e65ab2e841d14980539ba94e2216d4e8135c948a852b9a8bb0359c85d7", + "content/docs/sessions.mdx": "e8693563738f690c21be92e0ea09e925528bc85bea2c0fb4799c3f1c4074cfba", + "content/docs/examples.mdx": "5f1dde8043695c40edf775345159d93b2444d5ce6a109829b78678b0b5de0d46", "content/docs/environments-and-files.mdx": "e054c18b22581c3573a6018a9659879ed2776e029d0d12c17e90eb537becb50c", "content/docs/hosted-providers.mdx": "9c241090709a9929ab6a34615db1e20a94c1f36649026281836060e81ac40b4c", "content/docs/self-hosted-execution.mdx": "eeed4c6b3646927ccc3c7ac2d20b2c0f9c8a65e42d734310fe3959e016324e57", @@ -53,7 +53,7 @@ "content/docs/admin-api.mdx": "f43f4f1cac887bc4baa4968d76542a87ba1a6ddeef9259299b53cd98a4aea5e1", "content/docs/observability.mdx": "c81214e1865517a9163c48c7ce7c396f5490c9d162080dfa05fa5ebc147f6c8b", "content/docs/troubleshooting.mdx": "bccd725d2389a80b66caf1a1da80532bd68dd3d470bf851799d0114f84e0af25", - "content/docs/user-guide.mdx": "7c099b2d787ce3d7876889c7cefd621840ec083f267eadf278214a83f11ba274", + "content/docs/user-guide.mdx": "cbe8d7f62666ca229041e7413f254cef051bc93b8abe2aefd94ee77c00fa4c85", "public/images/source/docs/assets/development-architecture.png": "24e6d0145d4f16ad70b07b6bc643808a6455aaf6398434d199cf74def200fca6", "content/docs/development.mdx": "2e5249ddfca571d264e93fd1e0e390a4bd5b0b623bda100cd02f2982929850bb", "content/docs/harness-onboarding.mdx": "8959febf77b2e9e4b16d301eabd8027f09ebd635f2c2713a40d22884afe95d12", diff --git a/apps/docs/scripts/verify-docs-facts.mjs b/apps/docs/scripts/verify-docs-facts.mjs index ccf9b0b4c..fce27c13d 100644 --- a/apps/docs/scripts/verify-docs-facts.mjs +++ b/apps/docs/scripts/verify-docs-facts.mjs @@ -5,6 +5,7 @@ import path from 'node:path' import crypto from 'node:crypto' import assert from 'node:assert/strict' import { fileURLToPath } from 'node:url' +import { execFileSync } from 'node:child_process' const app = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..') const repo = path.resolve(app, '../..') const record = JSON.parse(fs.readFileSync(path.join(app, 'content/guide-sources.json'))) @@ -26,5 +27,21 @@ 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) } +// Retired behavior must not reappear in any authored or generated surface. +// Each claim contradicts its current owner; update the owner, not this list. +const retiredClaims = [ + ['it has no implicit deployment default', 'contracts/agents-api/model-execution.md#deployment-defaults'], + ['Sessions must name `agent.model`', 'contracts/agents-api/model-execution.md#deployment-defaults'], + ['automatically adapted by Runtime', 'contracts/agents-api/model-execution.md (native protocols only)'], + ['`none` and Docker sandboxes only', 'contracts/agents-api/message-input.md'], + ['当前 Core 不接受托管 Skill 引用', 'contracts/agents-api/environments.md (x_agents_core.environment)'], +] +// Provenance and historical protocol evaluations keep their original wording. +const historical = /^provenance\/|\/model-protocol-[^/]*\.md$|verify-docs-facts\.mjs$/ +const tracked = execFileSync('git', ['ls-files', '-z', '--', '*.md', '*.mdx', '*.yaml', '*.json', '*.ts', '*.tsx', '*.mjs', '*.go'], { cwd: repo, encoding: 'utf8' }).split('\0').filter(n => n && !historical.test(n)) +for (const file of tracked) { + const text = fs.readFileSync(path.join(repo, file), 'utf8') + for (const [claim, owner] of retiredClaims) assert.ok(!text.includes(claim), `Retired claim in ${file}: "${claim}". Current rule: ${owner}`) +} 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/apps/web/src/i18n/locales/en/keys.ts b/apps/web/src/i18n/locales/en/keys.ts index 7f570e878..ca4ce7c82 100644 --- a/apps/web/src/i18n/locales/en/keys.ts +++ b/apps/web/src/i18n/locales/en/keys.ts @@ -109,7 +109,7 @@ export const keys = { failed: "The API address couldn't be read.", localOnly: "For access from other machines, configure a domain and HTTPS in System.", noAddress: "Core has no public API address yet. Configure a domain and HTTPS in System.", - model: "To create a Session, replace {{model}} with a model name your model provider serves. Running an Agent needs a model provider: pass one in each request, save one on the Agent, or rely on the deployment default.", + model: "Replace {{model}} with a model name your model provider serves, or remove the model field to use this deployment's default model configuration. Running an Agent needs a model provider: pass one in each request, save one on the Agent, or rely on the deployment default. Self-hosted Sessions never use the deployment default.", keyPlaceholder: "", projectKey: "Set OPENAI_API_KEY to an API key issued for this project. A key is shown only once, when it is issued; if it's lost, issue a new one.", projectHelp: "Samples for applications that call the Agents API with this project's API keys. The console never sends these requests.", diff --git a/apps/web/src/i18n/locales/en/sessions.ts b/apps/web/src/i18n/locales/en/sessions.ts index 19686565e..d797b941c 100644 --- a/apps/web/src/i18n/locales/en/sessions.ts +++ b/apps/web/src/i18n/locales/en/sessions.ts @@ -302,7 +302,6 @@ export const sessions = { supportedTextParts: "User message {{number}} must contain supported text parts.", nonblankTextParts: "User message {{number}} needs nonblank text across its parts.", atLeastOneTextPart: "User message {{number}} needs at least one text part.", - inlineModelRequired: "Enter a model ID for the inline Agent.", selectSavedAgent: "Select a saved Agent before configuring Session-only overrides.", nonemptyModelOverride: "Enter a non-empty Session model override.", inlineMustNotSendId: "Inline Session creation must not send agent_id.", diff --git a/apps/web/src/i18n/locales/zh-CN/keys.ts b/apps/web/src/i18n/locales/zh-CN/keys.ts index 1b4ac4bf8..00cc62a1f 100644 --- a/apps/web/src/i18n/locales/zh-CN/keys.ts +++ b/apps/web/src/i18n/locales/zh-CN/keys.ts @@ -111,7 +111,7 @@ export const keys: TranslationShape = { failed: "无法读取 API 地址。", localOnly: "从其他机器调用前,请先在系统中配置域名与 HTTPS。", noAddress: "Core 尚未配置公开 API 地址,请在系统中配置域名与 HTTPS。", - model: "创建 Session 时,把 {{model}} 换成模型服务提供的模型名。运行 Agent 需要模型服务:在每个请求里传入、保存在 Agent 上,或使用部署默认值。", + model: "把 {{model}} 换成模型服务提供的模型名;也可以删掉 model 字段,使用本部署的默认模型配置。运行 Agent 需要模型服务:在每个请求里传入、保存在 Agent 上,或使用部署默认值。自托管 Session 不使用部署默认值。", keyPlaceholder: "<项目 API key>", projectKey: "把 OPENAI_API_KEY 设为这个项目签发的 API key。key 只在签发时显示一次;丢失后请签发新 key。", projectHelp: "应用用这个项目的 API key 调用 Agents API 的示例。控制台不会发送这些请求。", diff --git a/apps/web/src/i18n/locales/zh-CN/sessions.ts b/apps/web/src/i18n/locales/zh-CN/sessions.ts index 18cd5046f..e05e49a93 100644 --- a/apps/web/src/i18n/locales/zh-CN/sessions.ts +++ b/apps/web/src/i18n/locales/zh-CN/sessions.ts @@ -303,7 +303,6 @@ export const sessions = { supportedTextParts: "用户消息 {{number}} 必须包含受支持的文本片段。", nonblankTextParts: "用户消息 {{number}} 的文本片段中必须包含非空文本。", atLeastOneTextPart: "用户消息 {{number}} 至少需要一个文本片段。", - inlineModelRequired: "请输入内联 Agent 的模型 ID。", selectSavedAgent: "配置 Session 专用覆盖项前,请先选择已保存的 Agent。", nonemptyModelOverride: "请输入非空的 Session 模型覆盖值。", inlineMustNotSendId: "创建内联 Agent Session 时不得发送 agent_id。", diff --git a/contracts/agents-api/execution-configuration.md b/contracts/agents-api/execution-configuration.md index 80725071f..72e0a1a4f 100644 --- a/contracts/agents-api/execution-configuration.md +++ b/contracts/agents-api/execution-configuration.md @@ -36,8 +36,9 @@ returns: sources are independent; a model-only override can retain an Agent's harness and whole provider bundle. Explicit inline harness selection is `session`; a null inline Agent extension resets the harness to `deployment` without clearing the -inherited provider. A null Session provider inherits normally. Model is required -inline or inherited from a saved Agent; it has no implicit deployment default. +inherited provider. A null Session provider inherits normally. The model may come +from the Session, a saved Agent or the deployment default; which Sessions may omit +it is owned by [model execution](model-execution.md#deployment-defaults). The provider's `status` describes visibility: diff --git a/docs/api/public-agent-api.md b/docs/api/public-agent-api.md index 1207753d6..df311a662 100644 --- a/docs/api/public-agent-api.md +++ b/docs/api/public-agent-api.md @@ -143,6 +143,7 @@ only additions to the OpenAI shapes, and they sit inside `x_agents_core`: | `harness` | Agent, or a Session's inline `agent` | `codex`, `claude_sdk` or `mcode` | | `model_provider` | Agent, or Session creation (top level) | `protocol`, `base_url`, `api_key`, and for `mcode` also `context_window` and `max_output_tokens`. The protocol must be one the harness supports: Codex `responses`, Claude Code `anthropic`, MiniMax Code any of `anthropic`, `responses`, `chat_completions` | | `harness_config` | Agent, inline `agent`, or Session creation (top level, wins) | The harness's native model parameters, such as Codex's `model_reasoning_effort` | +| `environment` | Session creation (top level), any placement | Portable preparation: `environment_template_id`, `files`, `env`, `packages`, `setup_commands`, `skills`, `plugins`, `capability_directories`. A field may not also appear in `environment`; see [Environments](../../contracts/agents-api/environments.md#preparation-order) | | `installation` | Read-only, on `self_hosted` Sessions | Short-lived install commands for your machine; see [self-hosted execution](../getting-started/self-hosted.md) | Any other member is rejected with 400. `api_key` is write-only: reads return @@ -242,7 +243,7 @@ Returns 201 with the Session: | `environment.type` | Runs on | Notes | | --- | --- | --- | | `openai_hosted` | A sandbox Core creates (node or E2B) | Optional `network`, `packages`, `files`, `skills`, `plugins`, `setup_commands`, or a template | -| `self_hosted` | Your machine | Requires an absolute `workspace_directory`. The response carries install commands in `x_agents_core.installation`; see [self-hosted execution](../getting-started/self-hosted.md) | +| `self_hosted` | Your machine | Requires an absolute `workspace_directory`. Skills, packages, files or a template go in `x_agents_core.environment`. The response carries install commands in `x_agents_core.installation`; see [self-hosted execution](../getting-started/self-hosted.md) | | `none` | An existing device connection | `input` required; uses the default model only | ### Session status @@ -298,7 +299,8 @@ oac "/agents/sessions/$SESSION_ID/events" -H "Idempotency-Key: $KEY" -d '{ - **When idle,** a message starts a new Turn. **While a Turn runs,** it joins that Turn (steering); it does not start a parallel task. - **Content** is `input_text`, plus `input_image` as an inline PNG or JPEG data URI. - Images work with Codex and Claude Code, on `none` and Docker sandboxes only. The + Images work with Codex and Claude Code wherever the Runtime supports them; + MiniMax Code rejects them. The whole request is limited to 1 MiB. - Full rules: [message input](../../contracts/agents-api/message-input.md). @@ -517,12 +519,12 @@ Details: [Source Files and Skills](../../contracts/agents-api/source-files.md). ## Environment Templates -A template saves workspace setup for reuse by `openai_hosted` Sessions: +A template saves workspace setup for reuse. `openai_hosted` Sessions reference it in +`environment`; `self_hosted` Sessions in `x_agents_core.environment`: ```python template = client.beta.agents.environments.templates.create( name="python-data", - network={"access": "restricted", "allowed_domains": ["pypi.org", "files.pythonhosted.org"]}, packages={"python": ["pandas"]}, setup_commands=[{"command": "mkdir -p /workspace/outputs"}], ) @@ -530,8 +532,8 @@ template = client.beta.agents.environments.templates.create( | Field | Meaning | | --- | --- | -| `network` | `access`: `enabled`, `disabled`, or `restricted` to 1–100 exact hosts in `allowed_domains`. A Session can only narrow it | -| `packages` | `npm` and `python` packages. `system` packages are rejected: bake them into the image | +| `network` | `access`: `enabled` (default), `disabled`, or `restricted` to 1–100 exact hosts in `allowed_domains`. A Session can only narrow it. Current Runtimes don't enforce `disabled` or `restricted`, so a Session that needs them is rejected; see [restricted network policy](../../contracts/agents-api/environment-templates.md#restricted-network-policy) | +| `packages` | `npm` and `python` packages. `system` packages are rejected: preinstall them in the image or on the machine | | `setup_commands`, `env` | Run and set at preparation. Never returned by reads | | `files`, `skills`, `plugins` | Initial content. Up to 50 files, 10 MiB inline in total | @@ -554,8 +556,16 @@ session = client.beta.agents.sessions.create(environment={"type": "none"}, input The HTTP path is `/vaults`, with the Beta header. A credential is used when an MCP server's URL matches its `mcp_server_url` exactly, or when the tool names its -`credential_id`. Service-origin MCP works with Codex and Claude Code on `none` -Sessions only. +`credential_id`. + +An MCP tool's `connection_origin` decides who connects: + +| `connection_origin` | Connects from | Works with | +| --- | --- | --- | +| `service` (default) | Core's side, for `none` Sessions | Codex and Claude Code | +| `environment` | Inside the workspace (managed or your own machine) | Codex, Claude Code and MiniMax Code. MiniMax Code needs a null allowlist and `required: false` | + +Current rules: [public MCP connection origin](../../contracts/agents-api/environments.md#public-mcp-connection-origin). ## Limits and differences from OpenAI @@ -566,7 +576,7 @@ Sessions only. | Session create idempotency | Same key returns the original Session | | Event stream | Live only; no replay, `Last-Event-ID` ignored | | Tools | No enabled `web_search`; no multi-agent with functions; MiniMax Code has no public functions | -| Images | Inline PNG/JPEG only; Codex and Claude Code; `none` and Docker sandboxes | +| Images | Inline PNG/JPEG only; Codex and Claude Code; MiniMax Code rejects them | | Packages | `packages.system` rejected | Per-operation status and harness differences are in the diff --git a/docs/examples.md b/docs/examples.md index 38ca63672..91010175f 100644 --- a/docs/examples.md +++ b/docs/examples.md @@ -48,8 +48,9 @@ Each feature maps to one part of the API. Read the code next to the guide sectio ### Not covered -Vaults and MCP authentication, OAuth, Session deletion, and MiniMax Code on your -own machine. +Vaults and MCP authentication, OAuth, Session deletion, MiniMax Code on your own +machine, and managed Skills or templates on your own machine +(`x_agents_core.environment`). ## Add an example diff --git a/docs/user-guide.md b/docs/user-guide.md index a8780006c..3cfb3d832 100644 --- a/docs/user-guide.md +++ b/docs/user-guide.md @@ -105,7 +105,7 @@ snapshot; editing the source later doesn't change a running Session. | To | Use | | --- | --- | | Upload a Skill and pick a version | [Skills](api/public-agent-api.md#skills) | -| Reuse packages, files, setup and network rules | [Environment Templates](api/public-agent-api.md#environment-templates) | +| Reuse packages, files and setup commands | [Environment Templates](api/public-agent-api.md#environment-templates) | | Call your own code from the agent | [Function tools](api/public-agent-api.md#function-tools) | | Connect an MCP server, with credentials | [Execution tools](../contracts/agents-api/execution-tools.md) and [Vaults](api/public-agent-api.md#vaults) | | Use Skill or Plugin directories on your machine | [Local capability directories](getting-started/self-hosted.md#local-capability-directories) | diff --git a/example/parsar/README.md b/example/parsar/README.md index d795cf169..be5d87dec 100644 --- a/example/parsar/README.md +++ b/example/parsar/README.md @@ -102,8 +102,10 @@ A few more implementation details: running Session. - **Workspaces:** hosted Sessions each get their own. User-machine Sessions use the selected host directory, so the same path means shared files. -- **Skills on a user machine** come only from local capability directories; managed - Skill references are rejected explicitly, not ignored. +- **Skills on a user machine** come only from local capability directories in this + example; it rejects Agents bound to managed Skills instead of ignoring them. Core + itself can deliver managed Skills to user machines through + `x_agents_core.environment`. ## Validation diff --git a/example/parsar/server/sessions.mjs b/example/parsar/server/sessions.mjs index d275e05a8..30a73eed2 100644 --- a/example/parsar/server/sessions.mjs +++ b/example/parsar/server/sessions.mjs @@ -19,7 +19,7 @@ function requestFor(store, id, body) { if (agent.skill_ids.length) throw new AppError( 400, - "用户机器使用本地能力目录,当前 Core 不接受托管 Skill 引用。请使用未绑定托管 Skill 的 Agent,并在运行时填写本地能力目录。", + "此示例的用户机器只使用本地能力目录,暂不传递托管 Skill。请使用未绑定托管 Skill 的 Agent,并在运行时填写本地能力目录。", ); if (mcps.length) throw new AppError( diff --git a/services/agents-api/internal/api/session_agent.go b/services/agents-api/internal/api/session_agent.go index c1a6c8cdc..aa9be76b0 100644 --- a/services/agents-api/internal/api/session_agent.go +++ b/services/agents-api/internal/api/session_agent.go @@ -28,7 +28,7 @@ func resolveSessionAgent(input sessionRequest, saved *v1.SavedAgent) (v1.Agent, request.Model = &saved.Model } if request.Model == nil { - return v1.Agent{}, errors.New("agent.model is required without agent_id.") + return v1.Agent{}, errors.New("agent.model is required without agent_id unless a deployment default model applies.") } resolved, err := resolveSavedAgent(request) if err != nil {