Skip to main content
Moved to App Settings in v0.129.0

The tuning values on this page are configured in the in-app App Settings screen (sidebar footer, sliders icon) and stored in app_settings.jsonc -- not in .env. A value left in .env is ignored and named once in the startup log; run chatwalaau settings migrate --write to carry an existing configuration across. Feature enable-gates and secrets stay in .env. See Configuration -> Application settings.

Models & Reasoning

Changed in v0.107.0

Chat models are configured exclusively through the Model Offering Catalog (model_offerings.jsonc). The legacy per-provider variables (AZURE_OPENAI_MODELS, ANTHROPIC_MODELS, OPENAI_MODELS, FOUNDRY_MODELS, MODEL_MAX_CONTEXT_TOKENS, ANTHROPIC_HOSTING, and the per-provider chat endpoint/key variables) have been removed. The *_MODELS snippets shown below in the per-provider sections describe what each offering needs -- put those values on an offering in the catalog instead. The shared Azure credential variables and OPENAI_API_KEY are retained.

Multi-model switching

Author several offerings in model_offerings.jsonc and switch between them mid-conversation:

  • A model selector appears above the chat input (hidden when only one model is configured)
  • Per-session model selection persists across reloads
  • Regenerate with a different model -- click the chevron on Regenerate
  • Each assistant message shows which model generated it
  • All models share the same Tools, Skills, and MCP integrations

Per-model context-window limits are set by each offering's context_window field (defaulting to 128000 when unset). The context-window progress bar above the input updates automatically when you switch models.

Model Offering Catalog

Every chat model is managed from a single JSONC file. Point MODEL_OFFERINGS_FILE at it (default model_offerings.jsonc, resolved against the working directory); it is the single source of truth for model routing. A non-demo deployment with no catalog boots normally with a startup warning (so the App Settings screen stays reachable to fix it); chat is unavailable and returns a message pointing at chatwalaau models add / the App Settings screen the moment you try it (DEMO_MODE=true runs without one).

Each offering describes one model:

{
"auth_profiles": { "gateway": { "api_key_env": "GATEWAY_API_KEY" } },
"offerings": [
// The default chat model (at least one chat offering is required).
{
"id": "gpt-5.2",
"provider": "azure-openai",
"model_ref": "gpt-5.2", // the real deployment name
"endpoint": "${AZURE_OPENAI_ENDPOINT}",
"default": true,
"context_window": 400000
},
// Claude via an Anthropic-compatible gateway (per-offering hosting).
{
"id": "claude-opus-4-8",
"provider": "anthropic",
"hosting": "foundry",
"model_ref": "claude-opus-4-8",
"base_url": "https://my-gateway.example.com/anthropic",
"auth_profile": "gateway"
},
// A non-OpenAI Foundry family: turn off the OpenAI reasoning controls.
{
"id": "deepseek-v4",
"provider": "foundry",
"model_ref": "my-deepseek-deployment",
"endpoint": "${FOUNDRY_PROJECT_ENDPOINT}",
"family": "bare"
},
// Optional: at most one embeddings, one image and one live offering.
{
"id": "embeddings",
"provider": "azure-openai",
"model_ref": "text-embedding-3-small",
"endpoint": "${AZURE_OPENAI_ENDPOINT}",
"operations": ["embeddings"]
}
]
}

Why it helps:

  • Gateways. One endpoint that fronts several model families becomes several offerings sharing an endpoint / base_url -- no new provider to configure.
  • Mixed hostings. Direct Claude and Foundry-hosted Claude can coexist in one instance (per-offering hosting), which the single global ANTHROPIC_HOSTING could not express.
  • One required chat model, everything else optional. At least one chat offering is required; embeddings, image and live offerings are optional. With several chat models, the default: true one (or the first) is used when no model is specified.

