From 0ac33acf549eef596d77b737d6d5e3bebe1c2585 Mon Sep 17 00:00:00 2001 From: Him188 Date: Thu, 6 Aug 2026 17:38:34 +0900 Subject: [PATCH 1/3] =?UTF-8?q?docs:=20session=20overrides=20=E2=80=94=20f?= =?UTF-8?q?ield=20reference,=20voice=5Fid=20rename,=20public=20cap?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Document the overridable fields in the session-creation flow (previously just "an object gated by an allowlist"), and align with the API revision: voice_profile_id → voice_id everywhere, first_message_prompt added, top-level language sugar removed from the wire (SDK option folds into overrides), public sessions capped to language + voice_id. The per-agent allowlist setting stays undocumented; pages describe the 400 behavior only. Co-Authored-By: Claude Fable 5 --- agents/build/configuration.mdx | 4 +- agents/build/dynamic-variables.mdx | 16 +++--- agents/build/voice-language.mdx | 6 ++- agents/deploy/authenticated-sessions.mdx | 32 ++++++++++-- agents/deploy/public-agents.mdx | 2 +- agents/deploy/react-sdk.mdx | 2 +- agents/deploy/web-sdk.mdx | 2 +- agents/deploy/widget.mdx | 32 ++++++------ agents/quickstart.mdx | 4 +- api-reference/agent-errors.mdx | 2 +- api-reference/openapi.json | 62 +++++++++++------------- 11 files changed, 92 insertions(+), 72 deletions(-) diff --git a/agents/build/configuration.mdx b/agents/build/configuration.mdx index 9190330..fdf9166 100644 --- a/agents/build/configuration.mdx +++ b/agents/build/configuration.mdx @@ -32,7 +32,7 @@ Choose how the agent opens each conversation: ## Voice -The Voice panel selects the voice profile your agent speaks with (`voice_profile_id`) and its speaking language (`speaking_language`: `en`, `ja`, `zh`, `ko`, `es`, `fr`, `de`). See [Voice & language](/agents/build/voice-language) for picking a voice and how automatic language detection interacts with this setting. +The Voice panel selects the voice your agent speaks with (`voice_id`) and its speaking language (`speaking_language`: `en`, `ja`, `zh`, `ko`, `es`, `fr`, `de`). See [Voice & language](/agents/build/voice-language) for picking a voice and how automatic language detection interacts with this setting. ## Conversation settings @@ -94,7 +94,7 @@ curl --request GET "https://api.fish.audio/v1/agent/agents/$AGENT_ID/config" \ "first_message": "Hi, thanks for calling Acme. How can I help?" }, "voice": { - "voice_profile_id": "802e3bc2b27e49c2995d23ef70e6ac89", + "voice_id": "802e3bc2b27e49c2995d23ef70e6ac89", "speaking_language": "en" }, "conversation": { diff --git a/agents/build/dynamic-variables.mdx b/agents/build/dynamic-variables.mdx index a05d5a9..586f716 100644 --- a/agents/build/dynamic-variables.mdx +++ b/agents/build/dynamic-variables.mdx @@ -6,10 +6,10 @@ icon: "brackets-curly" An agent's published configuration is shared by every caller — but each session can be personalized at creation time. Two mechanisms cover this, and both travel in the same `POST /v1/agent/sessions` request: -| Mechanism | What it does | Gated by | +| Mechanism | What it does | Scope | |---|---|---| -| `dynamic_variables` | Fills `{{placeholder}}` templates in your configuration text | Nothing per-agent — no allowlist | -| `overrides` | Replaces whole configuration fields for this session | Per-agent allowlist of overridable fields | +| `dynamic_variables` | Fills `{{placeholder}}` templates in your configuration text | Any placeholder you define | +| `overrides` | Replaces whole configuration fields for this session | Four overridable fields | ## Dynamic variables @@ -62,7 +62,7 @@ You don't need a variable for the current date or time — the agent already kno ## Overrides -Overrides replace configuration fields wholesale for one session — for example, forcing a different language for a caller. Because they change agent behavior, each agent declares which fields callers may override; everything else is rejected. +Overrides replace configuration fields wholesale for one session — for example, forcing a different language for a caller. The overridable fields are `first_message` (or its generated twin `first_message_prompt`), `system_prompt`, `voice_id`, and `language` — the full table with types, limits, and exactly what each replaces is in [Authenticated sessions](/agents/deploy/authenticated-sessions#overrides). ```bash API (curl) @@ -87,17 +87,17 @@ const session = await AgentSession.start({ ### The `language` shorthand -Overriding the session language is common enough that the request accepts a top-level `language` field as shorthand for `overrides.language`. Both forms pass through the same allowlist gate — if `language` is not overridable on the agent, both are rejected. +Overriding the session language is common enough that the SDKs accept a top-level `language` option — the widget takes it as an attribute — and fold it into `overrides.language` for you. On the wire there is only one spelling: ```json -{ "agent_id": "YOUR_AGENT_ID", "language": "ja" } +{ "agent_id": "YOUR_AGENT_ID", "overrides": { "language": "ja" } } ``` ### Validation | Case | Result | |---|---| -| Override field not on the agent's allowlist | `400` | +| Override field not enabled for the agent | `400` | | Unknown field inside `overrides` | `422` | | Unknown top-level field in the request | `422` | @@ -134,7 +134,7 @@ const sessionToken = await response.json(); // pass to AgentSession.start({ sess ``` -In `agentId` mode, values arrive from the end user's browser — treat them as untrusted input. Keep the override allowlist limited to fields you are comfortable letting anyone set, and use `sessionToken` mode when personalization must come from data only your backend knows. +In `agentId` mode, values arrive from the end user's browser — treat them as untrusted input, and use `sessionToken` mode when personalization must come from data only your backend knows. Public sessions accept only the `language` and `voice_id` overrides; the prompt-shaping fields require a backend-created session. ## Going further diff --git a/agents/build/voice-language.mdx b/agents/build/voice-language.mdx index 716affa..ff8e831 100644 --- a/agents/build/voice-language.mdx +++ b/agents/build/voice-language.mdx @@ -39,7 +39,7 @@ The voice picker on the **Configuration** page has two levels: a curated list fo ## Use any voice model -The agent's voice is a **voice model id** (`voice_profile_id`) — the same ids used as `reference_id` in [Text to Speech](/features/text-to-speech). Any public voice model from the Voice Library works, including: +The agent's voice is a **voice model id** (`voice_id`) — the same ids used as `reference_id` in [Text to Speech](/features/text-to-speech). Any public voice model from the Voice Library works, including: - **Library voices** — ready-made public voices. Find ids in the [Voice Library](/features/manage-voices). - **Your cloned voices** — [clone a voice](/features/voice-cloning) once, then use its model id as your agent's voice. @@ -55,7 +55,7 @@ curl --request PATCH "https://api.fish.audio/v1/agent/agents/$AGENT_ID/config" \ --header "Content-Type: application/json" \ --data '{ "voice": { - "voice_profile_id": "802e3bc2b27e49c2995d23ef70e6ac89" + "voice_id": "802e3bc2b27e49c2995d23ef70e6ac89" } }' ``` @@ -80,6 +80,8 @@ curl --request PATCH "https://api.fish.audio/v1/agent/agents/$AGENT_ID/config" \ The voice model and the speaking language are independent settings: picking a voice does not change the language, and vice versa. Choose a voice that sounds natural in the language you configure. +Both settings can also be replaced for a single session — send `overrides.voice_id` or `overrides.language` on the session request. See [Overrides](/agents/deploy/authenticated-sessions#overrides). + ## Going further diff --git a/agents/deploy/authenticated-sessions.mdx b/agents/deploy/authenticated-sessions.mdx index c004714..8417915 100644 --- a/agents/deploy/authenticated-sessions.mdx +++ b/agents/deploy/authenticated-sessions.mdx @@ -119,8 +119,7 @@ More on what the SDK can do once connected is in the [Web SDK](/agents/deploy/we | ------------------- | ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `agent_id` | string, required | The agent to talk to. It must have a [published version](/agents/deploy/versions-publishing). | | `name` | string, optional | Display name for this session in the console's Conversations list, up to 128 characters. Omit it to show the session's start time instead. API-key requests only — keyless (public) creation rejects it with `400`. | -| `language` | string, optional | Shorthand for `overrides.language`; subject to the same override allow-list. See [Voice & language](/agents/build/voice-language). | -| `overrides` | object, optional | Per-session config overrides. Each field must be enabled in the agent's override allow-list — unauthorized fields are rejected with `400`. | +| `overrides` | object, optional | Replace parts of the published configuration for this session — see [Overrides](#overrides). | | `dynamic_variables` | object, optional | Up to 50 entries of string, number, or boolean values, substituted into `{{placeholders}}`. See [Dynamic variables](/agents/build/dynamic-variables). | | `tool_events` | boolean, optional | Stream tool lifecycle events (`toolCallStarted` / `toolCallCompleted` / `toolCallFailed`) to the client. Default `true`; set `false` to keep tool inputs and outputs off the client. | | `end_user_id` | string, optional | Your identifier for the end user, for attribution in [conversation history](/agents/monitor/conversation-history). | @@ -132,6 +131,33 @@ More on what the SDK can do once connected is in the [Web SDK](/agents/deploy/we Unknown fields — top-level or inside `overrides` — are rejected with `422`. +## Overrides + +`overrides` replaces parts of the agent's published configuration for one session — the agent itself never changes: + +| Field | Type | Effect for this session | +| ---------------------- | ---------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `first_message` | string, up to 10,000 characters | The agent opens with exactly this text, spoken verbatim — whatever first-message mode the configuration sets. `{{placeholders}}` render inside it. | +| `first_message_prompt` | string, up to 10,000 characters | Instructions the agent generates its opener from, replacing the configured first-message behavior. `{{placeholders}}` render inside it. Mutually exclusive with `first_message` — sending both is `422`. | +| `system_prompt` | string, up to 8,000 characters | Replaces the configured system prompt entirely. `{{placeholders}}` render inside it. | +| `voice_id` | string | The voice the agent speaks with — any [voice model id](/agents/build/voice-language#use-any-voice-model) from the Voice Library. Voices bias pronunciation toward their own language, so pair it with `language`. | +| `language` | `en`, `ja`, `zh`, `ko`, `es`, `fr`, `de` | Pins the conversation language, taking precedence over the configured [speaking language](/agents/build/voice-language#speaking-language) and automatic language detection. | + +```json +{ + "agent_id": "YOUR_AGENT_ID", + "overrides": { + "first_message": "Welcome back, {{name}} — picking up where we left off.", + "voice_id": "802e3bc2b27e49c2995d23ef70e6ac89", + "language": "ja" + } +} +``` + +On [public agents](/agents/deploy/public-agents), keyless (browser-created) sessions may override only `language` and `voice_id` — the prompt-shaping fields are rejected with `400` regardless of the agent. Create the session from your backend to use them. + +Everything else on the request is not an override: `dynamic_variables`, `timezone`, `record_audio`, and `tool_events` are separate top-level fields. Session length is not settable per session — `max_duration_seconds` comes from the agent's [conversation configuration](/agents/build/configuration#call-duration). + ## Response ```json JSON @@ -187,7 +213,7 @@ Session creation fails with standard HTTP statuses; the SDK surfaces them as a ` | Status | Meaning | | ------ | --------------------------------------------------------------------------------------------------------------------------------------------- | -| `400` | An `overrides` field is not on the agent's override allow-list. | +| `400` | An `overrides` field is not enabled for this agent, or a keyless request sent an override [public sessions don't accept](#overrides). | | `401` | Invalid API key. A request with no `Authorization` header at all is treated as a public-agent request instead. | | `402` | Quota exceeded. | | `403` | Public-agent request rejected: the agent is not public, or the page's `Origin` is not on the allow-list. | diff --git a/agents/deploy/public-agents.mdx b/agents/deploy/public-agents.mdx index 3aebb00..626aaea 100644 --- a/agents/deploy/public-agents.mdx +++ b/agents/deploy/public-agents.mdx @@ -92,7 +92,7 @@ Public session creation is rate limited on two dimensions at once: per **client ## Treat public input as untrusted -On the public path, the entire session request originates in the visitor's browser. The platform enforces its own guardrails — `overrides` are filtered against the agent's allowlist and unauthorized fields are rejected with `400` — but anything that passes through verbatim is attacker-controllable: +On the public path, the entire session request originates in the visitor's browser. The platform enforces its own guardrails — public sessions accept only the `language` and `voice_id` [overrides](/agents/deploy/authenticated-sessions#overrides), rejecting everything else with `400` — but anything that passes through verbatim is attacker-controllable: - **`metadata`** is stored and returned exactly as sent, never interpreted by the platform. When you read it back in [conversation history](/agents/monitor/conversation-history) or [webhooks](/agents/monitor/webhooks), treat it as untrusted data — never as proof of who the visitor is. - **`dynamic_variables`** are chosen by the page that starts the session. Don't inject anything through them that the visitor shouldn't control. See [Dynamic variables](/agents/build/dynamic-variables). diff --git a/agents/deploy/react-sdk.mdx b/agents/deploy/react-sdk.mdx index 05a3ec4..3a16662 100644 --- a/agents/deploy/react-sdk.mdx +++ b/agents/deploy/react-sdk.mdx @@ -103,7 +103,7 @@ const sessionToken = await res.json(); await startSession({ sessionToken }); ``` -See [Authenticated sessions](/agents/deploy/authenticated-sessions) for the backend side. `startSession` accepts the same options as `AgentSession.start` in the [Web SDK](/agents/deploy/web-sdk), including [`clientTools`](/agents/build/client-tools). Session settings such as `overrides` and `dynamicVariables` apply when you connect with an `agentId`; with a `sessionToken`, your backend sets them in its session-creation request instead. +See [Authenticated sessions](/agents/deploy/authenticated-sessions) for the backend side. `startSession` accepts the same options as `AgentSession.start` in the [Web SDK](/agents/deploy/web-sdk), including [`clientTools`](/agents/build/client-tools). Session settings such as [`overrides`](/agents/deploy/authenticated-sessions#overrides) and `dynamicVariables` apply when you connect with an `agentId`; with a `sessionToken`, your backend sets them in its session-creation request instead. ## What `useConversation` returns diff --git a/agents/deploy/web-sdk.mdx b/agents/deploy/web-sdk.mdx index 9d18ad9..bb91f83 100644 --- a/agents/deploy/web-sdk.mdx +++ b/agents/deploy/web-sdk.mdx @@ -61,7 +61,7 @@ const session = await AgentSession.start({ sessionToken }); | -------------------------- | --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `agentId` / `sessionToken` | — | One of the two, required | | `clientTools` | `Record` | Handlers for [client tools](/agents/build/client-tools) declared on the agent | -| `overrides` | `SessionOverrides` | Per-session config overrides (`agentId` mode only — with `sessionToken`, your backend sends them when creating the session) | +| `overrides` | `SessionOverrides` | Per-session config [overrides](/agents/deploy/authenticated-sessions#overrides) — `first_message`, `first_message_prompt`, `system_prompt`, `voice_id`, `language` (`agentId` mode only — with `sessionToken`, your backend sends them when creating the session) | | `dynamicVariables` | `Record` | Values for `{{placeholders}}` in the agent config — see [Dynamic variables](/agents/build/dynamic-variables) | | `language` | `string` | Shorthand for overriding the agent's language | | `toolEvents` | `boolean` | Whether tool lifecycle events reach this client (default `true`; `agentId` mode only — with `sessionToken`, your backend sets `tool_events`) | diff --git a/agents/deploy/widget.mdx b/agents/deploy/widget.mdx index 98a9274..2219bf0 100644 --- a/agents/deploy/widget.mdx +++ b/agents/deploy/widget.mdx @@ -56,22 +56,22 @@ Every attribute below has a camelCase prop; `dynamicVariables` and `textContents ## Attributes -| Attribute | Description | -| --------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- | -| `agent-id` | Public agent ID. Required unless the `sessionTokenProvider` property is set — see [Private agents](#private-agents). | -| `agent-name` | Display name in the header. | -| `greeting` | Home-screen headline. | -| `proactive-message` | Enables the attention bubble next to the launcher. | -| `proactive-delay` | Seconds before the bubble shows. Default `3`. | -| `transcript` / `text-input` / `mic-muting` | Feature switches, on by default; set `"false"` to disable. | -| `consent` | `"true"` shows a first-run terms card (default off). Acceptance is remembered in `localStorage`. | -| `consent-text`, `terms-url`, `privacy-url`, `consent-key` | Consent copy, linked policies, and the `localStorage` key (default `fish-agent-consent`). | -| `position` | `bottom-right` (default), `bottom-left`, `top-right`, `top-left`. | -| `language` | Pin the session language, subject to the agent's override allowlist. See [Voice & language](/agents/build/voice-language). | -| `dynamic-variables` | JSON object of `{{name}}` template values. See [Dynamic variables](/agents/build/dynamic-variables). | -| `user-id` | Your end-user identifier, stored on the session. | -| `server-url` | Fish API base override. Default `https://api.fish.audio`. | -| `text-contents` | JSON overriding any UI string (keys in `DEFAULT_TEXTS` of `@fishaudio/agent-widget`). | +| Attribute | Description | +| --------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- | +| `agent-id` | Public agent ID. Required unless the `sessionTokenProvider` property is set — see [Private agents](#private-agents). | +| `agent-name` | Display name in the header. | +| `greeting` | Home-screen headline. | +| `proactive-message` | Enables the attention bubble next to the launcher. | +| `proactive-delay` | Seconds before the bubble shows. Default `3`. | +| `transcript` / `text-input` / `mic-muting` | Feature switches, on by default; set `"false"` to disable. | +| `consent` | `"true"` shows a first-run terms card (default off). Acceptance is remembered in `localStorage`. | +| `consent-text`, `terms-url`, `privacy-url`, `consent-key` | Consent copy, linked policies, and the `localStorage` key (default `fish-agent-consent`). | +| `position` | `bottom-right` (default), `bottom-left`, `top-right`, `top-left`. | +| `language` | Pin the session language — see [Overrides](/agents/deploy/authenticated-sessions#overrides). | +| `dynamic-variables` | JSON object of `{{name}}` template values. See [Dynamic variables](/agents/build/dynamic-variables). | +| `user-id` | Your end-user identifier, stored on the session. | +| `server-url` | Fish API base override. Default `https://api.fish.audio`. | +| `text-contents` | JSON overriding any UI string (keys in `DEFAULT_TEXTS` of `@fishaudio/agent-widget`). | ## Private agents diff --git a/agents/quickstart.mdx b/agents/quickstart.mdx index 280aa6f..dfa84f8 100644 --- a/agents/quickstart.mdx +++ b/agents/quickstart.mdx @@ -54,13 +54,13 @@ Build a voice agent and talk to it in a few minutes. Use the console for a no-co "system_prompt": "You are a friendly support agent for Acme. Keep answers short and conversational." }, "voice": { - "voice_profile_id": "802e3bc2b27e49c2995d23ef70e6ac89" + "voice_id": "802e3bc2b27e49c2995d23ef70e6ac89" } } }' ``` - The response includes the agent's `agent_id` — use it as `$AGENT_ID` below. `voice_profile_id` accepts any voice model id from the [Voice Library](/features/manage-voices). + The response includes the agent's `agent_id` — use it as `$AGENT_ID` below. `voice_id` accepts any voice model id from the [Voice Library](/features/manage-voices). `system_prompt` is limited to 4,000 characters; longer prompts return `422`. diff --git a/api-reference/agent-errors.mdx b/api-reference/agent-errors.mdx index 846d5ee..9089300 100644 --- a/api-reference/agent-errors.mdx +++ b/api-reference/agent-errors.mdx @@ -46,7 +46,7 @@ The exceptions to that shape: ## 400 vs 422 -`422` is field-level validation: unknown fields (the public surface rejects them), length caps, enum values, invalid IANA timezones, dynamic-variable naming. `400` is semantic: an override not on the agent's allow-list, mutually exclusive pagination parameters (`page` + `cursor`), an undecodable cursor, a page offset past 100,000 rows, or a knowledge upload that isn't UTF-8 plain text. +`422` is field-level validation: unknown fields (the public surface rejects them), length caps, enum values, invalid IANA timezones, dynamic-variable naming. `400` is semantic: an [override](/agents/deploy/authenticated-sessions#overrides) not enabled for the agent, mutually exclusive pagination parameters (`page` + `cursor`), an undecodable cursor, a page offset past 100,000 rows, or a knowledge upload that isn't UTF-8 plain text. Two quirks worth coding around: diff --git a/api-reference/openapi.json b/api-reference/openapi.json index c763d96..b75d809 100644 --- a/api-reference/openapi.json +++ b/api-reference/openapi.json @@ -1885,7 +1885,7 @@ "enum": [ "first_message", "system_prompt", - "voice_profile_id", + "voice_id", "language" ], "type": "string" @@ -2026,7 +2026,7 @@ { "lang": "bash", "label": "Create Agent", - "source": "curl --request POST \\\n --url https://api.fish.audio/v1/agent/agents \\\n --header 'Authorization: Bearer ' \\\n --header 'Content-Type: application/json' \\\n --data '{\n \"name\": \"Receptionist\",\n \"description\": \"Handles inbound calls.\",\n \"config\": {\n \"prompt\": {\n \"system_prompt\": \"You are the receptionist for Fish Dental.\"\n },\n \"voice\": {\n \"voice_profile_id\": \"\",\n \"speaking_language\": \"en\"\n }\n }\n }'" + "source": "curl --request POST \\\n --url https://api.fish.audio/v1/agent/agents \\\n --header 'Authorization: Bearer ' \\\n --header 'Content-Type: application/json' \\\n --data '{\n \"name\": \"Receptionist\",\n \"description\": \"Handles inbound calls.\",\n \"config\": {\n \"prompt\": {\n \"system_prompt\": \"You are the receptionist for Fish Dental.\"\n },\n \"voice\": {\n \"voice_id\": \"\",\n \"speaking_language\": \"en\"\n }\n }\n }'" } ] } @@ -2112,7 +2112,7 @@ "enum": [ "first_message", "system_prompt", - "voice_profile_id", + "voice_id", "language" ], "type": "string" @@ -2290,7 +2290,7 @@ "enum": [ "first_message", "system_prompt", - "voice_profile_id", + "voice_id", "language" ], "type": "string" @@ -2739,7 +2739,7 @@ }, "patch": { "summary": "Update Draft Config", - "description": "Patch the draft configuration section by section; omitted sections keep\ntheir value. Changes only affect live sessions after the next publish.\n`prompt.system_prompt` is limited to 4000 characters (422 beyond).\n`voice.voice_profile_id` accepts any public voice model id.\n`voice.speaking_language` accepts `en`, `ja`, `zh`, `ko`, `es`, `fr`, `de`;\nanything else is 422. `tool_ids` and\n`knowledge_source_ids` replace their attachment lists wholesale and every\nid must resolve, else 422.", + "description": "Patch the draft configuration section by section; omitted sections keep\ntheir value. Changes only affect live sessions after the next publish.\n`prompt.system_prompt` is limited to 4000 characters (422 beyond).\n`voice.voice_id` accepts any public voice model id.\n`voice.speaking_language` accepts `en`, `ja`, `zh`, `ko`, `es`, `fr`, `de`;\nanything else is 422. `tool_ids` and\n`knowledge_source_ids` replace their attachment lists wholesale and every\nid must resolve, else 422.", "security": [ { "BearerAuth": [] @@ -10266,27 +10266,6 @@ "default": null, "title": "Name" }, - "language": { - "anyOf": [ - { - "enum": [ - "en", - "ja", - "zh", - "ko", - "es", - "fr", - "de" - ], - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "title": "Language" - }, "timezone": { "anyOf": [ { @@ -10412,7 +10391,7 @@ }, "AgentSessionOverridesPayload": { "additionalProperties": false, - "description": "Wire twin of @fishaudio/agent-protocol `SessionOverrides` (session.ts).\n\nEvery field must be allow-listed in Agent.overrides_allowed; unauthorized\nfields fail session creation loudly rather than being silently dropped.", + "description": "Wire twin of @fishaudio/agent-protocol `SessionOverrides` (session.ts).\n\nEvery field must be allow-listed in Agent.overrides_allowed; unauthorized\nfields fail session creation loudly rather than being silently dropped.\nKeyless (public) sessions are additionally capped to PUBLIC_OVERRIDE_FIELDS\n(service.py) regardless of the allowlist.", "properties": { "first_message": { "anyOf": [ @@ -10427,6 +10406,19 @@ "default": null, "title": "First Message" }, + "first_message_prompt": { + "anyOf": [ + { + "maxLength": 10000, + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "First Message Prompt" + }, "system_prompt": { "anyOf": [ { @@ -10440,7 +10432,7 @@ "default": null, "title": "System Prompt" }, - "voice_profile_id": { + "voice_id": { "anyOf": [ { "maxLength": 256, @@ -10451,7 +10443,7 @@ } ], "default": null, - "title": "Voice Profile Id" + "title": "Voice Id" }, "language": { "anyOf": [ @@ -10999,7 +10991,7 @@ "enum": [ "first_message", "system_prompt", - "voice_profile_id", + "voice_id", "language" ], "type": "string" @@ -11617,7 +11609,7 @@ "PublicAgentVoicePatch": { "additionalProperties": false, "properties": { - "voice_profile_id": { + "voice_id": { "anyOf": [ { "maxLength": 256, @@ -11628,7 +11620,7 @@ } ], "default": null, - "title": "Voice Profile Id" + "title": "Voice Id" }, "speaking_language": { "anyOf": [ @@ -11822,7 +11814,7 @@ "enum": [ "first_message", "system_prompt", - "voice_profile_id", + "voice_id", "language" ], "type": "string" @@ -12124,9 +12116,9 @@ }, "AgentVoiceConfig": { "properties": { - "voice_profile_id": { + "voice_id": { "default": "4501d82f5de3467ebf4d7ef095a2deee", - "title": "Voice Profile Id", + "title": "Voice Id", "type": "string" }, "speaking_language": { From d1d0f05682947f62c3902c42a1007c5a7cf13b1d Mon Sep 17 00:00:00 2001 From: Him188 Date: Thu, 6 Aug 2026 17:41:52 +0900 Subject: [PATCH 2/3] docs: drop the language-shorthand aside Co-Authored-By: Claude Fable 5 --- agents/build/dynamic-variables.mdx | 8 -------- 1 file changed, 8 deletions(-) diff --git a/agents/build/dynamic-variables.mdx b/agents/build/dynamic-variables.mdx index 586f716..a1314c7 100644 --- a/agents/build/dynamic-variables.mdx +++ b/agents/build/dynamic-variables.mdx @@ -85,14 +85,6 @@ const session = await AgentSession.start({ ``` -### The `language` shorthand - -Overriding the session language is common enough that the SDKs accept a top-level `language` option — the widget takes it as an attribute — and fold it into `overrides.language` for you. On the wire there is only one spelling: - -```json -{ "agent_id": "YOUR_AGENT_ID", "overrides": { "language": "ja" } } -``` - ### Validation | Case | Result | From 3c9a94d306b783df087b90991543ac4583ead9f5 Mon Sep 17 00:00:00 2001 From: Him188 Date: Thu, 6 Aug 2026 17:47:27 +0900 Subject: [PATCH 3/3] docs: split overrides out of the dynamic-variables page Co-Authored-By: Claude Fable 5 --- agents/build/dynamic-variables.mdx | 69 +++++------------------- agents/deploy/authenticated-sessions.mdx | 2 + 2 files changed, 14 insertions(+), 57 deletions(-) diff --git a/agents/build/dynamic-variables.mdx b/agents/build/dynamic-variables.mdx index a1314c7..9ed03a4 100644 --- a/agents/build/dynamic-variables.mdx +++ b/agents/build/dynamic-variables.mdx @@ -1,19 +1,10 @@ --- -title: "Dynamic Variables & Overrides" -description: "Personalize each session with template variables and per-session configuration overrides" +title: "Dynamic Variables" +description: "Personalize each session with template variables supplied at creation time" icon: "brackets-curly" --- -An agent's published configuration is shared by every caller — but each session can be personalized at creation time. Two mechanisms cover this, and both travel in the same `POST /v1/agent/sessions` request: - -| Mechanism | What it does | Scope | -|---|---|---| -| `dynamic_variables` | Fills `{{placeholder}}` templates in your configuration text | Any placeholder you define | -| `overrides` | Replaces whole configuration fields for this session | Four overridable fields | - -## Dynamic variables - -Write `{{variable_name}}` placeholders in your agent's system prompt or first message and supply values when you create the session. Substitution happens once, when the published configuration is assembled for the session. +An agent's published configuration is shared by every caller — dynamic variables personalize it per session. Write `{{variable_name}}` placeholders in your agent's system prompt or first message and supply values when you create the session. Substitution happens once, when the published configuration is assembled for the session. ```text System prompt You are a support agent for {{company}}. The caller's name is {{customer_name}} @@ -60,53 +51,18 @@ Session records never store dynamic variable values. You don't need a variable for the current date or time — the agent already knows both, in the session's timezone. See [Time & timezone](/agents/build/time-timezone). -## Overrides - -Overrides replace configuration fields wholesale for one session — for example, forcing a different language for a caller. The overridable fields are `first_message` (or its generated twin `first_message_prompt`), `system_prompt`, `voice_id`, and `language` — the full table with types, limits, and exactly what each replaces is in [Authenticated sessions](/agents/deploy/authenticated-sessions#overrides). - - -```bash API (curl) -curl --request POST https://api.fish.audio/v1/agent/sessions \ - --header "Authorization: Bearer $FISH_API_KEY" \ - --header "Content-Type: application/json" \ - --data '{ - "agent_id": "YOUR_AGENT_ID", - "overrides": { "language": "ja" } - }' -``` - -```javascript JavaScript SDK -import { AgentSession } from "@fishaudio/agent-client"; - -const session = await AgentSession.start({ - agentId: "YOUR_AGENT_ID", - overrides: { language: "ja" }, -}); -``` - - -### Validation - -| Case | Result | -|---|---| -| Override field not enabled for the agent | `400` | -| Unknown field inside `overrides` | `422` | -| Unknown top-level field in the request | `422` | - - -The session record stores which overrides took effect. - +Variables fill placeholders in the configured text. To replace whole configuration fields for a session — the prompt itself, the opener, voice, language — use [overrides](/agents/deploy/authenticated-sessions#overrides) on the same request; `{{placeholders}}` render inside overridden text too. ## Who supplies the values -Where variables and overrides come from depends on the session's [access mode](/agents/deploy/overview#who-may-start-sessions): +Where variable values come from depends on the session's [access mode](/agents/deploy/overview#who-may-start-sessions): -| Mode | Who creates the session | Who supplies variables and overrides | +| Mode | Who creates the session | Who supplies the values | |---|---|---| | `agentId` ([public agents](/agents/deploy/public-agents)) | The SDK, directly from the browser | The browser, via `AgentSession.start()` options | | `sessionToken` (private agents) | Your backend, with your API key | Your backend, in its `POST /v1/agent/sessions` call | -In `sessionToken` mode the SDK's `overrides`, `dynamicVariables`, and `language` options have no effect — the session already exists by the time the token reaches the browser. Attach personalization server-side instead: +In `sessionToken` mode the SDK's `dynamicVariables` option has no effect — the session already exists by the time the token reaches the browser. Attach personalization server-side instead: ```javascript Backend (sessionToken mode) // Your backend endpoint, called by your own frontend @@ -119,28 +75,27 @@ const response = await fetch("https://api.fish.audio/v1/agent/sessions", { body: JSON.stringify({ agent_id: "YOUR_AGENT_ID", dynamic_variables: { customer_name: user.name, plan: user.plan }, - overrides: { language: user.locale }, }), }); const sessionToken = await response.json(); // pass to AgentSession.start({ sessionToken }) ``` -In `agentId` mode, values arrive from the end user's browser — treat them as untrusted input, and use `sessionToken` mode when personalization must come from data only your backend knows. Public sessions accept only the `language` and `voice_id` overrides; the prompt-shaping fields require a backend-created session. +In `agentId` mode, values arrive from the end user's browser — treat them as untrusted input, and use `sessionToken` mode when personalization must come from data only your backend knows. ## Going further - The fields your placeholders and overrides act on. + The fields your placeholders act on. - Set variables from your backend when creating the session. + Replace whole configuration fields for one session. Sessions assemble the published configuration. diff --git a/agents/deploy/authenticated-sessions.mdx b/agents/deploy/authenticated-sessions.mdx index 8417915..458f658 100644 --- a/agents/deploy/authenticated-sessions.mdx +++ b/agents/deploy/authenticated-sessions.mdx @@ -156,6 +156,8 @@ Unknown fields — top-level or inside `overrides` — are rejected with `422`. On [public agents](/agents/deploy/public-agents), keyless (browser-created) sessions may override only `language` and `voice_id` — the prompt-shaping fields are rejected with `400` regardless of the agent. Create the session from your backend to use them. +The session record stores which overrides took effect. + Everything else on the request is not an override: `dynamic_variables`, `timezone`, `record_audio`, and `tool_events` are separate top-level fields. Session length is not settable per session — `max_duration_seconds` comes from the agent's [conversation configuration](/agents/build/configuration#call-duration). ## Response