Rules of thumb:

  • Secrets never live in the file. Reference an environment variable by name (api_key_env) or a named auth_profiles entry, or rely on the shared Entra ID credential lanes. ${VAR} in endpoint / base_url is filled from the environment.
  • family overrides the per-model options a gateway model advertises: openai-reasoning, anthropic-adaptive, or bare (no generation controls -- use this for non-reasoning gateway models). A family must match its provider: azure-openai / openai / foundry take openai-reasoning or bare, and anthropic takes anthropic-adaptive or bare; any other pairing is rejected at startup. Omit family to let the provider infer it.
  • A malformed catalog fails startup fast with a message naming the offending offering, so a typo never silently drops your models.
  • DEMO_MODE always uses the legacy lane. The legacy *_MODELS variables are now deprecated in favor of the catalog (still supported when no catalog is present).
  • Catalog invariants (enforced by the CLI, the GUI, and the server): at least one chat offering and exactly one default among them; unique ids; at most one embeddings, one image and one live offering; a live offering uses the azure-openai provider and serves no other operation; hosting applies to the anthropic provider only. A live offering is the GPT-Live voice deployment that enables the Live conversation.

When a deployment cannot serve a feature

Some features are supplied by the model's deployment, and whether they work depends on how that deployment was created -- not on the model.

Claude on Microsoft Foundry: pick the right hosting option

Foundry offers two hosting options, chosen when you create the deployment. Choosing "Default settings" in the portal picks Hosted on Azure, which is the restricted one:

Hosted on AzureHosted on Anthropic
Where inference runsAzure infrastructureAnthropic infrastructure
Hosted web searchNot supported✅ Supported
Structured outputNot supported✅ Supported

Requests that use an unsupported feature are rejected with 400 by design. The symptom looks like this, and every turn fails:

web search not supported in your workspace

The fix is to recreate the deployment, not to change any setting in ChatWalaʻau:

  1. Foundry portal → model catalog → your Claude model → DeployCustom settings
  2. Expand Model version settings and pick the version labeled Hosted on Anthropic
  3. Note the deployment name and point the offering's model_ref at it

Inside one Foundry resource the endpoint URL and authentication are unchanged -- only the deployment name changes.

The tool version is not the problem

Anthropic publishes three web search tool versions. All three are server-side tools, so none of them works on a Hosted-on-Azure deployment, and the two newer ones also require code execution — which is unsupported there too.

If you must stay on a restricted deployment

Tell the offering what its deployment cannot serve, and ChatWalaʻau stops sending it. In App Settings, or directly in the file:

{
"id": "claude-opus-5-foundry",
"provider": "anthropic",
"model_ref": "claude-opus-5",
"hosting": "foundry",
"base_url": "https://my-aifoundry.services.ai.azure.com/anthropic",
"capabilities": {
"web_search": false,
"native_structured_output": false,
"mcp": false,
"skills": false,
"image_generation": false
}
}

The settings behave differently, and the difference matters:

SettingWhat "Not available" does
Web searchRemoves the capability. There is no substitute. The web-search guidance is also removed from the system prompt, so the agent will not claim it can search — it will not invent citations.
Structured outputTurns the feature off for this model. A run-target that has an output schema configured falls back to a plain answer on it, and the built-in agent's card says so. There is no degraded path: the forced-tool-use fallback this project once shipped was never compatible with the agent framework and was removed in v0.125.0.
MCPRemoves every MCP tool for this model — both stdio and streamable-HTTP servers — and the MCP guidance with them. Your MCP servers keep running and other models keep their tools; this changes what this model is offered.
SkillsRemoves Agent Skills for this model: no skill is advertised and load_skill / read_skill_resource / run_skill_script are absent. Skills Management and the skills on disk are untouched.
Image generationRemoves image_generate / image_edit for this chat model. The image offering itself, and other chat models, are unaffected.
Function callingShown as Always available and cannot be turned off — see below.

Structured output and web search cannot share a turn

This is a provider restriction, not a ChatWalaʻau setting: the Responses API rejects a request that carries both a JSON output format and the hosted web search tool (Web Search cannot be used with JSON mode.). Rather than fail the turn, ChatWalaʻau drops web search for any turn that asks for structured output.

You are told where it happens, so a search that stops working has a reason:

  • the ChatWalaʻau Core card and the Custom agent editor both say "Web search is dropped while structured output is on" while a schema is set
  • the Prompt Dump's tool surface lists web_search as EXCLUDED with the reason structured output

Turn structured output off -- clear the format on the Core card, or remove the outputSchema from a Custom agent -- and web search comes back on the next turn.

Why Function calling cannot be turned off

MCP tools, the three skill tools and the two image tools all reach a provider as function tools. A model that could not call functions could not carry any of them, so a catalog able to say "function calling off, MCP on" would be describing something that cannot exist. Rather than validating that combination, ChatWalaʻau removes it: the row is visible so the whole vocabulary is in one place, and it is fixed at available.

Register only models that support function calling as chat offerings. Writing "function_calling": false in the file is rejected at load with an error that says so.

These are opt-outs, not opt-ins

A capability you do not write means enabled. An offering with no capabilities block, a key you left on Default, an unknown model, no catalog at all — every one of those resolves to "available". Only an explicit Not available on this deployment withholds anything, which is why adding these settings changed nothing about how your existing offerings behave.

Nothing disappears silently: a withheld tool appears in the prompt dump as excluded with the reason provider capability, the Built-in agent card names what the selected model withholds, and the server logs one line naming the offering.

The same rule covers the one absence that is nobody's setting. Hosted web search is dropped whenever structured output is on, because the provider rejects the pair -- so it is listed as excluded with the reason structured output, which points at the run-target's own card rather than at this catalog.

Leave everything on Default unless a request actually fails because of it. Default means "available", which is how every offering behaved before these settings existed.

Another way to get Claude and web search on Foundry

Register the deployment under the native foundry provider instead — its platform-supplied web search is unaffected by the Anthropic restriction. The trade-off is that generation options there are detected by deployment name, so a Claude deployment shows none. Recreating it as Hosted on Anthropic is usually better.

The order models appear in

The order of the chat offerings in the file is the order the model selector shows. Put your most-used model first and it appears first.

The default: true flag decides only which model is preselected for a new chat. It does not move that model to the top of the list -- a default sitting third in the file appears third, and is still the one preselected.

Changed in v0.106.0

Before v0.106.0 the default model was always hoisted to the top of the selector, regardless of where it sat in the file. If your default is not already first, the dropdown order will look different after upgrading -- the default now appears where it actually is. Nothing about which model answers has changed. To get the old look, drag it to the top in App Settings.

Authoring offerings (CLI and GUI)

You do not have to hand-write the JSONC. The catalog is operator-configurable two ways, and both read and write the same MODEL_OFFERINGS_FILE, so you can mix and match. list still reflects a running server; the authoring commands and the screen below manage the file itself.

CLI (offline, no server required). The chatwalaau models commands read and write the local catalog file, creating it if it does not exist:

# Interactive wizard: author and append one offering
$ chatwalaau models add
Provider [azure-openai / anthropic / openai / foundry]: anthropic
Model ref: claude-opus-4-8
Operation [chat / embeddings / image / live]: chat
Offering id: claude-opus-4-8
Default chat model? [y/N]: y
Base URL: https://api.anthropic.com
Hosting [direct / foundry]: direct
Family (optional):
Context window (optional): 200000
API key environment variable name: ANTHROPIC_API_KEY
Wrote model_offerings.jsonc (1 offering).

# Edit or remove an existing offering by id
$ chatwalaau models edit claude-opus-4-8
$ chatwalaau models remove claude-opus-4-8

# List the models a running server is serving (read-only, unchanged)
$ chatwalaau models list

The wizard prompts only for the name of the API-key environment variable (api_key_env), never the secret value. chatwalaau init can also run this "set up your first model" step right after it writes .env (skip it with chatwalaau init --no-model, or in any non-interactive run), so you can configure a model before or after init.

GUI (App Settings screen). Open the App Settings screen from the gear/sliders icon in the chat sidebar footer (next to the info icon). The left pane is a searchable settings list (with a refresh); the right pane is the Model Offering Catalog editor. Compose offerings grouped by operation -- Chat (at least one; exactly one default), Embeddings (0-1), Image (0-1), and Live (0-1). Each referenced environment variable shows a detected / not set indicator, so you can confirm the key is present without ever seeing its value. Save applies immediately via in-process hot reload -- no restart -- and a progress indicator shows while the change is applied.

Each offering shows as a compact row (id, provider, model, default) that expands on click when you want to edit it. Drag the grip handle to reorder -- that order is exactly what the chat model selector shows.

note

Saving from the GUI writes clean JSON, so hand-written comments in model_offerings.jsonc are not preserved. (Named auth_profiles entries are preserved.) CLI edits take effect the next time the server starts; GUI saves hot-reload the running server in place. No new environment variable is introduced -- both paths use MODEL_OFFERINGS_FILE (default model_offerings.jsonc).

Task model assignments

Besides the chat models you pick in the selector, ChatWalaʻau runs a few background helper models -- to generate a chat's title, extract user memory, curate agent memory, summarize a Teams meeting, and turn a natural-language question into an ontology SPARQL query -- and, since v0.169.0, to run the tasks a Live conversation delegates. Each of these is assigned to one of your existing chat offerings, so it inherits that offering's provider, endpoint, and credentials automatically.

  • GUI. In the App Settings screen, the Task model assignments section lists each task with a dropdown of your chat offerings plus Follow session / default.
  • CLI. chatwalaau models role list shows the tasks and current assignments; chatwalaau models role set <role> <offering-id> assigns one and chatwalaau models role clear <role> unsets it.
  • File. They live in an optional top-level roles block in model_offerings.jsonc, e.g. "roles": { "session_title": "gpt-4o-mini" }.

Leaving a task unassigned uses the chat's own model (then the catalog default), which is the default behavior (for Live delegation, the selected agent's own model). The role keys are session_title, user_memory_extraction, agent_memory_curation, meeting_summary, ontology_nl, and live_delegation.

note

Since v0.109.0 these assignments replaced the dedicated SESSION_TITLE_MODEL, USER_MEMORY_EXTRACTION_MODEL, AGENT_MEMORY_CURATION_MODEL, TEAMS_MEETING_SUMMARY_MODEL, and ONTOLOGY_NL_MODEL environment variables, which were removed. A leftover variable is ignored (with a startup advisory naming the successor role).

Anthropic (Claude) provider

Claude models are offerings in the Model Offering Catalog with "provider": "anthropic". They appear in the same selector as every other model and can be picked per turn. Each offering chooses its own hosting, so direct and Foundry-hosted Claude models can sit side by side.

Direct hosting (Anthropic public API) -- the key lives in an environment variable the offering names:

{
"id": "claude-opus-4-8",
"provider": "anthropic",
"hosting": "direct", // the default when omitted
"model_ref": "claude-opus-4-8",
"api_key_env": "ANTHROPIC_API_KEY" // or an auth_profile
// "base_url": "https://your-gateway.example.com" // optional proxy
}

Foundry hosting (Anthropic on Microsoft Foundry) -- the offering carries the full Anthropic-on-Foundry URL in base_url:

{
"id": "claude-opus-5",
"provider": "anthropic",
"hosting": "foundry",
"model_ref": "claude-opus-5", // the Foundry deployment name
"base_url": "https://my-aifoundry.services.ai.azure.com/anthropic"
// Auth A -- API key: "api_key_env": "MY_FOUNDRY_KEY"
// Auth B -- Entra ID: omit api_key_env; the shared Azure credential is used
// (AZURE_CREDENTIAL_MODE = cli | managed-identity | default)
}
Use base_url, not endpoint, for Claude on Foundry

base_url is https://<resource>.services.ai.azure.com/anthropic -- built from the Azure AI Services resource name, not the Foundry project URL (.../api/projects/...). endpoint is not used on this hosting: since v0.163.0 an offering that sets it, or that lacks base_url, is rejected when the catalog is saved or loaded, with a message saying what to change. For Entra ID auth, do not point api_key_env at a token -- it is sent verbatim as the api-key header and returns HTTP 401.

Retired environment variables

ANTHROPIC_HOSTING, ANTHROPIC_MODELS, ANTHROPIC_FOUNDRY_RESOURCE, ANTHROPIC_FOUNDRY_BASE_URL and ANTHROPIC_FOUNDRY_API_KEY are no longer read -- the catalog replaced them. Because the Anthropic libraries underneath still look for the three ANTHROPIC_FOUNDRY_* names, ChatWalaʻau removes them from its own process at startup (unless your catalog references one by name) and logs a warning for each: delete them from .env.

Anthropic requires max_tokens on every request as a hard output cap; its floor is the Anthropic max tokens setting in App Settings.

Hosted web search works out of the box for Claude (web_search_20250305). Every other agent feature works on either provider as long as the model supports tool calling. Speech-to-text, text-to-speech, image generation, and RAG embedding run on their own dedicated Azure models, independent of the chat provider.

OpenAI (direct) provider

Enable models from OpenAI's own public API alongside Azure OpenAI and Anthropic -- they appear in the same selector and can be picked per turn. OpenAI is disabled by default; leaving OPENAI_MODELS unset is a no-op.

Authentication is by API key only:

OPENAI_MODELS=gpt-5.1
OPENAI_API_KEY=sk-...
# OPENAI_BASE_URL=https://your-gateway.example.com # optional, OpenAI-compatible gateways

The current release supports reasoning models (for example gpt-5.x / o-series). They behave exactly like Azure OpenAI reasoning models -- same reasoning-effort control, hosted web search (country-scoped via WEB_SEARCH_COUNTRY), and structured output. Non-reasoning models (gpt-4o / gpt-4.1) are planned for a later release.

Microsoft Foundry provider

Enable reasoning models deployed in a Microsoft Foundry project alongside the other providers -- they appear in the same selector and can be picked per turn. Foundry is disabled by default; leaving FOUNDRY_MODELS unset is a no-op.

FOUNDRY_MODELS=gpt-5.1
FOUNDRY_PROJECT_ENDPOINT=https://<resource>.services.ai.azure.com/api/projects/<project>

Authentication is by Entra ID only, reusing the same Azure credential setup as Azure OpenAI: AZURE_CREDENTIAL_MODE (cli via az login, managed-identity on Azure-hosted compute, or default) plus the AZURE_TENANT_ID pin. There is no API-key option -- Foundry project endpoints authenticate with Entra ID; grant the signed-in identity a Foundry data-plane role (for example Azure AI User) on the project resource. AZURE_OPENAI_API_KEY does not apply to this provider.

Any Foundry chat-model deployment can be listed, and the generation controls match the model family: OpenAI reasoning deployments (gpt-5.x / o-series names) expose the same reasoning-effort control as Azure OpenAI reasoning models, while other families (for example DeepSeek) show no generation controls -- requests to them stay free of parameters those models reject. Web search (with citations) and structured output work across families.

Native Foundry vs Claude-on-Foundry

This provider ("provider": "foundry") serves models natively from a Foundry project endpoint. It is separate from the Anthropic provider's Foundry hosting ("provider": "anthropic", "hosting": "foundry"), which serves Claude through the Anthropic route and takes a base_url instead.

Model ids must be unique across all providers (AZURE_OPENAI_MODELS, ANTHROPIC_MODELS, OPENAI_MODELS, FOUNDRY_MODELS); a collision is rejected at startup. The model selector lists Azure first, then Anthropic, then OpenAI, then Foundry, and the default model is the first configured Azure model when any is set.

Generation options (set on the agent)

How hard a model reasons is part of the agent, not of each message. Every run-target fixes its own model and reasoning effort, and they reach the provider once, when the agent is built:

Run-targetWhere you set the model and effort
Built-in ChatWalaʻau Core agentDeclarative Agents & Workflows -> the Core card (model, reasoning effort, structured output). On a phone: the agent button above the message box (model + effort).
Custom Prompt agentThe agent's detail screen, or model.id / model.options.effort in its YAML
Harness agentThe harness detail screen, or model.id / model.options.effort in its YAML
Workflow agent nodeThe Prompt agent the node references

The available effort levels and the default are served by the backend (GET /api/model, the model_options catalog), so a surface renders only what the selected model advertises and a model that accepts no generation options renders no control. There is no environment variable for them; the Built-in agent's selection is stored in application settings and applied without a restart.

The Built-in agent's selection is server-wide

The Built-in agent answers chat, Microsoft Teams, the CLI, the OpenAI-compatible API and the background lanes (chat titles, user / agent memory, meeting minutes, Ontology). Changing its model or effort changes all of them at once. The surfaces that change it say so before applying.

Because the default effort is xhigh, short background work -- a chat title above all -- is generated at high effort unless you act. If that matters, select a Prompt agent whose effort is medium, or set the Built-in agent to medium and raise it per agent where it earns its cost.

Reasoning effort

Sets how hard the model reasons. One ladder for every reasoning provider:

ProviderLevelsDefaultMechanism
Azure OpenAI (gpt-6 / gpt-5.x)low, medium, high, xhigh, maxxhighreasoning.effort
OpenAI (direct, gpt-5.x / o-series)low, medium, high, xhigh, maxxhighreasoning.effort
Microsoft Foundry (gpt-5.x / o-series deployments)low, medium, high, xhigh, maxxhighreasoning.effort
Anthropic (Claude)low, medium, high, xhigh, maxxhighadaptive thinking + output_config.effort

A model whose catalog family is bare accepts no reasoning options, so no control is offered for it.

What follows the effort automatically

Effort is the only generation option you choose. Everything else is derived from it, identically on both reasoning families:

Derived from the effortlowmediumhighxhighmax
Verbosity (OpenAI family, text.verbosity)lowmediumhighhighhigh
Max output tokens (thinking and answer)1600032000480006400096000

Fixed and not selectable: the OpenAI reasoning summary (detailed) and Anthropic's thinking mode and display (adaptive, summarized; no budget_tokens).

Two consequences worth knowing:

  • Verbosity is no longer independent. "Reason hard but answer briefly" cannot be expressed -- ask for brevity in the prompt instead.
  • low effort caps the output at 16000 tokens. A very long single answer can stop there; raise the effort for long-form work.
Why no temperature / top_p?

Both supported model families are reasoning / adaptive-thinking models. Claude rejects temperature, top_p and top_k with HTTP 400, and the OpenAI reasoning models do not accept them either. The options catalog therefore does not offer sampling parameters. The mechanism is general, though: a future non-reasoning model can advertise temperature / top_p and the matching control appears automatically.

Prompt caching (input-token cost)

Every model call re-sends a large, stable prefix -- the system prompt plus the full tool schemas. On a long turn (especially a coding tool loop, where one message fans out into many sequential model calls) that prefix is billed again and again. Prompt caching marks the stable prefix as cacheable so it is billed once and re-read cheaply on the following calls. It is output-transparent: the model's replies are identical -- only billing and latency change.

It is on by default and provider-agnostic:

  • Anthropic (Claude): the backend injects cache_control breakpoints on the system block (which also covers the tool definitions) and the last few conversation messages, so in an agentic/coding tool loop the conversation tail -- tool results, file contents, reasoning -- re-reads at a large discount instead of being re-billed at full price on every model call.
  • Azure OpenAI: prompt caching is automatic for prefixes of ~1024 tokens or more; nothing to configure.

For very long tool loops, history compaction shifts the conversation prefix and lowers the conversation cache hit-rate. If caching is your priority, raise Compaction: message groups kept in App Settings -> Chat & session (keeps a wider stable window) and/or set ANTHROPIC_PROMPT_CACHE_TTL=1h (survives multi-minute pauses). Note the two compaction budgets are coupled by 2 x K < N, so a larger tool-call budget needs a larger message budget as well.

# Master toggle (default true). Set false to disable caching entirely.
PROMPT_CACHE_ENABLED=true

# Anthropic cache lifetime: 5m (default) or 1h (extended cache). Unknown -> 5m.
ANTHROPIC_PROMPT_CACHE_TTL=5m

When the active provider reports cache usage, the per-message token readout includes cache_read_input_tokens / cache_write_input_tokens, so you can see the savings directly.

For the saving across a whole turn -- which is what matters on a coding turn, where one request fans out into many model calls -- click the in / out counts under the assistant message. The detail shows the turn's cumulative cache reads and writes alongside the input that was billed at the full rate, so the ratio between them is the caching benefit.

tip

If credit usage still feels high on Claude, also lower the reasoning effort on the agent that answers (above). The default is xhigh, which spends a lot of output tokens thinking on every step; medium or low is plenty for many coding edits -- and for short background work such as chat titles.

Structured output (JSON)

Constrain the assistant's answer to JSON -- optionally to a specific JSON Schema -- so the reply is machine-readable instead of prose. It works across all base providers (Azure OpenAI, Anthropic, and OpenAI) and is off unless an agent asks for it: when it is off, requests are unchanged.

Where it is configured. On the agent, not per message (since v0.165.0): the Built-in ChatWalaʻau Core card in Declarative Agents & Workflows, or outputSchema in a custom Prompt agent's YAML. While it is on, every answer comes back as JSON, rendered as a copyable code block. Two modes:

  • Generic JSON -- just toggle on; the model returns a well-formed JSON object.
  • Explicit schema -- open the small editor (the +schema / edit button) and paste a JSON Schema. The answer is constrained to your schema. An empty or invalid schema falls back to generic JSON.

The controls are hidden for any model whose offering declares Structured output as Not available, and the Core card names structured output among what that model withholds -- so an absent control is never left looking like a feature this build does not have. A run-target that already had a schema configured answers in plain text on such a model; it is not silently presented as a structured answer.

Web search is dropped while structured output is on

The provider rejects a request that carries both, so ChatWalaʻau removes hosted web search for any turn that asks for JSON. The Core card, the Custom agent editor and the Prompt Dump all say so. See Structured output and web search cannot share a turn.

What "no schema" means depends on the model

Turning the toggle on without writing a schema falls back to a default schema, and that default is a property of the provider:

ProviderDefault when no schema is supplied
Azure OpenAI / OpenAIAny JSON object ({"type": "object", "additionalProperties": true})
Anthropic (Claude){"answer": "..."} -- an object with a single answer string

The difference is not a ChatWalaʻau choice: Anthropic's structured outputs require additionalProperties: false on every object, do not allow it to be omitted, and offer no way to request free-form JSON, so "any JSON object" cannot be expressed there. Rather than refuse the feature, those models fall back to a minimal valid shape -- and the schema editor states the exact shape you will get, so it is never a surprise.

Supply your own schema whenever the shape matters. An explicit schema always overrides the default, on every provider.

A schema that satisfies the strict rules works on every provider:

{
"type": "object",
"properties": { "answer": { "type": "string" } },
"required": ["answer"],
"additionalProperties": false
}

Every array needs "items", every object needs "additionalProperties": false, and every declared property must appear in "required". The editor lists any violation with the path of the offending sub-schema before you send.

note

Web search and structured output can't be used together (the providers reject that combination), so while structured output is on, web search is skipped for that turn. Other tools (coding, weather, and so on) keep working.

tip

Strict, native structured output (the default for the shipped models) guarantees the shape on the provider side, so a separate validation step is unnecessary. ChatWalaʻau still does a light, non-blocking check and shows a small JSON badge on the message -- amber if the output could not be parsed (for example a very long answer that was cut off). It never blocks or rewrites the answer.

Over the API. The OpenAI-compatible Responses API accepts the standard text.format field, so your existing OpenAI SDK code works unchanged -- see OpenAI-compatible API.

Reliability: transient provider errors

Model providers occasionally return a transient server error (HTTP 5xx) -- "The server had an error processing your request." In a coding session one question fans out into many sequential model calls, so the chance of hitting one at least once per turn is higher.

ChatWalaʻau handles this for you:

  • Automatic retry before any output. If the error happens before the answer has started streaming, the backend resends the request automatically (a small, bounded number of attempts with a short backoff). This is safe because nothing has been shown or saved yet, so the model simply restarts the turn. While it retries, the chat shows a brief "Temporary server error -- retrying..." notice so the run reads as in progress, not stalled.
  • No silent duplication. If the error happens after the answer has begun streaming, it is not retried (a retry could duplicate output). You get a clear "temporary server error -- please resend" message; just send again, or start a new chat if the conversation is very long.

A connection that dies mid-answer counts as retryable too (v0.143.1). If the provider accepts the request, starts streaming, and the connection is then closed before the answer finishes, that is a network interruption -- not a problem with your conversation. It follows the same rule as a transient server error: retried automatically if nothing had appeared yet, reported clearly if part of the answer was already on screen. Nothing is charged for an answer that never completed, and no tool runs twice. Before v0.143.1 this was reported as an internal error.

Errors that a retry would not fix are reported distinctly and are never retried:

ConditionWhat you seeWhat to do
Out of credits / quotaA billing message naming the providerAdd credits / raise the quota, or switch to another configured model
Rate limited (429)A rate-limit messageWait a moment and retry, lower the reasoning effort, or raise the deployment quota
Transient 5xx after output"temporary server error -- please resend"Resend; start a new chat if the conversation is very long
Connection dropped mid-answer (v0.143.1)"The connection to the model provider dropped part-way through the answer"Resend. If it keeps happening at roughly the same point each time, ask your operator to check for an idle timeout on the path to the provider