> For the complete documentation index, see [llms.txt](https://docs.amigo.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.amigo.ai/api-reference/change-logs/amigo-api/amigo-api-archive-v0-6-v0-9-99.md).

# Archive: v0.6.0 - v0.9.99

Archived release history for the Amigo API. For current releases, see the [Amigo API changelog](/api-reference/change-logs/amigo-api.md).

<details>

<summary>v0.9.99 - Verbatim Rubrics for Standard Quality Metrics (May 2026)</summary>

#### Verbatim Rubrics for LLM Judge Prompts

All 11 standard quality metrics (patient sentiment, conversational naturalness, conciseness, information accuracy, safety, and the six outcome metrics) now use the full verbatim rubric text from the authored specification instead of paraphrased summaries. This affects the `ai_query_prompt` field on builtin metric definitions.

The previous prompts condensed multi-paragraph rubrics into short narrative summaries, which stripped specific scoring anchors and signal definitions the LLM judge needs to score consistently. The updated prompts include the complete scoring bands, per-band anchor phrases, and severity definitions exactly as authored.

For the voice judge, the 10 dimension rubric blocks now include the full signal-to-severity mapping tables from the voice quality spec. Each dimension lists the specific signals to match against and the severity to assign, replacing the previous narrative descriptions. Severity labels are uppercase (CRITICAL, FLAG, WARNING) so the judge can anchor its output to them. A new scoring rule prevents the judge from upgrading or downgrading severity relative to what the spec assigns to each signal.

#### Increased Prompt Length Limit

The `ai_query_prompt` field on metric definitions now accepts up to 8,000 characters (previously 2,000). The higher limit accommodates full verbatim rubrics for standard quality judges.

**Breaking change:** None. The `ai_query_prompt` max length increase is backward-compatible. Existing custom metrics are unaffected. Standard metric prompt content has changed but standard metrics are platform-managed and not user-editable.

</details>

<details>

<summary>v0.9.98 - Simulation Bridge: Context Graph Versioning and Raised Limits (May 2026)</summary>

#### Context Graph Version Resolution

The simulation bridge endpoint now resolves the active context graph version instead of reading from the top-level context graph stub. Previously, the bridge prompt could reference stale states, tools, and behaviors that no longer matched what the voice agent actually runs. The bridge now reads the pinned version from the service's release version set, matching the same resolution path used by the agent engine at runtime.

If no version pin is configured, the bridge falls back to the latest version and logs a warning so operators can detect configuration drift.

#### Raised Concurrency and Scenario Limits

The simulation bridge now supports higher limits for power users running large-scale test suites:

| Parameter                                    | Previous Limit | New Limit |
| -------------------------------------------- | -------------- | --------- |
| Maximum scenarios per run                    | 20             | 50        |
| Maximum concurrency                          | 5              | 20        |
| Maximum concurrent bridge runs per workspace | 3              | 10        |

The maximum turns per scenario remains at 40. These limits apply to bridge runs initiated through the API or Developer Console. Agent Forge CLI users who call session primitives directly are not affected by these caps.

#### Updated Generation Model

Scenario generation and caller simulation now use an upgraded model for improved scenario diversity and more realistic caller behavior.

</details>

<details>

<summary>v0.9.97 - Absolute Upload URLs and Environment Configuration (May 2026)</summary>

#### Absolute Upload URLs

Upload links returned by the intake link endpoints now include fully qualified absolute URLs instead of relative paths. Previously, the `upload_url` field in link responses contained a relative path, requiring callers to construct the full URL themselves. Now the response includes the complete URL ready for sharing.

If the platform environment is not fully configured for upload link generation, the intake link endpoints return a `503 Service Unavailable` error with a clear message instead of returning a broken relative URL.

#### Surface URL Configuration

Surface delivery (SMS and email) now uses a dedicated forms URL configuration, separate from the API base URL. This allows surface URLs and upload URLs to be served from different domains. Error messages for misconfigured delivery have been simplified.

</details>

<details>

<summary>v0.9.96 - Shareable Upload Links (May 2026)</summary>

#### Shareable Upload Links for Customer Data Intake

Operators can now generate shareable upload links that give non-technical customers drag-and-drop file upload access - no API key or login required.

**New endpoints:**

| Method   | Path                                                | Description             |
| -------- | --------------------------------------------------- | ----------------------- |
| `POST`   | `/v1/{workspace_id}/intake/links`                   | Create an upload link   |
| `GET`    | `/v1/{workspace_id}/intake/links`                   | List upload links       |
| `DELETE` | `/v1/{workspace_id}/intake/links/{link_id}`         | Revoke an upload link   |
| `GET`    | `/v1/{workspace_id}/intake/links/{link_id}/uploads` | List uploads for a link |

Each link is scoped to a workspace and customer, with configurable expiration (1-720 hours, default 7 days) and a maximum upload count (1-10,000 files, default 100). Links can be revoked at any time.

#### Public Upload Page

The generated link opens a self-contained upload page at `/upload/{link_token}` with:

* Drag-and-drop file upload with progress indicators
* Client-side validation for file type and size
* Support for PDF, Word, PowerPoint, JPEG, and PNG files up to 100 MB each
* Clear error states for expired, revoked, or exhausted links

The link token itself is the authentication mechanism. No API credentials are exposed to the end user.

#### Link Lifecycle

Links report one of four statuses: `active`, `expired`, `revoked`, or `exhausted`. Uploaded files are tracked with the same metadata as API-submitted intake files, including SHA-256 hash, size, content type, and scan status.

</details>

<details>

<summary>v0.9.95 - Greeting Debounce Window (May 2026)</summary>

#### Post-Greeting Transcript Debounce

Voice sessions now apply a short debounce window after the agent greeting finishes playing, during which late-arriving user transcripts are still discarded. Speech-to-text engines can finalize transcripts for words spoken *during* the greeting with a delay that extends past the moment the greeting audio ends. Without this window, those stale fragments could reach the agent and contaminate the first real conversational turn.

The debounce applies to all transcript processing paths including barge-in detection, end-of-turn handling, and pre-fetch. No configuration is required - the protection is automatic for all voice sessions.

**Behavioral effect:**

* Callers who speak over the greeting no longer have their words echoed back or acted on after the greeting completes
* The first real agent turn starts cleanly, without leftover speech fragments from the greeting period
* Barge-in remains suppressed through the debounce window, consistent with greeting protection behavior

</details>

<details>

<summary>v0.9.94 - Patient Update: Gender, Language, and Structured Address (May 2026)</summary>

#### Expanded Patient Update Fields

The `patient_update` world tool now accepts additional demographic and address fields, giving agents the ability to update more patient information during a conversation without requiring a separate EHR workflow.

**New fields:**

| Field            | Description                                      |
| ---------------- | ------------------------------------------------ |
| `gender`         | Patient gender (male, female, other, or unknown) |
| `language`       | Preferred language (e.g. English, Spanish)       |
| `address_line_1` | Street address line                              |
| `city`           | City                                             |
| `state`          | State name                                       |
| `postal_code`    | Postal code                                      |

#### Structured Address Support

Addresses can now be provided as individual components (`address_line_1`, `city`, `state`, `postal_code`) instead of a single free-text string. Structured fields take precedence over the free-text `address` field when both are provided. Existing address data is preserved when unrelated fields are updated, so a phone number change no longer clears a previously stored address.

#### Gender and Language Carry-Forward

When `gender` or `language` is not provided in an update, the existing value is carried forward from the current patient record. This prevents unrelated updates from clearing demographic data.

</details>

<details>

<summary>v0.9.93 - Dashboard Filter Binding and Per-Panel Row Limits (May 2026)</summary>

#### Dashboard Filter Binding

The dashboard execute endpoint now binds filter values as named SQL parameters to panel queries. Filters declared in the dashboard definition are matched against `filter_values` supplied in the execute request. If a filter value is provided, it is bound; if not, the filter's default value is used. Unknown keys in `filter_values` are silently ignored, so clients can safely pass stale keys after a dashboard definition changes.

Filter IDs are validated on create and update: IDs must start with a lowercase letter, contain only lowercase letters, digits, and underscores, and be at most 64 characters. The reserved identifier `ws_id` cannot be used as a filter ID.

#### Per-Panel Row Limits

Panels can now declare a `max_rows` field that overrides the system default row limit for that panel's query. This allows data-heavy panels (tables, exports) to request more rows while keeping chart panels lightweight.

**Validation**

Creating or updating a dashboard with invalid or reserved filter IDs now returns `422 Unprocessable Entity` with a descriptive error message.

</details>

<details>

<summary>v0.9.90 - Standard Quality Metrics: 11 Builtin LLM-Judge Metrics (May 2026)</summary>

#### Standard Quality Metrics

The platform now ships 11 builtin quality metrics that evaluate every AI agent conversation using LLM-based judgment. These metrics run automatically on a daily schedule against call transcript summaries and require no configuration.

**5 universal metrics** apply to every service:

| Metric                     | Type             | What It Measures                                                                              |
| -------------------------- | ---------------- | --------------------------------------------------------------------------------------------- |
| Patient Sentiment          | Categorical      | How the patient felt about the interaction with the agent (positive, neutral, negative)       |
| Conversational Naturalness | Numerical (1-10) | Whether the agent sounds like a person or a scripted system                                   |
| Conciseness                | Numerical (1-10) | Whether the agent kept responses appropriately brief                                          |
| Information Accuracy       | Boolean          | Whether the agent accurately relayed information from tool calls                              |
| Safety                     | Categorical      | Whether a safety concern arose and how it was handled (no\_event, handled, warning, critical) |

**6 product-type outcome metrics** compute only for services tagged with the matching product type:

| Metric              | Product Type | Categories                                              |
| ------------------- | ------------ | ------------------------------------------------------- |
| Outcome: Scheduling | `scheduling` | escalated, resolved, no\_action                         |
| Outcome: Outbound   | `outbound`   | escalated, resolved, opted\_out, no\_action, no\_answer |
| Outcome: Coaching   | `coaching`   | escalated, resolved, no\_action                         |
| Outcome: Intake     | `intake`     | escalated, resolved, no\_action                         |
| Outcome: Triage     | `triage`     | escalated, resolved, no\_action                         |
| Outcome: Support    | `support`    | escalated, resolved, no\_action                         |

Product-type filtering uses service tags. Services tagged with a matching product type have the corresponding outcome metric computed for their calls. Services without a matching tag are excluded from that outcome metric. Universal metrics apply to all services regardless of tags.

#### Metric Model Update

The metric definition model adds a new field:

| Field                      | Type                    | Description                                                                                                                                                                    |
| -------------------------- | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `applies_to_product_types` | array of string or null | Product types this metric applies to. When set, the metric only computes for calls on services tagged with one of these types. When null, the metric applies to every service. |

All 11 standard quality metrics are returned by the metric settings and metric definitions endpoints alongside existing builtin metrics. They appear as `builtin: true` with `extraction_mode: "ai_query"` and daily granularity.

#### Writes and Idempotency

Standard quality metric results are written idempotently. Retries or reruns for the same time window overwrite previous results rather than duplicating rows. Metric values appear in the same metric values endpoints and dashboard views as all other metrics.

</details>

<details>

<summary>v0.9.89 - Phone Number Provisioning: Rest-of-World Support and Number Types (May 2026)</summary>

#### Phone Number Types

Phone number search and provisioning now support three number types: **local**, **mobile**, and **toll-free**. The `number_type` parameter is required on both the available-number search and the provisioning request. The area code filter is now validated to only apply to `local` numbers (returns 422 for other types).

The phone number response now includes a `number_type` field so you can see the type without additional lookups.

#### Rest-of-World Regulatory Bundle Discovery

Provisioning is no longer limited to US and CA. The `country` parameter now accepts any ISO 3166-1 alpha-2 country code. Required bundles are resolved dynamically based on the country, number type, and business end-user type:

* **US**: SHAKEN/STIR + CNAM bundles required (any number type)
* **CA**: CNAM bundle required (any number type)
* **Other countries**: regulatory compliance bundles are discovered automatically per country and number type

All required bundles must be approved before a number can be provisioned. The 409 error response now directs callers to inspect the bundle list to see which are missing or not yet approved.

#### Bundle List Filtering

The bundle list endpoint now supports optional filters:

| Parameter                     | Type        | Description                                                                       |
| ----------------------------- | ----------- | --------------------------------------------------------------------------------- |
| `policy_sid`                  | string      | Filter by exact policy SID                                                        |
| `iso_country` + `number_type` | string pair | Resolve and return only bundles required for that country/number-type combination |

`policy_sid` is mutually exclusive with the country/number-type pair. When no filters are provided, all bundles for the setup are returned.

#### Migration

* The `country` parameter on provisioning and available-number search no longer restricts to US/CA - any valid two-letter country code is accepted
* `number_type` is now a required parameter on available-number search and provisioning requests
* Phone number responses include the new `number_type` field

</details>

<details>

<summary>v0.9.88 - Voice Judge: Audio-Native Quality Evaluation (May 2026)</summary>

#### Voice Quality: Audio-Native Per-Call Scoring

The platform now evaluates voice agent call quality directly from audio recordings, scoring each call across 10 dimensions that measure the voice experience independent of conversational logic or prompting. Scores range from 0.0 to 1.0 per dimension, with severity classifications (Critical, Flag, Warning) and quoted evidence from the audio.

The 10 voice quality dimensions:

| Dimension                     | Priority | What It Measures                                                                  |
| ----------------------------- | -------- | --------------------------------------------------------------------------------- |
| Latency and Dead Air          | P0       | Response latency between turns, prolonged silence                                 |
| Pronunciation                 | P0       | Correct pronunciation of medical terms, drug names, dates, numbers, patient names |
| Clarity                       | P0       | Speech intelligibility and clean audio                                            |
| Filler and Silence Management | P1       | Graceful handling of processing pauses, appropriate verbal acknowledgments        |
| Interruption Handling         | P1       | Clean barge-in behavior, smooth recovery after being interrupted                  |
| Audio Consistency             | P1       | Absence of volume spikes, pitch anomalies, or mid-word cutoffs                    |
| Pacing                        | P2       | Conversational speech rate with appropriate pauses                                |
| Warmth and Tone               | P2       | Emotional appropriateness matched to patient state                                |
| Accent and Language Quality   | P2       | Language match and accent naturalness                                             |
| Voice Identity                | P2       | Consistent agent voice and persona across the call                                |

Each dimension includes an evidence quote describing exactly what was heard and when, so results are auditable rather than opaque scores.

Scoring runs as a scheduled batch job. Results are available per-service through a new API endpoint.

#### Platform API: Voice Judge Results Endpoint

New endpoint for retrieving per-call voice quality scores for a service:

| Method | Path                                                          | Description                               |
| ------ | ------------------------------------------------------------- | ----------------------------------------- |
| GET    | `/v1/{workspace_id}/services/{service_id}/voice-judge/recent` | Recent voice-judge results (newest first) |

Query parameters:

| Parameter | Type    | Default | Description                |
| --------- | ------- | ------- | -------------------------- |
| `limit`   | integer | 20      | Max rows to return (1-100) |

The response includes per-dimension scores, an overall composite score, severity counts, and the raw judge output with evidence quotes for UI drill-in.

Returns `503` when voice judge result data is unavailable, distinguishing a temporary dependency failure from "no evaluations yet" (which returns `200` with an empty list).

#### Metrics: 10 Voice Quality Metrics

Ten new builtin metrics aggregate per-call voice quality scores into per-workspace per-period averages:

* `voice_judge_latency_dead_air`
* `voice_judge_pronunciation`
* `voice_judge_clarity`
* `voice_judge_filler_silence`
* `voice_judge_interruption_handling`
* `voice_judge_audio_consistency`
* `voice_judge_pacing`
* `voice_judge_warmth_tone`
* `voice_judge_accent_quality`
* `voice_judge_voice_identity`

All are numerical metrics with daily granularity, unit `score`, and valid range \[0.0, 1.0]. Available through the existing metric store endpoints.

</details>

<details>

<summary>v0.9.87 - Soft Escalation and Empathy Detection Accuracy (May 2026)</summary>

#### Escalation: Soft Escalation Keeps Agent on the Call

When a caller requests to speak with a human in a non-emergency context, the platform now performs a **soft escalation** instead of immediately suspending the agent. The agent stays on the call, acknowledges the caller's request, and lets them know an operator is being contacted. Operators are notified through the standard escalation flow and can take over when ready.

Previously, all escalations suspended the agent immediately, which could leave the caller in silence while waiting for an operator to join. Soft escalation eliminates that gap - the caller continues to hear the agent until the operator is connected.

Hard escalation behavior is unchanged: crisis-level detections still suspend the agent, but the current sentence now finishes playing before the agent goes silent. This prevents mid-sentence audio cutoffs that could be jarring for the caller.

#### Emotion Detection: Stricter Empathy Tier 2 Activation

Tier 2 empathy (full empathy mode) now requires agreement between both the categorical emotion model and the dimensional valence model before activating based on a distress emotion label alone. Previously, a distress label from a single model was sufficient to trigger Tier 2, which could cause false activations on calm, low-energy speech - particularly on telephony-quality audio where the categorical model can default to distress classifications.

This change reduces false Tier 2 activations on routine calls. When Tier 2 activates incorrectly, it caps speech speed for the remainder of the call, making the agent sound unnaturally slow. The fix aligns the Tier 2 activation logic with the stricter conjunctive pattern already used for Tier 3.

No API changes. Both changes affect runtime behavior only.

</details>

<details>

<summary>v0.9.86 - Simulation and Playground Entity Visibility (May 2026)</summary>

#### World Model: Entity State Includes Simulation and Playground Events

Entity state projections now include events from simulation and playground sessions. Previously, these events were filtered out along with other non-production sources, which meant that entities created or modified during tool testing, text playground sessions, or simulation runs did not appear in the world model.

With this change, running a tool in the playground or executing a simulation that writes entity data will produce visible entity state - the same data the agent would see during a live conversation. This makes testing workflows more realistic and easier to validate.

Analytical pipelines - metrics, encounter detection, and gap detection - continue to exclude simulation and playground events. Production analytics are not affected.

No API changes. This is a data pipeline behavior change only.

</details>

<details>

<summary>v0.9.84 - Enriched Call Trace Analysis (May 2026)</summary>

#### Call Intelligence: Component Attribution

Post-call analysis now identifies which system component caused each behavioral issue during a call. Every misalignment between caller signals and agent responses is attributed to one of seven components: speech recognition, navigation model, emotion detection, state machine, tool execution, prompt logic, or turn-taking. Each attribution includes the specific issue, structural evidence, and a severity rating (critical, contributing, or minor).

This enables targeted debugging - instead of reviewing an entire call to understand what went wrong, you can see that a specific failure was caused by, for example, incorrect emotion detection or a state machine that failed to advance.

#### Call Intelligence: Enriched Execution Traces

Structured execution traces forwarded to the analysis pipeline now include richer per-turn data:

| Signal                    | Description                                                                                         |
| ------------------------- | --------------------------------------------------------------------------------------------------- |
| Tool summaries            | Structural shape of each tool call: name, input key names, output length, success/failure, duration |
| Reasoning step count      | Number of internal reasoning steps the agent took per turn                                          |
| Emotion label and valence | Detected caller emotion and emotional direction per turn                                            |
| Latency breakdown         | Navigation and engine timing per turn                                                               |
| STT confidence            | Speech recognition reliability score per turn                                                       |

All data is structural and categorical only. No patient names, dates of birth, medical record numbers, or raw tool input/output values are included in the analysis pipeline.

#### Call Intelligence: PHI-Safe Tool Reporting

Tool call reporting in execution traces has been redesigned around data minimization. Instead of forwarding raw tool inputs and outputs (which may contain patient information), traces now report only the structural shape: tool name, sorted input key names, output character length, success/failure flag, and execution duration. This eliminates the PHI surface area entirely rather than relying on redaction.

</details>

<details>

<summary>v0.9.83 - Judge Mode Metrics and Catalog Cleanup (May 2026)</summary>

#### Platform API: Judge Mode for Custom Metrics

Custom metric definitions now support **judge mode** - LLM-based evaluation of individual interactions using a rubric prompt you define. This lets you create metrics that score each call, encounter, or session against criteria specific to your organization.

**New definition fields:**

| Field         | Type     | Description                                                                                                           |
| ------------- | -------- | --------------------------------------------------------------------------------------------------------------------- |
| `prompt`      | `string` | Rubric prompt for LLM judge evaluation. Use `{$.path}` references to inject entity context data. Max 4000 characters. |
| `granularity` | `string` | `aggregate` (one value per time period, default) or `per_entity` (one value per interaction)                          |

**Validation rules for judge mode:**

* Metrics with a `prompt` must use `ai_query` extraction mode
* Metrics with `per_entity` granularity require a `prompt`
* The `prompt` must contain at least one `{$.path}` context variable
* Maximum 50 custom metric definitions per workspace

**Example:** A "clinical accuracy" judge metric could evaluate each call transcript against a rubric that checks whether the agent correctly verified allergies, confirmed medication dosages, and followed escalation protocols.

#### Platform API: Metric Catalog Response Changes

The `GET /v1/metrics/catalog` response schema has been updated:

**Added fields:**

| Field         | Type      | Description                                  |
| ------------- | --------- | -------------------------------------------- |
| `granularity` | `string`  | `aggregate` or `per_entity`                  |
| `has_prompt`  | `boolean` | Whether the metric uses LLM judge evaluation |

**Removed fields:**

| Field                | Notes                                 |
| -------------------- | ------------------------------------- |
| `source`             | No longer included in catalog entries |
| `channel_scope`      | No longer included in catalog entries |
| `period_granularity` | Replaced by `granularity`             |

#### Platform API: Freshness Endpoint Removed

The `GET /v1/metrics/freshness` endpoint has been removed.

</details>

<details>

<summary>v0.9.82 - Address-Aware Phone Number Provisioning (May 2026)</summary>

#### Platform API: Address Requirements on Phone Provisioning

Phone number search and provisioning now honor address requirements reported by the telephony provider, expanding the pool of numbers available for purchase.

**Search filtering:**

Available phone number search results are now filtered based on address compatibility rather than excluding all numbers with any address requirement:

* Searching in the same country as the setup's business address excludes numbers requiring a foreign address.
* Searching in a different country excludes numbers requiring a local (in-country) address.
* Numbers with no address requirement or flexible requirements are always included.

Previously, all numbers with any address requirement were excluded from search results.

**Provisioning validation:**

Phone number provisioning now validates address requirements before purchase and automatically attaches the setup's business address when required:

| Address Requirement | Behavior                                                                                                                 |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------ |
| `none`              | No address needed - number is purchased directly                                                                         |
| `any`               | Setup's business address is attached to the purchase                                                                     |
| `local`             | Setup's business address is attached. Returns `422` if the business address country does not match the number's country. |
| `foreign`           | Setup's business address is attached. Returns `422` if the business address country matches the number's country.        |

**New error responses:**

| Status | Condition                                                                              |
| ------ | -------------------------------------------------------------------------------------- |
| `409`  | Number is no longer available at purchase time                                         |
| `422`  | Number's address requirement is incompatible with the setup's business address country |

</details>

<details>

<summary>v0.9.81 - Country-Conditional Phone Number Bundles (May 2026)</summary>

#### Platform API: Country-Conditional Regulatory Bundles

Phone number provisioning now enforces country-specific regulatory bundle requirements. Instead of requiring all three Trust Hub verification steps (customer profile, SHAKEN/STIR, CNAM) upfront, the setup flow separates the customer profile from regulatory bundles, and each country specifies which bundles are required before provisioning.

**New endpoints:**

| Endpoint                                   | Method | Description                                                  |
| ------------------------------------------ | ------ | ------------------------------------------------------------ |
| `/v1/twilio-setup/{id}/bundle/shaken-stir` | POST   | Submit SHAKEN/STIR bundle (required for US numbers)          |
| `/v1/twilio-setup/{id}/bundle/cnam`        | POST   | Submit or update CNAM bundle (required for US + CA numbers)  |
| `/v1/twilio-setup/{id}/bundle`             | GET    | List all bundles for a setup with status and failure details |

**Country requirements:**

| Country | Required Bundles   |
| ------- | ------------------ |
| US      | SHAKEN/STIR + CNAM |
| CA      | CNAM only          |

**What changed:**

* **Setup creation no longer requires `cnam_display_name`** - CNAM is now submitted as a separate bundle after customer profile approval.
* **Bundles are submitted individually** - SHAKEN/STIR and CNAM are created via dedicated POST endpoints rather than being auto-advanced after customer profile approval.
* **Phone number provisioning gates on country-specific bundles** - A US number requires both SHAKEN/STIR and CNAM approved; a CA number requires only CNAM.
* **Bundle status includes failure details** - Each bundle carries human-readable failure strings from the latest rejection or noncompliant evaluation.
* **Pre-flight evaluations return actionable errors** - Bundle submission endpoints return `422` with structured failure details when Twilio's evaluation fails, so you can fix issues before waiting for async review.
* **CNAM display name is updatable** - POST to the CNAM bundle endpoint with a changed `display_name` updates the underlying data. Returns `409` if unchanged or if the bundle is under active review.
* **Use case creation gating simplified** - Only requires customer profile approval, not all bundles.
* **Phone number search gating simplified** - Only requires customer profile approval.
* **Country parameter restricted** - Phone number search and provisioning now accept only `US` or `CA`.

**Removed endpoints:**

| Endpoint                           | Replacement                                              |
| ---------------------------------- | -------------------------------------------------------- |
| `PATCH /v1/twilio-setup/{id}/cnam` | `POST /v1/twilio-setup/{id}/bundle/cnam`                 |
| `POST /v1/twilio-setup/{id}/retry` | Submit individual bundles via POST `/bundle/{kind}`      |
| `GET /v1/twilio-setup/{id}/event`  | `GET /v1/twilio-setup/{id}/bundle` for per-bundle status |

**Removed response fields:**

* Setup response no longer includes `shaken_stir`, `cnam`, `cnam_display_name`, `ready`, or `last_error`. Customer profile status is returned directly; bundle status is available via the bundles list endpoint.
* Phone number response no longer includes `shaken_stir_assignment_sid` or `cnam_assignment_sid`.

**Updated setup response:**

* `customer_profile` now includes `last_failure` (array of strings or null) for webhook rejection details.

</details>

<details>

<summary>v0.9.80 - Dashboard Embed BFF Proxy Auth (May 2026)</summary>

#### Platform API: Dashboard Embed BFF Proxy Auth

The `DashboardEmbed` component now supports cookie-based authentication through a backend-for-frontend (BFF) proxy. The `apiToken` prop is now optional - when omitted, the component uses same-origin credentials instead of a Bearer token.

This is useful when your application proxies dashboard API requests through its own backend, using session cookies or other server-side authentication rather than passing API tokens to the browser.

**What changed:**

* **`apiToken` is now optional** - Previously required. When omitted, the component sends requests with same-origin credentials and no Authorization header, allowing a BFF proxy to handle authentication server-side.
* **Cookie-based auth support** - Requests now include same-origin credentials, enabling session cookie authentication through a proxy.
* **No breaking changes** - Existing integrations that pass `apiToken` continue to work exactly as before.

</details>

<details>

<summary>v0.9.79 - Dashboard Workspace Scoping and Slug Uniqueness (May 2026)</summary>

#### Platform API: Dashboard Workspace Scoping

Dashboard panel queries now require a `:ws_id` parameter binding to enforce workspace-level data isolation. This prevents panels from accidentally querying data across workspaces.

**What changed:**

* **Write-time validation** - Creating or updating a dashboard with panel queries that do not reference `:ws_id` now returns `422 Unprocessable Entity` with a message identifying the offending panel. Previously, these queries were accepted and could return unscoped data at execution time.
* **Execute-time enforcement** - When executing a dashboard, any panel query missing the `:ws_id` binding returns an error result for that panel instead of running the query. Other panels in the same dashboard still execute normally.
* **Concurrent panel execution** - Panel queries now execute concurrently with bounded parallelism, improving dashboard load times when multiple panels are present.

#### Platform API: Dashboard Slug Uniqueness

Dashboard slugs are now enforced as unique within a workspace. Attempting to create or update a dashboard with a slug that is already in use by another active dashboard in the same workspace returns `409 Conflict`.

Previously, duplicate slugs could cause lookup failures when dashboards were retrieved by slug. Soft-deleted dashboards do not participate in the uniqueness constraint.

**What changed:**

* **Create** - Returns `409 Conflict` if the slug is already taken in the workspace.
* **Update** - Returns `409 Conflict` if the new slug collides with another active dashboard in the workspace.

</details>

<details>

<summary>v0.9.77 - Custom Phrase Escape Hatch and Adaptive Filler Timing (April 30, 2026)</summary>

#### Platform API: Custom Phrase for Progress Hints

Progress hints on tool call specs now support an optional `custom_phrase` field - an operator-authored filler utterance spoken while a slow tool executes. This is a narrow escape hatch for demo-critical tools where the standard generated fillers do not adequately cover the wait.

The field is gated to prevent misuse:

* **Minimum latency** - `expected_latency_ms` must be 4000 or higher. Custom phrasing is reserved for tools with demonstrably long waits.
* **Class required** - `progress_class` must be set. The class acts as the fallback when the custom phrase cannot be used (for example, when hints from multiple tools are merged).
* **Word limit** - The phrase must be 30 words or fewer to keep fillers concise.

When all gates are satisfied, the custom phrase is spoken on the first filler tick. Subsequent ticks fall back to the standard class-based templates. When progress hints from multiple concurrent tools are merged, custom phrases are dropped because they are tool-specific and cannot be meaningfully combined.

**What changed:**

* **`custom_phrase` field** - New optional string field on the progress hint object. Maximum 500 characters, at most 30 words. Validated on submission; requests that fail the gate conditions receive descriptive error messages.
* **Merge behavior** - When the platform merges progress hints across concurrent tools, custom phrases are excluded from the merged result. The merged hint uses the standard progress class templates.

#### Platform API: Adaptive Filler Timing

The voice agent now adapts when the first filler utterance fires based on the tool's declared expected latency. For tools that declare an expected wait, the first filler fires earlier in proportion to the expected duration, so callers hear acknowledgment sooner during moderate waits (4-9 seconds) rather than waiting for the default delay. Tools without a declared latency keep the existing timing.

**What changed:**

* **Earlier first filler** - Tools with a declared `expected_latency_ms` trigger their first filler utterance earlier, scaled to the expected wait. This prevents the scenario where a tool finishes before the caller hears any acknowledgment.
* **No change for unconfigured tools** - Tools without `expected_latency_ms` retain the existing default filler timing.

</details>

<details>

<summary>v0.9.76 - World Model FHIR Name Preservation (April 29, 2026)</summary>

#### Platform API: FHIR Name Data Preserved in World Events

World model events now preserve structured FHIR `name` data (the HumanName format used by EHR systems) in their full original shape. Previously, the structured name could be dropped during event processing, which meant downstream queries that accessed name components - given name, family name, prefixes, suffixes - would return empty results.

The platform still extracts a flat display name for quick lookups. When a display name is not explicitly provided, the platform derives one from the structured name by combining the first given name and family name. FHIR HumanName lists, plain string names, and explicit display names are all handled correctly.

**What changed:**

* **Structured name retention** - FHIR HumanName arrays are no longer removed from event data during processing. Queries that read name components (given names, family name, prefixes) from event data now return complete results.
* **Display name derivation** - When no explicit display name is set, the platform derives one from the first entry in a FHIR HumanName list or from a plain string name. This ensures display name is populated consistently regardless of the source data format.

</details>

<details>

<summary>v0.9.74 - Per-Workspace Audit Log Isolation (April 25, 2026)</summary>

#### Platform API: Audit Log Workspace Scoping

Audit log entries are now scoped to individual workspaces. Previously, certain auto-provisioning events were logged once without a workspace association. Now each workspace receives its own audit entry, so workspace-level audit queries return complete results without cross-workspace leakage.

**What changed:**

* **Per-workspace audit entries** - Operations that span multiple workspaces (such as user auto-provisioning) now emit a separate audit entry for each workspace involved. Each entry includes the workspace identifier and the user's role in that workspace.
* **Read-only isolation** - Audit log access is restricted to read-only queries scoped to the caller's workspace. Services cannot modify or delete audit records, and queries only return entries belonging to the requesting workspace.
* **Service role groups** - Service credentials are now assigned to role groups rather than referenced individually in access policies. Rotating a service credential no longer requires policy changes - the new credential is granted membership in the same role group.

</details>

<details>

<summary>v0.9.73 - Client Credentials OAuth2 &#x26; Secret Hashing (April 24, 2026)</summary>

#### Platform API: OAuth2 Client Credentials Grant

The identity service now fully supports the OAuth2 `client_credentials` grant type with secure secret management. Client secrets are hashed with a modern key derivation function (PBKDF2-SHA256, 210,000 iterations) before storage, replacing the previous approach.

**What changed:**

* **Credential creation** - Creating a `client_credentials` or `api_key` credential now generates a secret automatically and returns it in the response. The plaintext secret is shown once and cannot be retrieved again. The response includes both the credential metadata and the secret.
* **Secret rotation** - Rotating a `client_credentials` credential secret now uses the same secure hashing. API key rotation continues to work as before.
* **Token exchange** - The `client_credentials` token grant now verifies secrets against the new hash format. Verification runs off the main request thread to avoid blocking on the CPU-intensive hashing operation.
* **Backward compatibility** - Credentials created before this change (using the legacy hash format) continue to work. The system detects the hash format automatically and verifies accordingly. No migration is required for existing credentials.

</details>

<details>

<summary>v0.9.70 - Call Completion Reason Normalization &#x26; Validation (April 21, 2026)</summary>

#### Platform API: Standardized Call Completion Reasons

The `completion_reason` field on call intelligence records is now validated and normalized before storage. A canonical set of completion reasons is enforced across all producers (voice agent engine and API), and a database-level constraint prevents unknown values from entering the system.

The full set of valid completion reasons is: `completed`, `abandoned`, `escalated`, `transferred`, `timeout`, `error`, `voicemail`, `no_answer`, `caller_hangup`, `forwarded`, `terminal_state`, `warm_transfer_completed`, `no_inbound_audio`, `cancelled`.

**New value**: `cancelled` has been added for calls that are explicitly cancelled before completion.

**Alias mapping**: Legacy or provider-specific reason strings are automatically mapped to canonical values. For example, `max_duration` and `idle_timeout` both normalize to `timeout`. Unrecognized values are coerced to `null` and logged as warnings rather than causing write failures.

This change is backward-compatible. Existing calls with valid completion reasons are unaffected. Calls with previously stored non-canonical values will not be retroactively modified, but all new writes are validated.

</details>

<details>

<summary>v0.9.68 - Platform Health Monitoring &#x26; Entity Narrative Briefs (April 19, 2026)</summary>

#### Platform API: Platform Health Monitoring

Two new observability endpoints give operators real-time visibility into data pipeline health and end-to-end processing latency without requiring ad hoc data queries.

**Connector Health** (`GET /v1/{workspace_id}/sensorium/connector-health`) returns per-source event health for every data source writing into the workspace. Each source entry includes events ingested in the last hour and last 24 hours, mean events per minute, the last ingested timestamp, and a freshness category:

* `fresh` - last event less than 5 minutes ago
* `stale` - last event 5 to 60 minutes ago
* `quiet` - last event more than 60 minutes ago
* `never` - no events in the last 24 hours

**Loop Latency** (`GET /v1/{workspace_id}/sensorium/loop-latency`) measures the end-to-end time from data ingestion (a world model event landing) to agent action (the agent acting on that data). Returns an overall median latency, total pair count, and an hourly sparkline (up to 168 hours / 7 days) with per-hour pair counts and median latency. The `window_hours` query parameter controls the lookback window (1-168, default 24).

Both endpoints are workspace-scoped and rate-limited under the standard read policy.

#### Platform API: Entity Narrative Briefs

New AI-powered narrative brief generation for patient entities. The platform reads the last 90 days of world model events for a patient, synthesizes them into a structured narrative summary with a versioned prompt, and returns both Markdown and structured JSON representations.

* `POST /v1/{workspace_id}/entities/{entity_id}/brief` - generates a fresh brief on demand. The brief is persisted as a world model event, cached for fast retrieval, and includes evidence pointers (the event IDs that informed the narrative), a confidence score (0.0-1.0), the event count that went into the brief, and a prompt version identifier for traceability. Returns 404 if the entity is not a patient or does not exist in the workspace.
* `GET /v1/{workspace_id}/entities/{entity_id}/brief` - returns the latest cached brief. Cache misses fall through to the event store and repopulate the cache transparently. When no brief has ever been generated, the response returns a consistent empty shape (null `event_id` and content fields) rather than a 404, so the UI can render a "not yet generated" state without error handling.

Briefs are currently scoped to patient entities. Cohort, territory, and workspace-level briefs are planned for a future release.

</details>

<details>

<summary>v0.9.67 - WhatsApp Voice Notes, Desktop Sessions &#x26; Simulation Bridge (April 18, 2026)</summary>

#### Platform API: WhatsApp Voice Note Conversations

The voice agent now handles WhatsApp voice notes as a full conversation channel. Patients send a voice note, the platform transcribes it, runs the same reasoning engine pipeline (context graphs, tools, safety boundaries, world model), synthesizes the agent's spoken reply, and returns it as a voice note in the same WhatsApp thread.

Session continuity is keyed on the patient's phone number - no session ID management required. Switching between text and voice notes in the same thread preserves full conversation context. Concurrent voice notes from the same patient are serialized (409 if a turn is already in progress) to prevent race conditions in the reasoning engine.

The voice turn endpoint accepts any common audio format and returns OGG Opus. Audio payloads are capped at 20 MB with enforcement at both the API gateway and engine tiers.

#### Platform API: Desktop Session Proxy

New desktop session endpoints let API consumers and the Developer Console drive RDP desktop sessions without direct cloud infrastructure access. The platform proxies session lifecycle operations (create, screenshot, action, status, disconnect) to the desktop sidecar, handling authentication, workspace isolation, and audit logging transparently.

Sessions are workspace-scoped and limited to one active session at a time per connector. Concurrent session creation is rejected. All operations require admin-level permissions and emit PHI-access audit events.

#### Platform API: Simulation Bridge

New `POST /v1/{workspace_id}/simulations/bridge` endpoint that turns a natural language test objective into a set of autonomous test scenarios. The platform generates personas with distinct temperaments and conversation strategies from the objective, then runs each scenario end-to-end as an autonomous caller against the configured service.

Each bridge run creates a tracked coverage run with per-scenario sessions, so results are visible through the existing coverage graph and scoring APIs. Runs are capped at 3 concurrent per workspace (429 if exceeded) with a 30-minute overall timeout.

This is the REST API equivalent of `forge simulation bridge` - same scenario generation and autonomous execution, accessible without the CLI.

#### Platform API: Phone Number Use Case Management

Phone number provisioning now supports use case management. Each number can be assigned to specific use cases (A2P messaging, outbound voice, etc.), with the platform enforcing capability requirements per use case type. Numbers, use cases, and their assignments are managed through dedicated CRUD endpoints under channel management.

Available number search filters by country, area code (NANP countries only), and required capabilities. The provisioning flow validates that the business profile and trust products are fully approved before allowing number purchases.

#### Platform API: Trigger Input Override

The manual fire endpoint (`POST /v1/{workspace_id}/triggers/{trigger_id}/fire`) now accepts an optional JSON body with an `input` field. Values from the override are merged into the trigger's stored `input_template` at fire time, so webhook consumers and manual testers can supply dynamic values (phone numbers, entity IDs, custom parameters) without modifying the trigger configuration.

This is the mechanism webhook destinations use to pass extracted payload fields through to the trigger's action.

</details>

<details>

<summary>v0.9.66 - Progress Hints and Expanded EHR Projections (April 17, 2026)</summary>

#### Platform API: Tool-Wait Progress Hints

Agent engineers can now shape how the voice agent narrates tool waits on a per-state and per-tool basis. A new `ProgressHint` primitive describes the *shape* of a wait - a semantic `progress_class` (`lookup`, `write`, `external_call`, `compute`, `multi_step`), an `expected_latency_ms`, and a `mode` (`auto`, `silent`, `backchannel`, `verbal`) - instead of the previous per-state filler phrase lists. The engine generates the actual utterance at runtime from the hint plus tool semantics, turn emotion, and conversation context.

* **New field** `progress` (optional `ProgressHint`) on `ToolCallSpec` in `action_tool_call_specs` and `exit_condition_tool_call_specs`.
* **New field** `progress` (optional `ProgressHint`) on `ChannelOverride` (state-level per-channel override).
* **Resolution order**: per-tool hint > per-state channel override > engine default, merged field-wise so a tool only overrides the fields that actually differ.
* **Attempt-aware retries**: when a tool retries, the engine emits deterministic templated language keyed on `progress_class` - acknowledgement on attempt 1, brief apology on attempt 2, "still working" on attempt 3 - with no LLM call in the retry latency path.

{% hint style="warning" %}
**Breaking change (state-level only).** The fields `suppress_filler` and `filler_vocabulary` on state `ChannelOverride` and `ToolCallSpec` have been removed. Agent configs that set those fields must migrate to `progress`. Service-level `voice_config.filler_style`, `voice_config.filler_vocabulary`, and `voice_config.backchannel_delay_ms` are unchanged and continue to apply as defaults when no per-state/per-tool hint is set.
{% endhint %}

#### Platform API: Expanded EHR FHIR Projections

Charm-integrated workspaces now project every Charm entity into a queryable FHIR resource, closing gaps that forced scheduling and eligibility tools to fall back to partial data:

* **Practitioner**: members → FHIR Practitioner with NPI, role, licensed states, specialty, and active flag. Resolves previously dead `Practitioner/charm-{id}` references in `Appointment.participant`.
* **Location**: facilities → FHIR Location with address, timezone, geo position, phone, and hours of operation. Test/sentinel facilities project as `status=inactive`. Nearest-facility scheduling lookups now return real rows.
* **Coverage**: per-patient insurance → FHIR Coverage with subscriber DOB and name, effective/term period, relationship, payer reference, and a deterministic fingerprint for dedup. Unblocks payer eligibility checks.
* **Slot**: bookable Slots projected with `start`, `end`, `status`, and a schedule reference. Exposed via a new Slot view endpoint that resolves the provider display name from the Slot's schedule reference, so scheduling surfaces no longer need to join against the raw Schedule resource.
* **Extended Patient**: language, marital status, race/ethnicity (US Core extensions), emergency contact, deceased status, and an assigned-facility Location reference.
* **Extended Appointment**: appointment mode → serviceType, appointment timezone, member degree, member specialization, resource type, payer extensions, and cancelationReason on cancelled status.

</details>

<details>

<summary>v0.9.65 - Data-MCP Backend URL Override (April 17, 2026)</summary>

#### Data-MCP: Caller-Configurable Backend URL

Data-MCP callers can now choose which backend the MCP server proxies to on a per-request basis, instead of being pinned to the server's default deployment. A new `X-Amigo-Api-Url` request header specifies the target backend, validated against an allowlist on every request. Calls without the header continue to use the deployment's configured default, so existing integrations keep working unchanged.

The header value must match a host on the service's configured allowlist. Unknown hosts return `400`. The allowlist always includes the deployment's configured default, so clients do not need to send the header for that backend.

This lets a multi-region client route a Data-MCP request to the appropriate regional Classic API backend without running a separate MCP service for each region. Credential state is isolated by organization, key, and backend so a token issued for one backend is not reused against another.

</details>

<details>

<summary>v0.9.64 - Epidemiology REST Endpoints (April 17, 2026)</summary>

#### Platform API: Epidemiology REST Endpoints

Six new workspace-scoped endpoints under `/v1/{workspace_id}/epidemiology/` expose the population-health analytics tables shipped in v0.9.63 directly over HTTP. Same statistical methodology (Wilson CI, Byar CI, Charlson CCI, Pearson χ² / PMI / Jaccard / lift); no SQL or Delta access needed to query them.

* `GET /v1/{workspace_id}/epidemiology/prevalence` - active-condition prevalence with Wilson 95% CI. Filter by `code`, `code_system` (`ICD10`, `SNOMED`, `ICD9`, `OTHER`), `age_bucket` (`0-17`, `18-34`, `35-49`, `50-64`, `65-79`, `80+`), `gender`. Toggle `min_support_only=true` to hide small-cell cohorts (observed < 5).
* `GET /v1/{workspace_id}/epidemiology/trends` - monthly incidence time series for a specific code. Requires `code`; accepts `start_month` / `end_month` in `YYYY-MM` format plus the same cohort filters.
* `GET /v1/{workspace_id}/epidemiology/cohort-drivers` - Standardized Prevalence Ratio (SPR = observed / expected) per `(age_bucket, gender)` cohort with Byar 95% CI. Requires `code`. `SPR > 1` means the cohort over-indexes for that code. Defaults to `min_support_only=true`.
* `GET /v1/{workspace_id}/epidemiology/cooccurrence` - co-occurring active-condition code pairs with Jaccard, lift, PMI, and Pearson χ². Filter by `code` to constrain one side of the pair. Sort by `lift` (default), `pmi`, `chi_square`, or `jaccard`.
* `GET /v1/{workspace_id}/epidemiology/patient-burden` - per-patient condition features including Charlson Comorbidity Index (Quan 2005 ICD-10) and age-adjusted CCI (Charlson 1994). Filter by `min_charlson`, `age_min` / `age_max`, or `gender`. Sort by any numeric feature column (default `age_adjusted_charlson_index`).
* `GET /v1/{workspace_id}/epidemiology/patient-burden/{patient_entity_id}` - full burden row for a single patient plus per-category Charlson flags across all 17 Quan (2005) ICD-10 categories (myocardial infarction, CHF, peripheral vascular, cerebrovascular, dementia, chronic pulmonary, rheumatic, peptic ulcer, mild liver, diabetes +/- complications, hemiplegia, renal, malignancy, moderate/severe liver, metastatic, HIV/AIDS).

All endpoints enforce workspace isolation and apply the documented read rate limit. The server returns `503` when result data is unavailable, `502` on a downstream query failure, and `404` for an unknown patient on the detail endpoint.

The six analytics tables are also advertised to the Insights Agent's `sql_query` tool and the Data-MCP server, so agents and MCP clients can compose the epidemiology outputs with any other world-model query in the same call.

</details>

<details>

<summary>v0.9.63 - Epidemiology Analytics &#x26; Inbound Webhook URL Canonicalization (April 16, 2026)</summary>

#### Platform API: Epidemiology Analytics Tables

New population-health analytics pipeline producing six layered output tables from the world model's L1 clinical projections. Each table is explainable, cite-able, and suitable for feeding into risk stratification models without a black-box step in between.

* **`patient_condition_fact`** - exploded patient × condition grain with onset date, age at onset, code system normalized to `ICD10` / `SNOMED` / `ICD9`, and coarse age cohort buckets. The base table every downstream measure joins against.
* **`disease_trends_monthly`** - incident case counts per code per month per cohort. Use for outbreak detection, seasonality curves, and trend charts.
* **`disease_prevalence_current`** - active-condition prevalence with Wilson 95% confidence interval. Reliable for small samples (Wilson 1927, Brown-Cai-DasGupta 2001): the interval stays in `[0, 1]` even for tiny cohorts.
* **`disease_cohort_drivers`** - Standardized Prevalence Ratio (SPR) per `(code, cohort)` with Byar 95% confidence interval (Breslow & Day 1987). The canonical epidemiology measure for "does this cohort over- or under-index for this condition?" - an interpretable alternative to feature importance from a black-box model.
* **`patient_condition_burden`** - per-patient Charlson Comorbidity Index using Quan (2005) ICD-10 mappings, plus age-adjusted CCI per Charlson (1994). Feature-ready input for risk stratification; MLflow / AutoML / SQL rules consume it downstream.
* **`condition_cooccurrence_pairs`** - co-occurring code pairs with Jaccard similarity, lift, pointwise mutual information, expected count, and chi-square. Drives correlation-matrix visualizations and comorbidity pattern mining.

All association and ratio measures emit a `min_support_met` flag at the standard small-cell suppression threshold (observed count ≥ 5); UIs and downstream queries should filter on it to avoid reporting unstable rates. Tables are scoped per workspace and land in `analytics_{env}.public.*`.

Methodology is published and cited inline: Wilson (1927), Breslow & Day (1987), Charlson et al. (1987, 1994), Quan et al. (2005).

#### Platform API: Inbound Webhook URL Canonicalization

The inbound webhook receive URL moved from `/hooks/{workspace_id}/{destination_id}` to `/v1/{workspace_id}/hooks/{destination_id}` to match the versioned, workspace-scoped path convention used across the rest of Platform API. The URL is server-generated and returned on webhook destination create and get responses, so newly created destinations return the new URL automatically. Integrations that persisted an old URL should re-fetch the destination record and update their external webhook configuration.

</details>

<details>

<summary>v0.9.62 - Per-Key Entity Enrichment (April 16, 2026)</summary>

#### Platform API: Per-Key Entity Enrichment

New first-class API for extending world model entities with custom, source-attributed values. Previously, extra attributes on an entity were collapsed into an opaque blob with no source, confidence, or audit trail. Enrichment values are now per-key events with the same provenance, supersedes chain, and confidence resolution as every other world model event.

Each write validates against a workspace-scoped registry of allowed keys. Admins declare the keys their workspace tracks (entity type, value type, optional enum values, minimum confidence, PII flag) before any source can write them. Unknown keys are rejected at write time; enum violations, wrong value types, and sub-floor confidence values return `400` with a specific message. The same write API handles manual entries, connector backfills, forms, and agent-extracted values, differentiated only by `source` and `confidence`.

Reads return the current winner per `(entity, key)`, selected by confidence class (authoritative > human-approved > AI-verified > uncertain) with recency as the tiebreaker. A history endpoint walks the full supersedes chain so any value can be traced back to the source event, timestamp, and confidence that produced it.

New endpoints:

* `PUT /v1/{workspace_id}/world/entities/{entity_id}/enrichment/{key}` - write a single value with source, confidence, and optional `effective_at`. Returns the event ID and ingested timestamp.
* `GET /v1/{workspace_id}/world/entities/{entity_id}/enrichment` - list current winners for an entity with full provenance (value, value\_type, confidence, source, source\_system, effective\_at, event\_id).
* `GET /v1/{workspace_id}/world/entities/{entity_id}/enrichment/{key}/history` - supersedes chain for one key, newest first, with `is_current` and `supersedes` pointers.
* `POST /v1/{workspace_id}/world/enrichment-keys` - register a key (`entity_type`, `key`, `value_type`, optional `allowed_values`, `min_confidence`, `is_pii`).
* `GET /v1/{workspace_id}/world/enrichment-keys` - list registered keys, optionally filtered by `entity_type`.
* `PATCH /v1/{workspace_id}/world/enrichment-keys/{key_id}` - update `allowed_values`, `source_hint`, `description`, `min_confidence`, or `is_pii`. `key` and `value_type` are immutable; create a new key and migrate if those need to change.
* `DELETE /v1/{workspace_id}/world/enrichment-keys/{key_id}` - unregister a key. Historical events remain in the append-only log; future writes against that key return `400`.

Value types: `string`, `number`, `boolean`, `date`, `enum`, `json`. Writes require the `admin` role or above (`Workspace:Update`). Reads are rate-limited.

Agent-extracted values that do not match a registered key are silently dropped, so they do not pollute the event stream or win over governed values. This gives admins full control over which attributes are tracked without blocking agent-side capture.

See the [Data & World Model](https://docs.amigo.ai/developer-guide/platform-api/data-world-model#entity-enrichment) developer guide for the full request contract and the [World Model](https://docs.amigo.ai/data/world-model#entity-enrichment) conceptual overview.

</details>

<details>

<summary>v0.9.61 - Customer Data Intake (April 16, 2026)</summary>

#### Platform API: Customer Data Intake

New direct upload channel for approved customer integrations to stream PHI documents into a workspace landing zone. Complements the connector system for cases connectors cannot cover: bulk historical loads, partner document drops, and upstream systems that prefer to push on their own cadence.

* `POST /v1/{workspace_id}/intake/files` - streams a single file body into workspace-isolated storage. Returns upload `id`, `volume_path`, server-computed `sha256`, `size_bytes`, and `scan_status`.
* Two-layer authentication: the standard platform-api key or JWT plus a per-customer HMAC signature over a canonical request string (`sha256:content_type:customer_slug:timestamp`). Timestamp freshness window prevents replay.
* Metadata travels in `x-amigo-intake-*` headers so large payloads stream without JSON buffering. Server recomputes SHA-256 during the stream; a mismatch deletes the partial object and returns `422`.
* Every accepted upload writes an intake ledger row (workspace, customer slug, storage path, filename, content type, hash, size, uploader actor, received-at, scan status) and attempts to emit a signal event for downstream consumers.
* Access requires a normal workspace credential plus a separately provisioned customer HMAC secret. The route is not a self-service intake surface.
* TLS transport and workspace isolation are implementation controls, but the route does not by itself establish a HIPAA or HITRUST compliance posture. Deployment, contractual, retention, residency, and operating controls remain separate prerequisites.

This phase-0 release did not include malware scanning, built-in document parsing, or a self-service HMAC-secret portal. `scan_status` therefore remained `skipped`. Those capabilities were not part of the released contract and this historical entry makes no delivery commitment for them.

See the [Data Intake](https://docs.amigo.ai/developer-guide/platform-api/data-world-model/intake) developer guide for the full request contract and the [Customer Data Intake](https://docs.amigo.ai/data/customer-data-intake) conceptual overview.

</details>

<details>

<summary>v0.9.60 - Warm Hand-Off, Agent Trace, Call Analysis &#x26; Webhook Filtering (April 15, 2026)</summary>

#### Platform API: Warm Hand-Off

New warm transfer flow for operator escalation. When a patient asks to speak with a human, the agent dials the call center into the existing conference, puts the patient on hold, briefs the operator with full conversation context, then connects them. The patient never repeats themselves.

Three conference phases driven by tool calls:

* **Normal** - Agent and patient in conversation
* **Briefing** - Agent and operator connected, patient on hold. The operator receives a real-time AI briefing with situation summary, patient context, and recommended actions. The operator can ask the agent questions or instruct it to resume with the patient.
* **Connected** - Operator and patient connected, agent removed from the call

Barge-in is automatically disabled during the briefing phase to prevent the operator's speech from interrupting the agent's context transfer. The agent is stopped and removed from the conference once the operator takes over.

#### Platform API: Agent Trace APIs

Two new debugging endpoints for agent conversation analysis:

* `GET /calls/{id}/trace` - Per-turn execution log with actions, tools, state transitions, emotions, inner thoughts, and latency. Includes barge-in details (interrupted text, discarded utterances).
* `GET /calls/{id}/prompts` - Full LLM prompts (system prompt, conversation history, tool definitions) for each turn.

Equivalent endpoints are available for simulation sessions. Per-turn prompts are emitted as events for analytics queries.

#### Platform API: Call Trace Analysis

New `GET /calls/{id}/trace-analysis` endpoint providing audio-native intelligence analysis of completed calls. Returns emotional arc, key decision moments with causal attribution, counterfactual analysis, coaching recommendations, and interaction dynamics. Analysis is computed asynchronously after call completion, so the endpoint returns `status: pending` while processing and `status: unavailable` if analysis is not configured.

#### Platform API: Decision Trace

Agent reasoning is now classified with structured signal and effect types on each conversation turn. Every turn carries a `signal_kind` (what triggered the agent's response, such as caller speech, tool result, or state transition) and `effect_kind` (what the agent did: spoke, invoked a tool, navigated, or escalated). Decision events are emitted at call end for analytics, with three new metrics: turns per call, tool invocation rate, and state transition rate.

#### Platform API: Webhook Event Type Validation

Inbound webhook destinations now enforce `accepted_event_types` filtering. When a destination defines an event type whitelist, the platform extracts the event type from the signed request body (checking `type`, `event_type`, `event`, and `action` fields in priority order) and rejects payloads that don't match with a 422 response. Event type extraction uses only the signed body; unsigned headers are excluded to prevent spoofing via replay attacks with modified headers.

#### Platform API: Webhook Trigger Retry

Webhook destinations now support configurable retry on transient trigger fire failures via the `retry_attempts` field. When a connection timeout or network error occurs during trigger execution, the platform retries with exponential backoff (0.5s base delay). Only transient connection-level errors are retried; application errors that may have persisted data are not retried, preventing duplicate events from non-idempotent operations.

#### Platform API: Web Chat Audio Input

New `POST /step-audio` endpoint on text sessions allows web chat clients to send audio recordings instead of text. Audio is transcribed server-side and fed through the same reasoning pipeline as text input, so users can mix voice and text messages in the same session.

#### Platform API: Minimum TTS Speed

New `min_tts_speed` field on voice configuration sets a floor for the empathy engine's speed modulation. The empathy system reduces TTS speed after detecting caller distress, but without a floor it could make the agent sound unnaturally slow. The minimum speed prevents over-modulation while preserving the warmth response.

#### Platform API: Insurance Payer Search

New `world_payer_search` tool for mid-call insurance payer lookup. Queries FHIR payer resources synced from the EHR with fuzzy matching (alias expansion for common abbreviations like "Blue Cross" to "BCBS", token overlap, and sequence matching). The agent can verify a patient's stated insurance carrier against the practice's accepted payer list during the call.

#### Platform API: Simulation Tags

Simulation runs and sessions now accept an optional `tags` parameter, an array of strings for labeling and filtering. Tags are persisted and returned through create and list endpoints.

#### Platform API: Surface Re-Delivery

Surfaces (agent-generated forms) can now be re-delivered after initial delivery. Previously, the deliver endpoint rejected surfaces that had already been sent. Now only terminal statuses (completed, expired, archived) and pending review block re-delivery. This allows resending form links when a patient loses the original.

#### Platform API: Context Graph Tool Validation

Pushing a context graph now validates that all referenced built-in integration tool IDs exist. Invalid tool references are rejected at push time rather than failing at runtime during calls.

</details>

<details>

<summary>v0.9.58 - Voice Pipeline, Semantic Search &#x26; Connector Architecture (April 13, 2026)</summary>

#### Platform API: Barge-In Improvements

Three changes to voice pipeline barge-in detection:

1. **Recognized speech required** - Barge-in now always requires actual recognized words from the speech-to-text engine. Previously, sustained background noise classified as speech activity for 2 seconds could trigger an interrupt with zero recognized words. This eliminates false interruptions from coughs, breathing, HVAC, and background conversation.
2. **Short phrase support** - The minimum speech duration for barge-in has been lowered significantly. Short responses like "yes," "no," and "okay" (200-400ms) can now trigger barge-in. Previously these finished before reaching the duration threshold and were only processed as end-of-turn events.
3. **Faster end-of-turn interrupt** - When the speech engine detects end-of-turn with a complete transcript, the system now interrupts the agent's audio immediately from the recognition listener rather than waiting for the transcript processing queue. This eliminates 50-200ms of latency on short-phrase interrupts.

#### Platform API: Dynamic Call Forwarding

The `forward_call` tool now accepts an optional `phone_number` parameter (E.164 format) for ad-hoc call forwarding to any number. Previously, call forwarding was limited to pre-configured numbers from EHR location data or static workspace settings. The resolution priority is: explicit phone number (if provided) > location-based lookup (if location\_id provided) > static workspace fallback. Workspaces only need `forward_call_enabled` in their voice configuration to use the tool - no pre-configured forwarding number is required.

#### Platform API: Semantic Entity Search

At this release, the entity-list endpoint accepted `?semantic=<query>` for cosine-similarity ordering against available entity embeddings. It also accepted `?tags=<tag1,tag2>` for array-overlap filtering, and both parameters composed with the other entity filters.

**Current status:** This is a historical v0.9.58 capability. The active entity-list API no longer exposes the `semantic` or `tags` parameters, and current entity projections do not provide semantic entity search. Use the supported text and typed field filters instead.

#### Platform API: Memory Analytics Sample Facts

The memory analytics endpoint now returns a `sample_facts` field on each dimension in the response. Sample facts are representative examples drawn from distinct entities using a windowed sampling approach that guarantees per-dimension coverage. Text is truncated for cache safety.

#### Platform API: Connector Configuration in Workspace Settings

Connector definitions are now managed through workspace settings with typed configuration models. Each connector definition includes a sync strategy field with strict validation, preventing a class of misconfiguration bugs (incorrect strategy values, missing fields). The data source response now includes an `is_stale` field computed from the connector's last successful sync and its configured cadence. Configuration changes are picked up by the connector runner's config refresh loop.

#### Platform API: Asynchronous Entity Projection

Entity state projection is now decoupled from the event write path. Writing an event no longer blocks on recomputing the entity's full state. Events insert immediately, and a background projection process recomputes entity state asynchronously. This reduces write latency for high-throughput scenarios (bulk imports, concurrent agent sessions) while maintaining the same eventual consistency guarantee: entity state reflects all events within seconds of the write.

#### Platform API: Event-Driven Review Queue

The review queue now processes flagged events immediately via event-driven notifications instead of polling on a fixed interval. When the world model writer commits a low-confidence event, it publishes a notification that the review loop picks up and processes within seconds. A periodic safety-net poll (every 5 minutes) catches any events missed by the real-time path. Stale item expiration runs on its own cadence, separate from the review evaluation cycle.

#### Classic API: Tool Repo Files Endpoint Method Change

The tool repository file retrieval endpoint has changed from `GET` to `POST` with a JSON request body. The `ref` and `file_paths` parameters that were previously sent as form/query parameters are now sent in the JSON body. The operation ID (`get-tool-repo-files`) remains unchanged.

#### Classic API: Prompt Log Error Tracking

Prompt logs now include an `errored` field that indicates whether the LLM interaction produced an error. This allows filtering prompt logs to identify failed interactions without downloading and inspecting the full log content.

#### Classic API: Dynamic Behavior Webhook Fix

The `dynamic_behavior_set.version_changed` webhook event now sends the correct body payload. Previously, the webhook body did not match the documented schema when a dynamic behavior set version was created or updated.

#### Platform API: Computer Use RDP Hardening

The Computer Use execution tier now supports production-grade Windows RDP connections with enterprise network configurations:

* **RD Gateway traversal** for reaching desktops behind corporate firewalls
* **RemoteApp mode** for single-application access (launching one application rather than a full desktop session)
* **Terminal farm load balancing** for connecting to pools of application servers
* **Connection health monitoring** between automation rounds with automatic reconnect on transient failures
* **Desktop integration configuration** with 8 new fields for RDP gateway, RemoteApp, load balancing, and security settings

#### Platform API: Computer Use Agent Intelligence

The Computer Use execution tier now includes three intelligence layers that improve reliability on multi-step desktop automation tasks:

* **Context management** - Old screenshots are compacted to text descriptions while retaining the most recent images for visual continuity. This enables long-horizon tasks (more than 3-4 steps) that previously exhausted the model's context window.
* **Reflection agent** - Between automation rounds, a lightweight classifier evaluates whether the task is progressing, stuck in a loop, or complete. If stuck for three consecutive rounds, the task is terminated rather than looping indefinitely. Recovery suggestions are injected when the agent appears off-track.
* **Screen analysis** - UI elements and error states are extracted from screenshots and provided as structured grounding hints, improving click accuracy on complex forms and multi-panel layouts.

Two new desktop actions are also available: clipboard-based typing for Unicode and special characters, and drag operations for selection and drag-and-drop workflows.

#### Platform API: Typed Entity Response Fields

Entity API responses now include 19 typed top-level fields for common attributes: `name`, `phone`, `email`, `birth_date`, `gender`, `mrn`, `status`, `source`, `appointment_status`, `appointment_start`, `appointment_end`, `appointment_type`, `domain`, `industry`, `deal_stage`, `deal_amount`, `direction`, `duration_seconds`, and `call_sid`. These fields are available on all entity types (returning `null` when not applicable) and replace the need to parse the unstructured `state` object. The `state` field is now deprecated - it will continue to be returned for backward compatibility but consumers should migrate to the typed fields.

#### Platform API: Entity Projection Pipeline

Entity state projection now runs as a continuous streaming pipeline. Entity projections are computed from the event stream and updated continuously as new events arrive. This replaces the previous interval-based background task with a streaming architecture that reduces projection latency and scales independently of the agent engine.

#### Classic API: Cached Token Metering

A new `cached-token-count` usage event is now emitted alongside the existing `input-token-count` event. This tracks how many input tokens were served from the prompt cache versus computed fresh, enabling more granular cost analysis and cache hit rate monitoring.

</details>

<details>

<summary>v0.9.57 - Computer Use Execution Tier (April 13, 2026)</summary>

#### Platform API: Computer Use Execution Tier

Skills now support a fifth execution tier: **Computer Use**. This enables any agent skill to interact with desktop applications (browsers, remote desktop sessions, and VNC connections) through a multi-turn automation loop.

The agent connects to a desktop session, reads screen content, and performs actions (clicking, typing, navigating) to complete tasks in systems that do not expose APIs. This is particularly relevant in healthcare, where many EHR platforms, insurance portals, and practice management tools are accessible only through their web or desktop interfaces.

Key capabilities:

* **Browser automation** for web-based portals and applications
* **Remote desktop (RDP)** and **VNC** connections for legacy desktop applications
* **Multi-turn interaction loops** that handle multi-step UI workflows (login, navigate, fill forms, extract results)
* **Structured result extraction** - the skill returns structured data back to the calling agent, not raw screenshots

Computer Use tasks run with the same confidence scoring, audit logging, and review pipeline as other tool types. The execution tier is configured per skill, so workspaces control which skills have desktop access.

The five skill execution tiers are now: Direct (single LLM call), Orchestrated (multi-turn with tools), Autonomous (extended agent loops), Browser (headless web automation), and Computer Use (full desktop automation).

</details>

<details>

<summary>v0.9.56 - EHR Integration Improvements &#x26; Appointment Data Quality (April 13, 2026)</summary>

#### Platform API: Expanded EHR Outbound Write-Back

The outbound sync engine now supports write-back to additional EHR systems via SMART Backend Services (FHIR). The new handler supports both deferred mode (queues changes until the target system enables write access) and live mode (immediate FHIR resource creation). This brings the total number of EHR systems with bidirectional sync to four.

#### Platform API: Connector Authentication Expansion

The SMART Backend Services authentication flow now supports additional JWT signing configurations for service account authentication. This expands the set of EHR systems and cloud healthcare services that can use machine-to-machine authentication for data exchange.

#### Platform API: Appointment Cancellation Handling

Appointment projections now correctly detect cancellations synced from EHR systems. Previously, cancellations were only recognized when sent as explicit cancellation events. Now, appointments with a cancelled status are detected regardless of the event type used by the source system. This fixes a data quality issue where EHR-synced cancellations could appear as active appointments.

</details>

<details>

<summary>v0.9.52 - Data-Platform-First Memory (April 10, 2026)</summary>

#### Platform API: Data-Platform-First Memory

Memory dimension scores and entity facts are now served from pre-computed tables populated by a background pipeline, replacing the previous inline extraction approach. This eliminates query-time computation overhead and provides faster, more consistent reads.

Key changes:

* **Dimension endpoint** (`GET /v1/{ws}/memory/{entity_id}/dimensions`) reads pre-aggregated per-dimension stats (fact count, average confidence, source count, latest fact timestamp)
* **Facts endpoint** (`GET /v1/{ws}/memory/{entity_id}/facts`) now includes an `extracted_text` field on each fact: a pre-computed human-readable summary of the fact's content. Previously, callers had to parse the raw event data themselves.
* **Analytics endpoint** (`GET /v1/{ws}/memory/analytics`) is unchanged; it still queries live event data for workspace-level aggregation

The background pipeline runs as part of post-session processing. Newly ingested data is available in memory query results within seconds of pipeline completion. No API signature changes: existing integrations continue to work, and the `extracted_text` field is additive.

</details>

<details>

<summary>v0.9.51 - Behavior Settings, Sim Call Adapter &#x26; Outbound Prewarm (April 9, 2026)</summary>

#### Platform API: Behavior Settings

New workspace-level settings endpoint for managing dynamic behavior configurations:

| Endpoint                      | Method | Description                   |
| ----------------------------- | ------ | ----------------------------- |
| `/v1/{ws}/settings/behaviors` | `GET`  | Get current behavior settings |
| `/v1/{ws}/settings/behaviors` | `PUT`  | Update behavior settings      |

Stores tool-level behavioral directives with keyword, emotion, and state triggers. The Developer Console reads from this endpoint for its Behaviors management page.

#### Platform API: Simulation Call Adapter

Simulated coverage sessions now appear alongside real calls in the calls page. The call list endpoint supports an `include_simulated` parameter and `direction=simulated` filter. Call detail falls back to the simulation adapter when a call ID is not found in the real call store, so simulation sessions are accessible through the same call detail interface used for production calls.

#### Platform API: Streaming Playground

Playground and simulation sessions now stream LLM tokens in real time through the observer bus. Frontends connect via WebSocket and see tokens, tool calls, and state transitions as they happen, using the same streaming infrastructure as live voice sessions.

#### Performance: Outbound Call Prewarm

Outbound calls now prewarm the engine during the dialing/ringing phase (5-15 seconds before patient answers). When the patient picks up, the engine and greeting are already initialized. Eliminates approximately 3 seconds of dead air at the start of outbound calls.

#### Performance: Function Catalog Warmup

Platform function catalog discovery is now cached, eliminating a cold start delay on the first call in a workspace. Subsequent calls resolve the function catalog in under 1ms.

#### Platform API: LLM Extraction for Custom Memory Dimensions

Custom memory dimensions now support an `extraction_mode` field: `static` (JSONPath, deterministic) or `llm` (semantic extraction using the dimension's description as a prompt). Built-in dimensions use static extraction. Custom dimensions default to LLM extraction for handling nuanced, context-dependent information.

</details>

<details>

<summary>v0.9.49 - Memory Settings, Email Channel &#x26; Hazel EHR (April 8, 2026)</summary>

#### Platform API: Memory Dimension Settings

New workspace-level API for configuring memory dimensions. Six built-in dimensions (clinical, behavioral, operational, social, engagement, risk) ship as defaults. Workspaces can add custom dimensions, adjust weights, or deactivate built-ins without code changes.

| Endpoint                   | Method | Description                                |
| -------------------------- | ------ | ------------------------------------------ |
| `/v1/{ws}/settings/memory` | `GET`  | Get current memory dimension configuration |
| `/v1/{ws}/settings/memory` | `PUT`  | Update memory dimension configuration      |

Changes take effect on the next post-session processing run. The memory pipeline reads configuration dynamically.

#### Platform API: Email Channel

Native email delivery for surfaces via workspace-configured email provider. Surface delivery now supports email as a first-class channel alongside SMS and WhatsApp, with the same lifecycle tracking (delivered, opened, submitted) and real-time events.

#### Platform API: Hazel EHR Adapter

New EHR connector adapter for Hazel Health systems. Supports inbound polling (patients, visits, time slots, insurance records) and outbound write-back (visit creation, cancellation, rescheduling, insurance card upload, confirmation logging).

#### Fix: Soft Escalation Without Crisis Flag

Fixed a bug where the conversation monitor's `soft_escalate` action was silently discarded when the crisis flag was not set. Non-emergency operator handoff requests (e.g., caller asking to speak with a human) now correctly trigger escalation and fire the `call.escalated` event to the operator command center.

</details>

<details>

<summary>v0.9.48 - Simulation Coverage, Multi-Step Forms &#x26; Tool Migration (April 8, 2026)</summary>

#### Platform API: Simulation Coverage (Branch-and-Bound)

New coverage testing API that systematically explores context graph state space using branch-and-bound exploration. Replaces the previous exploration-based simulation model with a knowledge graph that tracks every turn individually.

| Endpoint                                            | Method | Description                                                                 |
| --------------------------------------------------- | ------ | --------------------------------------------------------------------------- |
| `/v1/{ws}/simulations/coverage/runs`                | `POST` | Create a coverage run with an ephemeral database branch for write isolation |
| `/v1/{ws}/simulations/coverage/runs/{id}/sessions`  | `POST` | Create a conversation session within a run                                  |
| `/v1/{ws}/simulations/coverage/sessions/{id}/step`  | `POST` | Step a session forward with a simulated user message                        |
| `/v1/{ws}/simulations/coverage/sessions/{id}/fork`  | `POST` | Fork a session into N children at a decision point (core B\&B primitive)    |
| `/v1/{ws}/simulations/coverage/sessions/{id}/score` | `POST` | Score a session against configured metrics                                  |
| `/v1/{ws}/simulations/coverage/runs/{id}/graph`     | `GET`  | Retrieve the coverage knowledge graph with topology overlay and ghost nodes |
| `/v1/{ws}/simulations/coverage/runs/{id}/complete`  | `POST` | Complete a run and clean up ephemeral branches                              |

The knowledge graph includes observed turns (per-state session counts, pass rates, turn counts) and a topology overlay with ghost nodes for context graph states never reached in any session. The fork primitive atomically clones parent session state N times, steps each with a different simulated message, and returns all observations.

{% hint style="warning" %}
**Breaking**: Previous simulation exploration endpoints (`sim_explorations`, `sim_conversations`) have been removed and replaced by the coverage API. Console updated in v2.22.0.
{% endhint %}

#### Platform API: Multi-Step Surface Forms

Surface forms with sections now render as stepped pages with progress bar, Next/Back navigation, and per-step field validation. Single-section and no-section forms continue to render as a single page (backward compatible).

#### Platform API: Gap Scanner Appointment Detection

The gap scanner now detects upcoming appointments using a batch query that joins entity relationships with appointment events at scan time. This runs once per workspace per tick and reads current event state directly, so appointment updates (cancellations, rescheduling) are reflected immediately.

#### Platform API: Legacy Tool Execution Removed

All workspaces have been migrated from the legacy serverless tool execution infrastructure to the platform's built-in tool system. The legacy tool executor and its associated configuration have been removed. Existing tool definitions continue to work; only the execution backend changed. This removes an external compute dependency and simplifies the deployment footprint.

</details>

<details>

<summary>v0.9.47 - Personas, Workflows &#x26; New Clinical Primitives (April 7, 2026)</summary>

#### Platform API: Personas

New first-class resource for cross-channel agent identity. A Persona defines who the agent is (name, role, background, communication style) independently of how it communicates (voice configuration, channel type). Services now reference a `persona_id` instead of embedding identity fields directly.

| Endpoint                 | Method   | Description                         |
| ------------------------ | -------- | ----------------------------------- |
| `/v1/{ws}/personas`      | `POST`   | Create a persona                    |
| `/v1/{ws}/personas`      | `GET`    | List personas (paginated, sortable) |
| `/v1/{ws}/personas/{id}` | `GET`    | Get a specific persona              |
| `/v1/{ws}/personas/{id}` | `PUT`    | Update a persona                    |
| `/v1/{ws}/personas/{id}` | `DELETE` | Delete a persona                    |

Services display the associated `persona_name` alongside the persona ID for easier identification.

#### Platform API: Environment & Workflow Settings

Two new workspace settings resources for configuration management:

* **Environment settings** (`GET/PUT /v1/{ws}/settings/environments`) - Per-environment configuration overlays (sandbox vs production). Services reference an environment, and the overlay provides tool and data source overrides. Audit-logged.
* **Workflow settings** (`GET/PUT /v1/{ws}/settings/workflows`) - Declarative multi-step workflow specifications stored at the workspace level. Enables structured, repeatable operational workflows that agents can follow.

#### Platform API: Queue & Ticket Tools

Two new built-in clinical tools:

| Tool            | Type  | Description                                                                                                                                                                                                                                       |
| --------------- | ----- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `queue_lookup`  | Read  | Reads outbound task entities from the world model, returning pending/scheduled tasks ordered by priority or next attempt time. Filterable by status (scheduled, dispatched, completed, failed, cancelled, snoozed).                               |
| `ticket_create` | Write | Creates a support ticket event for a patient entity. Writes a `ticket.created` event that flows through outbound sync to the workspace's ticketing or CRM system. Supports title, description, priority (low/normal/high/critical), and category. |

#### Platform API: Charm EHR Adapter

New EHR connector adapter for Charm systems. Supports patient polling, appointment reference data sync, and outbound appointment writes with CRM engagement tracking.

#### Platform API: Data Collection in Context Graphs

Context graphs can now include declarative data collection specifications. Instead of relying solely on the agent to identify missing data, context graph states can define what data must be collected and the system handles field rendering, validation, and world model integration automatically.

#### Breaking: Legacy Tool Aliases Removed

Legacy tool name aliases have been removed. All built-in clinical tools now use their canonical names only. Context graphs referencing the old names are automatically migrated.

#### Platform API: Multi-Number WhatsApp

WhatsApp messaging now supports multiple sender numbers per workspace with per-organization credential scoping. This enables workspaces to use different WhatsApp numbers for different services or departments.

</details>

<details>

<summary>v0.9.46 - Clinical Tools Expansion &#x26; Meditab EHR Adapter (April 6, 2026)</summary>

#### Platform API: New Clinical Tools

Three new built-in tools available during voice and text interactions:

| Tool                     | Type  | Description                                                                                                                                                                                                                     |
| ------------------------ | ----- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `log_call`               | Write | Records call outcome events (appointment booked, confirmed, declined, no answer, rescheduled, voicemail left, callback requested). Outcomes flow through outbound sync to source systems for reporting and workflow automation. |
| `reschedule_appointment` | Write | Reschedules an existing appointment to a new slot. Cancels the original and books the replacement atomically.                                                                                                                   |
| `save_patient`           | Write | Combined create-or-update operation. Updates an existing patient when entity ID is provided, or creates a new record with duplicate checking when not. Accepts flexible date formats and natural field names.                   |

#### Platform API: World Tool Prefix

Built-in clinical tools have been renamed to use a consistent naming convention. The previous tool names continue to work as legacy aliases, so no migration is required.

#### Platform API: Meditab EHR Adapter

New EHR connector adapter for Meditab systems. Uses SMART Backend Services authentication for standards-based connectivity. Supports appointment slot search and scheduling operations through the connector runner.

</details>

<details>

<summary>v0.9.45 - Database-Level Workspace Isolation (April 6, 2026)</summary>

#### Platform API: Database-Level Workspace Isolation

Workspace data isolation is now enforced at the database layer in addition to application-level access controls. Every data query is automatically scoped to the current workspace before execution, so no code path can access data across workspace boundaries.

This is a defense-in-depth measure for healthcare deployments where data isolation is a compliance requirement:

* **Fail-closed design** - If workspace context is missing from a request, the query returns zero rows rather than defaulting to unscoped access
* **Full coverage** - Applies to all data tables: events, entities, entity relationships, data sources, sessions, calls, surfaces, and configuration
* **Independent safety net** - Database-level enforcement cannot be bypassed by application code, even in the event of a bug in the API layer

Application-level access controls (API keys, role-based permissions) remain the primary access mechanism. The database layer provides an independent guarantee that data never leaks between workspaces.

#### Platform API: Observer Rate Limiting

The real-time observer connection endpoint now uses concurrent connection gauges with per-IP burst limits instead of flat rate limiting. This improves reliability for dashboards and monitoring tools that maintain persistent connections.

</details>

<details>

<summary>v0.9.44 - Branding Settings, Surface Rendering &#x26; Tool Repo Deprecation (April 6, 2026)</summary>

#### Platform API: Workspace Branding Settings

New branding settings endpoints let workspaces configure default visual branding for all patient-facing surfaces. Surface-level branding overrides workspace-level defaults, giving per-surface control when needed.

| Endpoint                     | Method | Description                               |
| ---------------------------- | ------ | ----------------------------------------- |
| `/v1/{ws}/settings/branding` | `GET`  | Get workspace default branding (any role) |
| `/v1/{ws}/settings/branding` | `PUT`  | Update workspace branding (admin/owner)   |

Branding configuration fields:

| Field              | Type   | Description                        |
| ------------------ | ------ | ---------------------------------- |
| `logo_url`         | string | Logo image URL (max 2048 chars)    |
| `primary_color`    | string | Primary brand color (max 32 chars) |
| `background_color` | string | Background color (max 32 chars)    |
| `font_family`      | string | Font family name (max 256 chars)   |

Workspace branding is automatically merged into surface rendering. Surfaces without their own branding inherit the workspace defaults. Changes are audit-logged.

#### Platform API: Dedicated Surface Rendering

Patient-facing surfaces now render through a dedicated web application instead of server-side HTML generation. The rendering app fetches the surface spec, saved field values, and merged branding via API, then renders a mobile-first form experience with:

* **Auto-save** - Individual fields are persisted as the patient fills them in
* **Workspace branding** - Logo, colors, and fonts applied automatically from workspace and surface-level settings
* **Improved error handling** - Distinct pages for expired, archived, and already-submitted surfaces

The patient-facing URL structure and token-based authentication are unchanged. Existing surface links continue to work.

#### Platform API: New Field Types

Two new surface field types for informational content within forms:

| Type    | Value     | Use Case                                  |
| ------- | --------- | ----------------------------------------- |
| Heading | `heading` | Section headers within longer forms       |
| Info    | `info`    | Read-only explanatory text between fields |

These are display-only fields; they do not collect data or appear in submissions.

#### Platform API: Surface Sections

Surfaces now support multi-page forms through sections. Each section groups fields into a page with its own title and description, creating a step-by-step experience for longer forms.

#### Classic API: Tool Repository Deprecated

All tool repository browsing endpoints have been removed. This includes branch listing, commit history, file browsing, directory listing, and diff viewing. Tool source code is now managed exclusively through the Agent Forge CLI and direct repository access.

The following endpoints are no longer available:

* `GET /v1/{org}/tool/repo/branch`
* `GET /v1/{org}/tool/repo/commit`
* `GET /v1/{org}/tool/repo/directory/{path}`
* `GET /v1/{org}/tool/repo/file`
* `GET /v1/{org}/tool/repo/file/{path}`
* `POST /v1/{org}/user/{id}/tool-repo-access`
* `DELETE /v1/{org}/user/{id}/tool-repo-access`

Tool publishing, versioning, and execution are unaffected.

</details>

<details>

<summary>v0.9.43 - Full-Fidelity Simulation &#x26; Call Intelligence (April 3, 2026)</summary>

#### Platform API: Full-Fidelity VoiceSim

VoiceSim now runs the full reasoning pipeline for each simulation step: real language model conversations, real tool execution, and real empathy classification. Previously, simulations used a simplified evaluation path. Now the same reasoning engine that powers live calls drives simulation, producing authentic results that match production behavior.

* **Real tool execution** - Simulated calls invoke the same tools as live calls (scheduling, patient lookup, FHIR operations), with results feeding back into the conversation loop.
* **Empathy classification** - Emotional responsiveness is evaluated in real time during simulation, so empathy-related configuration changes produce representative results.
* **Branch-isolated writes** - All tool-generated data writes during simulation go to an ephemeral database branch, preventing simulation artifacts from reaching production data.

#### Platform API: Sim Call Intelligence

Each VoiceSim evaluation step now produces call intelligence metrics: quality scores and analytics computed at session end. This is the same scoring pipeline used for live call monitoring, enabling direct comparison between simulated and production quality.

</details>

<details>

<summary>v0.9.42 - Voice Simulation &#x26; Egress IPs (April 2, 2026)</summary>

#### Platform API: Voice Simulation (VoiceSim)

New API for systematically exploring voice configuration space. VoiceSim evaluates configurations across 18 dimensions (barge-in, speed, empathy, safety, context, silence, tools, filler) against 8 built-in scenarios, scoring results with a quality oracle that penalizes dead air, greeting interruption, crisis response delays, and safety violations.

| Endpoint                      | Method | Description                                                                   |
| ----------------------------- | ------ | ----------------------------------------------------------------------------- |
| `/v1/{ws}/sims`               | `POST` | Create a simulation run                                                       |
| `/v1/{ws}/sims`               | `GET`  | List runs (newest first, paginated)                                           |
| `/v1/{ws}/sims/{id}/evaluate` | `POST` | Score a single (configuration, scenario) pair                                 |
| `/v1/{ws}/sims/{id}/sample`   | `POST` | LHS sample N points and evaluate all against all scenarios                    |
| `/v1/{ws}/sims/{id}`          | `GET`  | Run status and best results                                                   |
| `/v1/{ws}/sims/{id}/summary`  | `GET`  | Aggregated: best per scenario, penalty frequency, config diff from production |
| `/v1/{ws}/sims/{id}/points`   | `GET`  | Scored points (order by score or time)                                        |
| `/v1/{ws}/sims/{id}/complete` | `POST` | Mark run finished, clean up branches                                          |

Sim runs execute against isolated database branches for write safety. SSE workspace events provide live progress for the Developer Console UI.

#### Platform API: Egress IPs Endpoint

|              |                                                         |
| ------------ | ------------------------------------------------------- |
| **Endpoint** | `GET /v1/{workspace_id}/network/egress-ips`             |
| **Auth**     | Workspace API key (any role)                            |
| **Returns**  | Static NAT gateway IP addresses, region, usage guidance |

Customers can self-serve firewall allowlisting for EHR/CRM data source connectivity without contacting support.

</details>

<details>

<summary>v0.9.41 - Tool Testing Playground (April 2, 2026)</summary>

#### Platform API: Tool Testing Endpoints

New endpoints for testing HSM tools (world tools, skills, integrations) from the Developer Console without making a phone call. Test writes are source-isolated so no real EHR syncs, SMS deliveries, or surface deliveries occur.

|              |                                                                                                                                      |
| ------------ | ------------------------------------------------------------------------------------------------------------------------------------ |
| **Endpoint** | `POST /v1/{workspace_id}/tools/execute`                                                                                              |
| **Auth**     | Workspace API key (admin/owner only, requires `tools:test` scope)                                                                    |
| **Body**     | `tool_type` (clinical tool, skill, integration), `tool_name`, `service_id`, `input_params`, optional `entity_id`, optional `dry_run` |
| **Returns**  | Execution result, duration, tier, sub-tool call logs, blocked side effects                                                           |

|              |                                                                                                                    |
| ------------ | ------------------------------------------------------------------------------------------------------------------ |
| **Endpoint** | `GET /v1/{workspace_id}/services/{service_id}/tools/resolve`                                                       |
| **Auth**     | Workspace API key (admin/owner only)                                                                               |
| **Returns**  | List of available tools for the service with name, type, description, input schema, tier, and write classification |

**Safety guardrails:**

* All writes tagged with `source="tool_test"`, excluded from outbound sync allowlist
* Surface delivery is blocked for tool test sources
* Dry run mode simulates write operations without persistence

#### Agent Background Field Limit Increase

The `background` field on agent versions now accepts up to **10,000 characters** (previously 2,000). This accommodates rich persona descriptions, detailed domain knowledge, and extensive behavioral guidelines without truncation. Other text fields (name, description) retain their existing limits.

</details>

<details>

<summary>v0.9.40 - Source Overview, Pagination Totals &#x26; Query Improvements (April 1, 2026)</summary>

#### Source Pipeline Overview

New endpoint for inspecting the health of individual data sources in the pipeline:

|              |                                                                                                              |
| ------------ | ------------------------------------------------------------------------------------------------------------ |
| **Endpoint** | `GET /v1/{workspace_id}/pipeline/sources/{source_id}/overview`                                               |
| **Auth**     | Workspace API key (viewer+)                                                                                  |
| **Returns**  | Aggregated overview of a source's pipeline health: event counts by status, last sync time, and error summary |

Use this to monitor individual source health without polling the full pipeline status endpoint.

#### Pagination Totals

All paginated list responses across the Platform API now include a `total` field with the total count of matching records, not just the current page. This applies to every endpoint that returns `items`, `has_more`, and `continuation_token`.

#### Multi-Value Source Type Filtering

The data sources list endpoint (`GET /v1/{ws}/data-sources`) now accepts repeatable `source_type` query parameters for filtering by multiple source types in a single request (e.g., `?source_type=ehr&source_type=smart_fhir`).

#### FHIR Patient Sort Parameter

`GET /v1/{ws}/fhir/patients` now accepts a `sort_by` parameter with `+/-` prefix for sort direction. For example, `-last_event_at` returns patients sorted by most recent activity first, and `+created_at` returns patients sorted by creation date ascending.

</details>

<details>

<summary>v0.9.39 - HSM Extensions, Surface SMS Trust &#x26; Entity Recomputation (April 1, 2026)</summary>

#### Context Graph Action State Extensions

Three new optional fields on action states enable asynchronous workflows where the agent pauses mid-conversation, waits for external input, and resumes:

| Field                   | Description                                                                                                                                                                                           |
| ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `wait_for`              | Pause HSM navigation until a condition clears (`surface_submission` or `human_approval`). While waiting, the agent stays in the current state and makes empathetic small-talk.                        |
| `channel_overrides`     | Per-channel overrides for `objective`, `action_guidelines`, and `suppress_filler`. Keyed by channel kind (`voice`, `sms`). Allows the same context graph to behave differently across voice and text. |
| `surface_spec_template` | Surface spec auto-created on state entry. Uses the same schema as `POST /surfaces`. Entity ID defaults to the session's primary entity.                                                               |

Text sessions set `channel_kind = "sms"` on the engine session for channel override resolution. Wait conditions in text sessions use a dedicated event listener that blocks until `surface.submitted` or `surface.review_approved` arrives.

#### vCard Contact Cards for SMS Delivery

SMS surface delivery now sends a vCard contact card before the form link. iOS blocks clickable links in SMS from unknown senders; once the patient saves the contact, iOS trusts the sender and renders subsequent links as tappable.

The delivery endpoint performs a two-step send:

1. A vCard 3.0 attachment with the workspace's business name and phone number
2. The form link in a second message

vCard delivery is best-effort: if it fails, the form link is still sent. A new public endpoint serves the vCard file:

|              |                                                     |
| ------------ | --------------------------------------------------- |
| **Endpoint** | `GET /s/vcard/{workspace_slug}.vcf`                 |
| **Auth**     | None (public)                                       |
| **Response** | `text/vcard` with `Content-Disposition: attachment` |

#### Short Surface URLs

Surface links in SMS messages now use short redirect URLs (`/s/f/{surface_id}`) instead of the full HMAC-signed token URL. The short URL generates a fresh token server-side and issues a 302 redirect to the full surface page. This keeps SMS bodies compact and avoids carrier truncation of long URLs.

|               |                                                                |
| ------------- | -------------------------------------------------------------- |
| **Endpoint**  | `GET /s/f/{surface_id}`                                        |
| **Auth**      | None (public)                                                  |
| **Responses** | `302` redirect to `/s/{token}`, `404` not found, `410` expired |

The delivery response now includes `short_url` and `vcard_url` in the metadata.

#### Surface Entity Linking & State Recomputation

Surface lifecycle events (created, delivered, opened, submitted) are now linked to the entity on the event row, not just in the event data payload. This means surface events appear in entity timeline queries and contribute to entity state.

When a patient submits a surface, entity state recomputation runs within the same transaction. Submitted form data flows into entity demographic and clinical projections immediately, with no background job delay.

</details>

<details>

<summary>v0.9.38 - Text Agent Sessions &#x26; Surface Consent Gating (April 1, 2026)</summary>

#### Text Agent Sessions (SMS HSM Conversations)

The voice agent now supports full SMS-based conversations using the same context graph (HSM) engine that powers voice calls. A new `POST /voice-agent/create_outbound_text` endpoint creates an outbound text session that sends a greeting and conducts a multi-turn conversation over SMS.

| Parameter                     | Type              | Description                                       |
| ----------------------------- | ----------------- | ------------------------------------------------- |
| `phone_to` / `phone_from`     | string (E.164)    | Patient and agent phone numbers                   |
| `workspace_id` / `service_id` | string            | Workspace and service (agent) to run              |
| `entity_id`                   | string (optional) | World model entity ID for patient context loading |
| `surface_id`                  | string (optional) | Surface to deliver inline in the conversation     |
| `idempotency_key`             | string (optional) | Client dedup key (cached 5 minutes)               |

Rate limited to 20 per workspace per minute. Returns `session_id`, `status`, and `conversation_id`.

Inbound SMS (patients texting the agent's number) also creates text sessions automatically when no active session exists for that phone pair. The SMS webhook now validates that the target service supports text channels before spawning a session.

#### SMS Consent Enforcement

All outbound SMS, across both text agent sessions and surface delivery, now checks patient consent before sending. If a patient has opted out by texting STOP, UNSUBSCRIBE, CANCEL, END, or QUIT, the system blocks outbound messages and returns `403 Forbidden`.

Consent is tracked per patient per workspace, cached for fast lookups, and enforced at the application layer independently of carrier-level STOP handling.

#### Gap Scanner Auto-Delivery

The connector runner's gap scanner can now auto-deliver surfaces by triggering outbound text conversations. When `auto_deliver` is enabled in gap scanner settings and the surface channel is SMS, the scanner calls `create_outbound_text` to start a text conversation that delivers the surface inline, giving the patient context about why they are being asked rather than sending a bare link.

| Setting                   | Description                                              |
| ------------------------- | -------------------------------------------------------- |
| `auto_deliver`            | Enable automatic delivery of SMS surfaces (default: off) |
| `auto_deliver_service_id` | Service (agent) to use for the text conversation         |
| `sms_from_number`         | Agent phone number for outbound SMS                      |

Auto-delivery is best-effort: failures are logged but never block the scanner.

</details>

<details>

<summary>v0.9.37 - Platform API: API Key Rotation, Workspace Archive &#x26; Access Audit (April 1, 2026)</summary>

#### API Key Rotation

New `POST /api-keys/{key_id}/rotate` endpoint replaces a key's secret in a single atomic operation. The old secret stops working immediately and the response includes the new plaintext key exactly once. Accepts `duration_days` (1-90) for the rotated key's expiration. The rotated key inherits the original's name, role, and permissions.

API key responses now include a `last_used_at` timestamp for identifying stale keys.

#### Workspace Archive

New `POST /workspaces/{workspace_id}/archive` endpoint archives a workspace without deleting underlying data. Requires `owner` role and a slug confirmation in the request body to prevent accidental archival. Archived workspaces no longer appear in workspace listings.

#### Workspace Invitation Preview

New `GET /invitations/{invitation_id}/preview` endpoint returns a safe public view of a workspace invitation (workspace name, role, expiry, status) without requiring authentication. Designed for rendering invitation landing pages before the invited user signs in.

#### Workspace Access Audit Logging

All workspace membership and invitation operations now emit structured audit events:

* `workspace.member_added` - Member created or reactivated
* `workspace.invitation_sent` - Invitation created or resent
* `workspace.invitation_accepted` / `workspace.invitation_declined` - Invitation resolved
* `workspace.invitation_revoked` - Invitation revoked by admin

Each event records the actor entity, target entity/email, role, and contextual metadata (e.g., whether a member was reactivated vs newly created). Events are available through the audit log endpoints and compliance export.

</details>

<details>

<summary>v0.9.36 - Platform API: FHIR Resource History, Entity Cross-Referencing &#x26; Sync Filters (March 31, 2026)</summary>

#### FHIR Resource History

New endpoint `GET /fhir/resources/{resource_type}/{resource_id}/history` returns the version history for a single FHIR resource. Each history entry includes:

| Field                      | Description                                                            |
| -------------------------- | ---------------------------------------------------------------------- |
| `event_id`                 | Unique event identifier                                                |
| `event_type`               | Type of change (e.g., `create`, `update`)                              |
| `source` / `source_system` | Where the change originated                                            |
| `confidence`               | Data confidence level                                                  |
| `is_current`               | Whether this is the active version                                     |
| `fields_affected`          | List of FHIR field paths that changed compared to the previous version |
| `synced_at` / `sync_error` | Outbound sync status                                                   |
| `data`                     | Full FHIR resource payload at this version                             |

The `fields_affected` diff is computed server-side by comparing each version's data against its predecessor, walking nested objects to produce dot-path field names (e.g., `name.0.given`, `telecom.0.value`). Supports pagination via `limit` (1-50, default 10) and `offset` with `has_more` / `next_offset` in the response.

#### FHIR Entity Cross-Referencing

FHIR resource responses now include an `entity_id` field that links each FHIR resource to its corresponding world model entity. This applies to resource reads, creates, and updates, so every FHIR resource operation now returns the entity it resolved to (or `null` if no entity link exists yet). Enables direct navigation between FHIR resources and world model entities without a separate lookup.

#### Scoped Sync Failure Filtering

The FHIR sync failures endpoint (`GET /fhir/sync-failures`) now supports two new query parameters:

| Parameter            | Type   | Description                                                                       |
| -------------------- | ------ | --------------------------------------------------------------------------------- |
| `fhir_resource_type` | string | Filter failures to a specific FHIR resource type (e.g., `Patient`, `Appointment`) |
| `fhir_resource_id`   | string | Filter failures to a specific FHIR resource ID                                    |

The `total` field in the response now returns an accurate count matching the applied filters, rather than the number of returned items.

#### World Sync Queue Filters

The world sync events endpoint (`GET /world/sync`) adds the same two filters:

| Parameter            | Type   | Description                                         |
| -------------------- | ------ | --------------------------------------------------- |
| `fhir_resource_type` | string | Filter sync events to a specific FHIR resource type |
| `fhir_resource_id`   | string | Filter sync events to a specific FHIR resource ID   |

These complement the existing `status`, `data_source_id`, and `source_system` filters, enabling precise investigation of sync issues for individual resources.

#### Data Source Sync History

The data source sync history response now includes `fhir_resource_id` in failure records, making it possible to identify exactly which FHIR resource failed to sync from the data source detail view.

</details>

<details>

<summary>v0.9.35 - Voice Agent: Empathy-First Pipeline (March 31, 2026)</summary>

#### Empathy Tier Classification

The voice agent now classifies each caller turn into an empathy tier before generating a response. The classifier is rule-based (no LLM call, sub-100ms) and gates pipeline behavior, not just response style, but whether to speak, how much to say, and whether to advance the task at all.

| Tier | Name         | Behavior                                                          |
| ---- | ------------ | ----------------------------------------------------------------- |
| T0   | Functional   | Normal task-oriented pipeline                                     |
| T1   | Light Touch  | Empathy filler before task content                                |
| T2   | Full Empathy | 0.5s pause, empathy-first response, task secondary                |
| T3   | Hold Space   | 1s pause, pure empathy, zero task advancement, fillers suppressed |

Classification uses transcript keywords, emotion signals (valence, arousal, dominant emotion), and emotional trend across recent turns. Includes negation detection ("I'm not worried"), idiomatic exclusions ("dying to know"), and resolved-emotion handling ("I was worried but I'm fine now").

#### Empathy-Gated Filler and TTS

* **Anti-filler silence** - T2 inserts a 0.5s pause before any filler. T3 suppresses fillers entirely.
* **TTS presence mode** - Empathy fillers play at 0.85x speed with neutral emotion, avoiding uncanny vowel stretching on short phrases.
* **Filler taxonomy** - Fillers are now typed as `empathy`, `receipt`, or `working` based on the empathy tier, replacing the previous single filler category.

#### Empathy Baseline Decay

After distress, an empathy baseline decays at 0.15 per turn, preventing the agent from snapping back to a transactional tone immediately after a caller was upset. The baseline persists across turns and is reported in the `empathy_classified` observer event.

#### Engage Prompt Hardening

* Banned-word list prevents filler-plus-acknowledgement stacking (the agent no longer opens with "Okay" or "Sure" after a filler was already spoken).
* At T2+, the response generation prompt forces empathy-first responses. At T3, the entire response is empathy with zero task content.

</details>

<details>

<summary>v0.9.34 - Platform API: Surface SMS Delivery (March 31, 2026)</summary>

#### Real SMS Delivery for Surfaces

The `POST /surfaces/{id}/deliver` endpoint now sends surfaces to patients via SMS. When a phone number is provided as the `channel_address`, the platform resolves Twilio credentials from the workspace's configured phone numbers and sends the surface URL directly.

* **SMS delivery** - Surface URL sent via SMS with title as message body. Phone numbers validated against E.164 format.
* **Delivery metadata** - Response now includes `message_id` (provider SID), `from_number`, `delivery_provider`, and `delivered_at` for tracking and audit.
* **Voice agent integration** - The `create_surface` voice agent tool now supports delivery context, enabling the agent to create and deliver surfaces during live calls.

Previously, surfaces generated signed URLs that required manual distribution. Now the full create-to-deliver flow works end-to-end through the API.

</details>

<details>

<summary>v0.9.33 - Platform API: Search &#x26; Pagination Improvements (March 31, 2026)</summary>

#### Data Source Search

The `GET /data-sources` endpoint now accepts a `search` query parameter for filtering data sources by name, ID, source type, or sync status.

#### Patient Search Pagination

The `GET /fhir/patients` endpoint now returns proper pagination metadata:

* `has_more` (boolean) - whether additional results exist beyond the current page
* `next_offset` (integer) - offset for the next page, included only when `has_more` is true

Phone and MRN searches now also support offset-based pagination. The `q` parameter searches across name, MRN, phone, and entity ID.

#### Pipeline & Entity Query Hardening

* Pipeline endpoints now validate UUID parameters and return 400 on malformed IDs instead of 500
* Entity search and registry endpoints use consistent parameter cleaning

</details>

<details>

<summary>v0.9.32 - Platform API: Charm EHR Integration (March 30, 2026)</summary>

#### Charm EHR Inbound Adapter

New `charmhealth` connector type and external system for Charm Health EHR. Provides inbound data exchange via Charm's FHIR R4 API (US Core IG STU 3.1.1).

* **New source type** - `charmhealth` for inbound polling from Charm Health.
* **New connector type** - `charmhealth` for workspace configuration.
* **Dual-header authentication** - OAuth2 Bearer token + practice-level API key on every request. Token management handles exchange, refresh, and fallback to re-authentication.
* **Page-based pagination** - Adapts to Charm's non-standard integer page parameter instead of FHIR Bundle `next` links.
* **Adaptive rate limiting** - Automatic backoff with jitter on HTTP 429 responses, with configurable retry limits.
* **15 resource types** - Tiered by change frequency: Appointment (real-time), Patient/Encounter/Condition/MedicationRequest/Observation/AllergyIntolerance/Immunization/Goal (standard), Practitioner/Location/CareTeam/CarePlan/DiagnosticReport (slow), Organization (daily).
* **New config field** - `api_key_ssm_path` on connection config for the practice API key.

{% hint style="warning" %}
Outbound write-back is currently no-op (inbound-only). Full write-back support is pending licensing for Charm's proprietary write API.
{% endhint %}

</details>

<details>

<summary>v0.9.31 - Platform API: Self-Service SMART FHIR Provisioning (March 30, 2026)</summary>

#### Self-Service Secret Provisioning for SMART FHIR Data Sources

The `POST /data-sources` and `PUT /data-sources/{id}` endpoints now support inline secret provisioning for `smart_fhir` data sources. Pass `private_key_value` in `connection_config` and the API automatically provisions the key to secure storage and stores only an SSM path reference.

* **Inline key upload** - Include the PEM-encoded private key as `private_key_value` when creating or updating a data source. The API provisions it and replaces the field with `private_key_ssm_param_path`.
* **Response redaction** - API responses strip all inline secret fields (`*_value`, `*_pem`, `*_secret`, `*_password`) and mask SSM paths. A `private_key_ssm_param_path_configured: true` indicator confirms the key is provisioned.
* **Key rotation** - Send a new `private_key_value` on update to rotate the key. The old key is overwritten in secure storage.

This enables teams to connect new EHR systems entirely through the API or Developer Console without infrastructure involvement.

</details>

<details>

<summary>v0.9.28 - Platform API: Slot Search Time Preferences &#x26; User Actions Access (March 30, 2026)</summary>

#### Voice Agent: Time Preference Filtering

The `slot_search` tool now accepts an optional `time_preference` parameter (`morning`, `afternoon`, or `evening`) to filter appointment slots by time of day. When no slots match the preferred window exactly, the tool falls back to the nearest available time and indicates the fallback in the response.

Slot results are now cached per session, so `schedule_appointment` and `reschedule_appointment` can reference slots by index (`slot:0`, `slot:1`) without re-querying. The cache is isolated per voice session to prevent cross-session interference.

#### Classic API: User Actions Access

* New `enable_actions_access` boolean field on user records, returned in `GetUserInfo` responses. Controls whether a user can access actions features (tool repository browsing, action management). Defaults to `false`.

</details>

<details>

<summary>v0.9.25 - Outreach Optimization: Surface Insights, Fatigue Gating &#x26; Channel Optimization (March 29, 2026)</summary>

#### Voice Agent: `get_surface_insights` Tool

New context graph tool that queries a patient's surface analytics before creating new surfaces. Returns completion rate, preferred channel, pending surface count, and recent history. Enables agents to avoid surface fatigue: if a patient has multiple unfinished surfaces or low completion, the agent can collect data verbally instead.

#### Gap Scanner: Fatigue Gating

Three new gap scanner settings that prevent over-solicitation:

| Setting                | Default | Description                                                             |
| ---------------------- | ------- | ----------------------------------------------------------------------- |
| `max_pending_surfaces` | 3       | Skip entities with this many unfinished surfaces                        |
| `min_completion_rate`  | 0.0     | Skip entities whose completion rate is below this threshold             |
| `channel_optimization` | false   | Use each entity's historically preferred channel instead of the default |

#### Closed-Loop Feedback

Surface analytics now feed back into both agent-side and automated surface creation. The voice agent queries insights before creating surfaces, and the gap scanner checks pending counts and completion rates before generating outreach, preventing the common failure mode of sending more messages to patients who do not respond.

</details>

<details>

<summary>v0.9.24 - Platform API: Surface Analytics (March 29, 2026)</summary>

#### Surface Analytics (4 Endpoints)

Closed-loop intelligence for data collection surfaces under `GET /v1/{workspace_id}/analytics/surfaces/`:

| Endpoint                 | Description                                                                                                |
| ------------------------ | ---------------------------------------------------------------------------------------------------------- |
| `/completion-rates`      | Overall rate, time-bucketed trend, by-source breakdown (agent, gap scanner, manual). Filterable by entity. |
| `/channel-effectiveness` | Per-channel (SMS, email, WhatsApp, web, voice) completion rate and avg time-to-complete                    |
| `/field-abandonment`     | Per-field drop-off rate and save rate for abandoned surfaces                                               |
| `/entity/{entity_id}`    | Per-entity history: completion stats, preferred channel, recent surfaces                                   |

All support date range filtering (default 30 days, max 90) with `1h`/`1d`/`1w` intervals. Requires `viewer+` permissions.

Enables agents and gap scanners to optimize surface design. For example, switching to SMS after seeing low email completion rates, or removing a field that causes high abandonment.

</details>

<details>

<summary>v0.9.23 - Connector Runner: Automated Gap Scanner (March 29, 2026)</summary>

#### Gap Scanner Loop (New Background Loop)

Rule-based background loop on the connector runner that scans entities for missing data and creates surfaces automatically. This is the 8th background loop alongside poll, reconciliation, entity resolution, review, outbound subscriber, outbound dispatch, and config refresh.

**How it works:**

1. Scans workspaces with gap scanning enabled
2. Loads gap requirements from workspace settings (configurable rules)
3. Checks entity state against requirements using dot-notation path resolution
4. Creates surfaces for entities with missing data
5. Delivers via configured channel (SMS, email, etc.)
6. Sets a cooldown per entity to prevent notification fatigue (default 7 days)

#### Gap Scanner Settings API

| Endpoint                    | Description                                         |
| --------------------------- | --------------------------------------------------- |
| `GET /settings/gap-scanner` | Get gap scanner configuration (any role)            |
| `PUT /settings/gap-scanner` | Update configuration (admin/owner, partial updates) |

Settings include: `enabled` (default false), `scan_interval_seconds` (300), `appointment_lookahead_hours` (72), `cooldown_hours` (168), `max_surfaces_per_tick` (10), and `requirements` (list of gap detection rules).

Each requirement defines: entity type, trigger condition (`upcoming_appointment` or `recent_interaction`), required fields (dot-notation paths), delivery channel, and priority.

The scanner integrates with the connector runner's operational metrics and health status endpoint.

</details>

<details>

<summary>v0.9.22 - MFA, IP Allowlists &#x26; Mid-Call Surface Observation (March 29, 2026)</summary>

#### Platform API: Multi-Factor Authentication (MFA)

TOTP-based MFA with recovery codes. This provides an authentication control that can contribute evidence for HIPAA 164.312(d) and SOC 2 CC6.1/CC6.6; using the feature does not by itself establish compliance.

**User MFA endpoints:**

| Endpoint           | Description                                                                            |
| ------------------ | -------------------------------------------------------------------------------------- |
| `POST /mfa/enroll` | Generate TOTP secret + recovery codes. Returns `otpauth://` URI for authenticator app. |
| `POST /mfa/verify` | Confirm enrollment with a valid TOTP code                                              |

**Admin MFA endpoints** (requires `identity:admin`):

| Endpoint                            | Description                                    |
| ----------------------------------- | ---------------------------------------------- |
| `GET /admin/mfa/coverage`           | MFA enrollment statistics across the workspace |
| `POST /admin/mfa/reset/{entity_id}` | Reset MFA enrollment for a user                |

MFA can be enforced per SSO connection via `enforce_mfa`. Service accounts are exempt.

#### Platform API: IP Allowlists

Per-workspace CIDR-based IP restrictions on the token endpoint.

**Admin endpoints** (requires `identity:admin`):

| Endpoint                           | Description                              |
| ---------------------------------- | ---------------------------------------- |
| `POST /admin/ip-allowlists`        | Add a CIDR range                         |
| `GET /admin/ip-allowlists`         | List allowed ranges                      |
| `DELETE /admin/ip-allowlists/{id}` | Remove a range                           |
| `POST /admin/ip-allowlists/test`   | Test whether an IP matches the allowlist |

Cached for performance. Service accounts exempt. Fails open if cache unavailable.

#### Voice Agent: Mid-Call Surface Observation

The voice agent now passively observes surface submissions during active calls. When a patient submits a form the agent created, the agent receives a real-time notification and acknowledges it in the conversation (e.g., "I can see you just uploaded your insurance card, thank you").

Works through the workspace event stream: the agent subscribes during the call and filters for surface submissions matching surfaces it created.

</details>

<details>

<summary>v0.9.20 - Voice Agent: Mid-Call Surface Tools (March 29, 2026)</summary>

#### HSM Surface Tools (4 New)

Four context graph tools enabling voice agents to create and manage surfaces during live calls:

| Tool                   | Description                                                                             |
| ---------------------- | --------------------------------------------------------------------------------------- |
| `create_surface`       | Create a surface spec (entity, title, fields). Returns signed URL for patient delivery. |
| `deliver_surface`      | Mark surface as delivered to a channel address (phone/email). Records lifecycle event.  |
| `check_surface_status` | Poll current lifecycle status of a surface.                                             |
| `list_entity_surfaces` | List existing surfaces for an entity (filterable by status) to avoid duplicates.        |

All tools authenticate via the call's `agent_session` JWT for automatic workspace isolation. Errors are returned as structured messages rather than exceptions, so the agent can continue the call if a surface operation fails.

</details>

<details>

<summary>v0.9.19 - Platform API: Patient-Facing Surface Rendering (March 28, 2026)</summary>

#### Patient-Facing Endpoints

Token-authenticated patient-facing endpoints for surfaces. Patients access forms via HMAC-signed URL tokens, so no login is required.

| Endpoint                      | Description                                              |
| ----------------------------- | -------------------------------------------------------- |
| `GET /s/{token}`              | Render surface as mobile-first HTML (all 12 field types) |
| `POST /s/{token}/submit`      | Accept form submission (written at confidence 0.5)       |
| `PUT /s/{token}/fields/{key}` | Incremental auto-save for individual fields              |

* **Token-based access** - HMAC-SHA256 signed tokens with surface ID and expiration, no API key needed
* **Mobile-first rendering** - Server-side HTML generation, native device capabilities for photo/signature/file
* **Auto-save** - Fields save incrementally so patients don't lose progress
* **Rate limiting** - Per-IP: 30/min render, 10/min submit, 30/min auto-save
* **Atomic lifecycle** - Status transitions (opened, partial, completed) in single transactions to prevent race conditions
* **Field validation** - 10KB max per field value

Surface creation response now includes the signed `token` and full `url` when the token secret is configured.

</details>

<details>

<summary>v0.9.18 - Platform API: Surface Engine Foundations (March 28, 2026)</summary>

#### Surfaces (New Feature)

Agent-generated data collection interfaces delivered to patients through existing communication channels. Agents analyze entity state and data gaps, generate a `SurfaceSpec`, and the platform renders and delivers it.

**Models:**

| Model               | Description                                                                             |
| ------------------- | --------------------------------------------------------------------------------------- |
| `SurfaceSpec`       | What an agent generates: title, 1-100 fields, channel, expiration, entity association   |
| `SurfaceField`      | A data collection field with type, validation, conditional display, PHI flag            |
| `SurfaceSubmission` | What comes back: submitted field values, partial or complete status                     |
| `SurfaceStatus`     | Lifecycle: `created` -> `delivered` -> `opened` -> `partial` -> `completed` / `expired` |

**5 delivery channels:** SMS, WhatsApp, email, voice (IVR), web link.

**12 field types:** text, textarea, date, phone, email, number, select, multiselect, checkbox, photo, signature, file.

**Permissions:** `surfaces:read` (view specs and submissions) and `surfaces:write` (generate specs).

Submissions are written to the world model as events with source `surface` and flow through standard confidence gates, review queues, and entity resolution.

#### New Entity Type

`interaction` entity type added to the world model ontology for tracking surface lifecycle events as first-class entities.

</details>

<details>

<summary>v0.9.17 - Platform API: Audit Log Export (March 28, 2026)</summary>

#### Audit Log Export

Two new endpoints for exporting audit events as NDJSON files with time-limited download URLs:

| Endpoint             | Description                                                      |
| -------------------- | ---------------------------------------------------------------- |
| `POST /audit/export` | Create a new export for a date range. Returns export ID.         |
| `GET /audit/exports` | List all exports with status and download URLs (12-hour expiry). |

* NDJSON format, capped at 50,000 events per export
* Export action is itself audit-logged (with PHI flag if applicable)
* Returns `503` if export storage is not configured
* Requires `admin` or `owner` permissions

</details>

<details>

<summary>v0.9.16 - Platform API: Data Lineage, Retention Policies &#x26; Compliance Reporting (March 28, 2026)</summary>

#### Entity Data Lineage

`GET /world/entities/{entity_id}/lineage` - Full data lineage composing provenance (sources, confidence history, merge events) with outbound sync sinks (where data was sent, status) and review queue history (verdicts, reviewer actions).

#### Retention Policies

Per-workspace retention policies with a six-year default (2190 days) intended to support regulated retention programs:

| Endpoint                  | Description                                            |
| ------------------------- | ------------------------------------------------------ |
| `GET /settings/retention` | Get retention policy (any role)                        |
| `PUT /settings/retention` | Update retention policy (admin/owner, partial updates) |

Configurable per data type: call recordings, call transcripts, audit logs, world events, PHI data. Legal hold overrides all retention. Advisory for now: policy is stored but no automated deletion is performed yet.

#### Compliance Reporting

| Endpoint                        | Description                                                                                              |
| ------------------------------- | -------------------------------------------------------------------------------------------------------- |
| `GET /compliance/hipaa`         | HIPAA evidence report: audit stats, retention, encryption, API keys for configurable period (1-365 days) |
| `GET /compliance/access-review` | SOC 2 access review: all credentials with role, status, activity dates for attestation                   |

Both require `admin` or `owner` permissions.

</details>

<details>

<summary>v0.9.15 - Platform API: Unified Audit Trail &#x26; PHI Access Logging (March 28, 2026)</summary>

#### Unified Audit Trail

Enterprise audit APIs record covered actions with available actor identity, credential, IP address, resource context, and PHI classification. Coverage is route- and producer-specific, and audit writes are best-effort rather than a transactional record of every action across all services.

Audit writes are queued through an asynchronous buffered writer so requests do not wait for audit persistence. The append can fail independently, so a successful API response is not an audit receipt.

#### PHI Access Logging

The audit layer recognizes 12 PHI-sensitive route patterns, including entity reads, FHIR patient data, CRM contacts, call recordings, call intelligence, and audit reports themselves, and attempts to append access records for covered requests.

#### Audit Query API (4 Endpoints)

| Endpoint                                   | Description                                                                                                                                                        |
| ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `GET /audit`                               | List audit events with filters: service, action, actor, resource type, resource ID, PHI-only, date range                                                           |
| `GET /audit/phi-access`                    | PHI access report: covered records of who accessed patient data, when, and from where; useful as partial evidence for investigations and HIPAA 164.312(b) controls |
| `GET /audit/entity/{entity_id}/access-log` | All audit events for a specific resource                                                                                                                           |
| `GET /audit/summary`                       | Summary statistics: total events, PHI access events, unique actors, services with activity                                                                         |

All endpoints require `admin` or `owner` permissions and are workspace-scoped.

</details>

<details>

<summary>v0.9.14 - Platform API: Session Enforcement (March 28, 2026)</summary>

#### Idle Timeout & Concurrent Session Limits

Session enforcement controls with background cleanup, including a stricter default for user sessions:

| Session Type                      | Idle Timeout | Concurrent Limit        | Notes                                                  |
| --------------------------------- | ------------ | ----------------------- | ------------------------------------------------------ |
| User sessions (developer console) | 15 minutes   | 5 per entity/workspace  | Production-oriented default for regulated environments |
| Agent sessions (voice calls)      | 1 hour       | 50 per entity/workspace | Matches agent session TTL                              |

* Background process periodically revokes idle and expired sessions
* Concurrent limit enforced at session creation; oldest session evicted when limit reached
* Idle timeout configurable per-session (5 minutes to 24 hours)
* Sessions now track IP address and user agent for audit visibility

#### Session Management Endpoints

**User endpoints** (any authenticated user):

| Endpoint                        | Description                                 |
| ------------------------------- | ------------------------------------------- |
| `GET /sessions`                 | List active sessions for the current entity |
| `DELETE /sessions`              | Revoke all sessions (logout everywhere)     |
| `DELETE /sessions/{session_id}` | Revoke a specific session                   |

**Admin endpoints** (requires `identity:admin` scope):

| Endpoint                             | Description                                                        |
| ------------------------------------ | ------------------------------------------------------------------ |
| `GET /sessions/admin`                | List all active sessions with entity/workspace filters, pagination |
| `DELETE /sessions/admin/{entity_id}` | Revoke all sessions for a specific entity                          |

All revocation actions are audit-logged.

</details>

<details>

<summary>v0.9.13 - Account Lockout, Tool Repositories &#x26; Prompt Caching (March 28, 2026)</summary>

#### Platform API: Account Lockout & Brute Force Protection

Progressive account lockout on failed authentication attempts:

| Failures | Lock Duration                     |
| -------- | --------------------------------- |
| 5+       | 5 minutes                         |
| 10+      | 30 minutes                        |
| 20+      | Permanent (requires admin unlock) |

* **Per-IP rate limiting** on the token endpoint (60 requests/minute) for unauthenticated grant types (`api_key`, `client_credentials`, `google_oauth`)
* **Authenticated grants exempt** - `agent_session` and `refresh_token` grants bypass IP rate limiting since they already require valid credentials
* **Lockout checks** integrated into all grant types with entity-level and IP-level tracking
* **Successful auth clears counters** - lockout resets on valid authentication
* **Fail-open design** - if the cache is unavailable, auth proceeds normally

**Admin lockout endpoints** (requires `identity:admin` scope):

| Endpoint                                  | Description                            |
| ----------------------------------------- | -------------------------------------- |
| `POST /admin/lockout/unlock/{identifier}` | Unlock a locked account                |
| `GET /admin/lockout/locked-accounts`      | List all currently locked accounts     |
| `GET /admin/lockout/status/{identifier}`  | Check lockout status for an identifier |

Locked responses include `Retry-After` header for timed lockouts.

#### Classic API: Tool Repository Management

New endpoints for managing tool (action) source code repositories:

* **Repository access management** - Grant and revoke per-user access to tool repositories
* **Branch and commit history** - Browse branches and commits for tool repositories
* **File access** - Read files from tool repositories for code review and debugging
* **Access flag** - `enable_actions_access` field on user info for repository access gating

#### Classic API: Prompt Caching

LLM prompt caching for reduced latency and cost. The system separates conversation prompts into immutable history (cacheable across turns) and dynamic suffix (changes each turn), enabling cache hits on the static portion.

</details>

<details>

<summary>v0.9.12 - Analytics Engine: Command Center, Percentiles, Entity Intelligence, SSE (March 28, 2026)</summary>

#### Command Center

`GET /v1/{workspace_id}/command-center` - Single-pane workspace health dashboard.

Aggregates voice, pipeline, data quality, and identity metrics in a single call. Each section fails independently with `degraded_sections` reporting. Cached with 15s TTL. Alert derivation with 7 threshold checks.

| Section        | Key Metrics                                                                         |
| -------------- | ----------------------------------------------------------------------------------- |
| `voice`        | Active calls, escalated, calls today, avg quality score, escalation rate            |
| `pipeline`     | Source counts (healthy/degraded/failing), events last hour, outbound pending/failed |
| `data_quality` | Pending reviews, approval rate (7d), avg confidence, total entities, merges (7d)    |
| `identity`     | Active API keys, sessions, failed auths, locked accounts, MFA coverage              |
| `alerts`       | Level (warning/critical), code, message, section                                    |

#### Percentile Analytics

`GET /analytics/calls/advanced` - p50/p95/p99 for duration and quality, time series trends with p95 latency, breakdowns by service and call direction (inbound/outbound).

`GET /analytics/calls/comparison` - Period-over-period comparison. Takes two explicit date ranges and returns current metrics, previous metrics, and delta (absolute + percentage change).

#### Entity Intelligence (4 Endpoints)

| Endpoint                              | Description                                                       |
| ------------------------------------- | ----------------------------------------------------------------- |
| `GET /world/entities/{id}/graph`      | One-level relationship graph with neighbor metadata               |
| `GET /world/entities/{id}/provenance` | Data lineage, confidence history, merge events                    |
| `GET /world/entities/duplicates`      | Same\_as edges by ascending confidence, filterable by entity type |
| `GET /world/search`                   | ILIKE entity search with type, source, confidence filters         |

#### Real-Time SSE

`GET /v1/{workspace_id}/events/stream` - Server-Sent Events for real-time workspace updates.

Event types: `call.started`, `call.ended`, `call.escalated`, `pipeline.sync_completed`, `pipeline.error`, `review.submitted`, `alert`.

* 30s heartbeat keep-alive
* `Last-Event-ID` reconnection with replay from a circular buffer
* Backpressure handling: oldest events dropped on buffer overflow
* Falls back gracefully if the event system is unavailable

</details>

<details>

<summary>v0.9.11 - Call Intelligence Analytics Aggregation (March 27, 2026)</summary>

#### Analytics Endpoints (6 New)

Six analytics endpoints under `GET /v1/{workspace_id}/analytics/` that aggregate call intelligence data for dashboard visualizations:

| Endpoint                          | Description                                                                                   |
| --------------------------------- | --------------------------------------------------------------------------------------------- |
| `/analytics/call-quality`         | Quality score trends (avg/p50/p95), distribution (excellent/good/fair/poor), escalation rate  |
| `/analytics/emotion-trends`       | Dominant emotion distribution, valence/arousal trends over time                               |
| `/analytics/safety-trends`        | Escalation frequency, risk level distribution (low/medium/high/critical), safety match counts |
| `/analytics/latency`              | p50/p95/p99 by component (engine, TTFB, navigation, render), trends over time                 |
| `/analytics/tool-performance`     | Per-tool success/failure rates, failure trends, invocation counts                             |
| `/analytics/operator-performance` | Escalation rate trends, quality comparison (escalated vs non-escalated), connect time         |

**Common parameters** (all endpoints):

| Parameter               | Type               | Default | Description                                    |
| ----------------------- | ------------------ | ------- | ---------------------------------------------- |
| `days`                  | integer (1-90)     | 30      | Lookback window (overridden by explicit dates) |
| `date_from` / `date_to` | date               | none    | Explicit date range                            |
| `interval`              | `1h` / `1d` / `1w` | `1d`    | Time bucket for trend data                     |
| `service_id`            | string             | none    | Filter to a specific service                   |

All endpoints require `viewer+` permissions and are workspace-scoped.

</details>

<details>

<summary>v0.9.10 - Call Intelligence Endpoints (March 27, 2026)</summary>

#### Completed Call Intelligence

`GET /calls/{call_id}/intelligence` - Full intelligence profile for a completed call.

Joins persisted call intelligence summaries with per-turn data reconstructed from conversation history:

| Field                  | Description                                                                   |
| ---------------------- | ----------------------------------------------------------------------------- |
| `quality_score`        | Composite 0-100 penalty-based score                                           |
| `emotion_trajectory`   | Per-turn emotion, valence, and timestamps                                     |
| `risk_timeline`        | Per-turn risk score and conversation state                                    |
| `latency_profile`      | Per-turn latency waterfall (engine/nav/render/audio TTFB ms) + summary stats  |
| `tool_performance`     | Per-tool invocations, success/fail counts, avg duration                       |
| `conversation_quality` | Loop events and barge-in events with turn numbers                             |
| `*_summary`            | Full summaries (emotion, risk, latency, conversation, tool, safety, operator) |

Returns 404 if the call or intelligence data is not found.

#### Active Call Intelligence

`GET /calls/active/intelligence` - Active calls enriched with live intelligence overlay.

Reads call metadata and live intelligence snapshots (written after each caller speech turn):

| Field                | Description                           |
| -------------------- | ------------------------------------- |
| `current_emotion`    | Current detected emotion              |
| `current_valence`    | Current emotional valence             |
| `current_risk_score` | Current composite risk score          |
| `risk_trend`         | `rising`, `stable`, or `falling`      |
| `turn_count`         | Turns completed so far                |
| `escalation_active`  | Whether operator escalation is active |
| `current_state`      | Current context graph state           |

Supports `workspace_id` query parameter for filtering. Live intelligence data expires automatically when a call ends or the session is lost.

</details>

<details>

<summary>v0.9.9 - Call Intelligence Persistence (March 27, 2026)</summary>

#### Call Intelligence Summaries

The voice agent now computes and persists structured intelligence summaries at call end. Per-call operational telemetry is computed from in-memory session state and stored for analytics and dashboard use.

**Summaries persisted:**

| Summary                | Contents                                                                                 |
| ---------------------- | ---------------------------------------------------------------------------------------- |
| `emotion_summary`      | Dominant emotion, valence/arousal averages, peak negative, emotional shifts, final trend |
| `risk_summary`         | Composite risk score, level, contributing signals with weights                           |
| `latency_summary`      | Engine response time (avg/p50/p95), audio TTFB (avg/p50/p95), silence ratio              |
| `conversation_summary` | Turn count, states visited, loop count, barge-in count, completion reason                |
| `tool_summary`         | Total calls, success/failure counts, failure rate, per-tool breakdown                    |
| `safety_summary`       | Safety rule match count during the call                                                  |
| `operator_summary`     | Escalation status, operator timing, resolution                                           |

#### Composite Quality Score

Rule-based quality score (0-100) computed from intelligence summaries. Starts at 100 and applies penalties:

| Signal              | Threshold               | Penalty    |
| ------------------- | ----------------------- | ---------- |
| High latency        | p95 audio TTFB > 1000ms | -5 to -15  |
| Excessive silence   | Silence ratio > 0.2     | -10 to -20 |
| Caller barge-ins    | > 2 interruptions       | -5 to -15  |
| Agent loops         | Revisited states        | -10 to -20 |
| Operator escalation | Any                     | -10        |
| Tool failures       | Failure rate > 5%       | -5 to -15  |

Designed for dashboard filtering and trend analysis. The computation is pure (no I/O) - all data comes from in-memory session state. Write failures are logged but do not affect the caller or post-call processing.

#### Safety Match Tracking

The escalation handler now tracks safety rule matches during calls. The count is stored as `match_count` in `safety_summary` (with associated `actions`), and escalation status is tracked separately as `escalated` in `operator_summary`.

</details>

<details>

<summary>v0.9.8 - Pipeline Observability Dashboard (March 27, 2026)</summary>

#### Pipeline Dashboard API (9 Endpoints)

New read-only pipeline observability endpoints under `GET /v1/{workspace_id}/pipeline/` that power the pipeline dashboard. These combine live connector-runner operational state, cached source health data, and database aggregation queries.

| Endpoint                                  | Description                                                                                                        |
| ----------------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
| `/pipeline/status`                        | Composite pipeline status: overall health, active polls, total events/entities, per-source status, all loop states |
| `/pipeline/sources`                       | Data sources with live health from cached poll results                                                             |
| `/pipeline/sources/{source_id}/history`   | Sync history bucketed by time window (`1h` or `1d`)                                                                |
| `/pipeline/sources/{source_id}/events`    | Paginated events for a specific source                                                                             |
| `/pipeline/outbound`                      | Per-sink outbound sync summary (synced/failed/pending counts)                                                      |
| `/pipeline/outbound/{data_source_id}/log` | Paginated outbound sync log for a specific sink                                                                    |
| `/pipeline/entity-resolution`             | Entity resolution metrics: merge counts + loop status                                                              |
| `/pipeline/review`                        | Review pipeline metrics: queue depth, approval rate, avg review time                                               |
| `/pipeline/throughput`                    | Event throughput time series across all sources                                                                    |

All endpoints require `viewer+` permissions and are workspace-scoped.

**Graceful degradation** - If the connector runner is temporarily unavailable, the dashboard still returns database-backed metrics (event counts, sync history, review stats). Only live loop states and active poll counts are omitted.

#### Connector Runner Health Monitoring

The connector runner now exposes an operational health snapshot covering all background loops and per-source connection status:

* **Overall status** - `healthy`, `degraded`, or `starting` based on aggregate loop health
* **Per-source poll metrics** - Last poll time, duration (ms), event count, error, connection health
* **Loop states** - Entity resolution, review, outbound dispatch, subscriber, reconciliation
* **Connection health tracking** - Consecutive poll errors tracked per source. Unhealthy after 3+ failures, auto-recovers on success
* **Real-time source health** - Cached poll results with 1-hour TTL, available through the pipeline dashboard endpoints

</details>

<details>

<summary>v0.9.7 - athenahealth EHR, SSO Login &#x26; Safety Filters (March 26, 2026)</summary>

#### athenahealth EHR Integration

New dedicated EHR connector type for athenahealth with bidirectional sync:

**Inbound** - Real-time data ingestion via FHIR Subscription webhooks. The connector runner receives event notifications from athenahealth, fetches the full resource, maps it to FHIR R4, and writes to the world model. Supported resource types: Patient, Appointment, Department, Provider, Medication, Allergy, Insurance.

**Outbound** - Write-back through the handler registry. Supported operations:

| Operation          | What It Does                                                 |
| ------------------ | ------------------------------------------------------------ |
| Patient create     | Create new patient record in athenahealth                    |
| Patient update     | Merge demographics with existing record                      |
| Appointment book   | Book appointment (patient resolved from entity external IDs) |
| Appointment cancel | Cancel existing appointment                                  |

The `athenahealth` connector type is now available in workspace configuration alongside `fhir_store`, `revolution`, and `hubspot`.

#### SSO Login via Identity Federation

The Platform API now supports single sign-on (SSO) via identity federation. Users authenticate with their organization's identity provider, and the platform issues a JWT in the same token format as API key authentication.

* **`google_oauth` grant type** on `POST /token` - Exchange an identity provider authorization code for an Amigo JWT
* **Multi-workspace selection** - Users with credentials on multiple workspaces receive a workspace list; re-call with `workspace_id` to complete authentication
* **Auto-provisioning** - Domain-based provision policies automatically create credentials for new users on first SSO login. Global policies expand to all workspaces
* **Refresh tokens** - Rotated on use with configurable idle timeout for compliance

#### Identity Admin API

New admin endpoints for identity management (requires `identity:admin` scope):

| Endpoint              | What It Does                                  |
| --------------------- | --------------------------------------------- |
| Credential CRUD       | Create, list, update, delete API credentials  |
| Credential rotation   | `POST /admin/credentials/{id}/rotate-secret`  |
| Provision policies    | CRUD for domain-based auto-provisioning rules |
| Federation identities | CRUD for SSO identity mappings                |
| User listing          | List users across workspaces                  |
| Audit log             | Query authentication and admin action history |

All list endpoints support pagination (`limit` + `has_more` + `continuation_token`), case-insensitive search, and sort (`+field`/`-field` syntax).

#### Per-Service Safety Filter Toggle

New `safety_filters_enabled` field on service configuration (defaults to `true`). When set to `false`, conversation monitoring (monitor concepts, triage, accumulation) is bypassed for that service while independent risk scoring remains active. Useful for non-clinical services or internal testing environments.

New accumulation tuning fields on safety configuration: `accumulation_mild_threshold` (minimum concern level counted toward accumulation, default 1) and `accumulation_fast_track_level` (concern level that bypasses accumulation and triggers immediate action, default 3).

</details>

<details>

<summary>v0.9.6 - Ontology Migration, World Tools &#x26; Write Safety (March 24, 2026)</summary>

#### Entity Type Ontology Migration (Breaking)

{% hint style="danger" %}
**Breaking change**: Entity types in the world model have migrated from domain-role names to ontological categories. The `entity_type` field on entities and in API responses has changed:

* `patient`, `practitioner`, `operator` → `person`
* `location` → `place`

Event-level FHIR resource types (`fhir_resource_type`) are **unchanged** - events still carry `Patient`, `Practitioner`, `Location`, etc. The `outbound_entity_types` field in data source configuration also remains as FHIR resource type names.
{% endhint %}

The world model now uses ontological entity types instead of domain-specific roles. A single `person` entity can represent a patient, practitioner, or both. The projection function detects roles from the underlying event data and produces role-aware output with the relevant sections for each role.

**Migration**: A SQL migration converts existing entity\_type values in entities, events, and entity\_graph rows. If you filter or query by entity\_type in your code, update the values:

| Before         | After                      |
| -------------- | -------------------------- |
| `patient`      | `person`                   |
| `practitioner` | `person`                   |
| `operator`     | `person`                   |
| `location`     | `place`                    |
| `organization` | `organization` (unchanged) |
| `appointment`  | `appointment` (unchanged)  |
| `deal`         | `deal` (unchanged)         |

#### Organization and Deal Entity Types

Organization and Deal are now first-class entity types in the world model with dedicated projections:

* **Organization** - Aggregates company data (name, phone, domain, industry, address, employee count) from CRM and EHR sources. Fixes entity resolution for CRM company records that were previously orphaned.
* **Deal** - Stores deal/opportunity data (name, amount, stage, pipeline, close date) as native entities instead of encoding through FHIR Basic resources.

Both types are included in entity resolution, auto-enrichment, and CRM views.

#### New FHIR Views Endpoint

* `GET /v1/{ws}/fhir/views/organizations` - FHIR Organization resources by data source

#### New Voice Agent Tools

Three new built-in tools for clinical data during live calls:

| Tool                    | Type  | What It Does                                                                    |
| ----------------------- | ----- | ------------------------------------------------------------------------------- |
| **Medication lookup**   | Read  | Retrieves a patient's active medications with dosage, frequency, and prescriber |
| **Prescription refill** | Write | Creates a refill request at voice confidence for review before EHR sync         |
| **Encounter lookup**    | Read  | Retrieves encounter history (visits, diagnoses, participating practitioners)    |

#### Duplicate Write-Tool Prevention

The voice agent now prevents duplicate write-tool invocations during async execution. When the agent re-invokes the same write tool with identical parameters while the first call is still in-flight (e.g., during barge-in recovery), the duplicate call is blocked and returns immediately. This prevents double-booking appointments, duplicate insurance records, and other data integrity issues from concurrent tool calls.

#### Session Event Injection Idempotency

The session event injection endpoint now deduplicates identical events within a 30-second window. When the platform API retries an injection due to a network timeout, the duplicate is detected and returns a `deduplicated` status instead of triggering a second agent response. This prevents the agent from responding to the same event twice.

#### Ontology Foundation

{% hint style="info" %}
This is a foundational change that does not affect current API contracts. Entity types and projections continue to work as before.
{% endhint %}

The world model now categorizes entity types into ontological categories (person, organization, place, event, transaction). This enables role-aware projections where merged entities (e.g., a patient who is also a CRM contact) produce output that includes all relevant role-specific sections. The projection registry dispatches to the correct projection based on entity type, making the system extensible without modifying core logic.

</details>

<details>

<summary>v0.9.5 - Developer Portal API Improvements (March 24, 2026)</summary>

#### Search on All List Endpoints

All Platform API list endpoints now support a `search` query parameter for case-insensitive filtering:

| Endpoint                    | Fields Searched         |
| --------------------------- | ----------------------- |
| `GET /v1/{ws}/skills`       | name, description, slug |
| `GET /v1/{ws}/integrations` | name, display\_name     |
| `GET /v1/{ws}/agents`       | name, description       |
| `GET /v1/{ws}/hsms`         | name                    |
| `GET /v1/{ws}/services`     | name, description       |

#### Delete Dependency Safety

Delete operations now check for downstream dependencies before proceeding. If a resource is referenced by another entity, the API returns `409 Conflict` with a list of referencing entity names.

| Resource      | Checks For         |
| ------------- | ------------------ |
| Skills        | HSM references     |
| Integrations  | Skill references   |
| HSMs / Agents | Service references |

#### Rate Limit Headers

All rate-limited endpoints now include response headers on every request (not just on 429 responses):

* `X-RateLimit-Limit` - Maximum requests per window
* `X-RateLimit-Remaining` - Requests remaining in current window
* `X-RateLimit-Reset` - Seconds until window resets

#### Standardized Error Codes

All error responses now include a machine-readable `error_code` field:

```json
{
  "error_code": "RESOURCE_NOT_FOUND",
  "message": "Skill not found",
  "details": {},
  "request_id": "req_abc123"
}
```

This applies to all domain exceptions and global error handlers.

#### Connector Entity Views

New endpoints for browsing connected data sources and their entities:

* `GET /v1/{ws}/world/connectors` - Overview of all connected data sources with entity counts, sync status, and health
* `GET /v1/{ws}/world/connectors/{data_source_id}/entities` - Paginated entity list per data source with type and name filtering
* `GET /v1/{ws}/world/connectors/{data_source_id}/resources` - FHIR resources by data source with resource type filtering

Entity list endpoints support `source` and `source_system` filters for scoping by data origin.

#### CRM Routes

New CRM-specific endpoints for workspaces with CRM integrations:

* `GET /v1/{ws}/crm/status` - Contact/company/deal counts, sync health, connector info
* `GET /v1/{ws}/crm/contacts` - Search contacts by name, email, or phone
* `GET /v1/{ws}/crm/contacts/{id}` - Full contact state with timeline
* `GET /v1/{ws}/crm/contacts/{id}/timeline` - Activity feed (calls, meetings, notes, syncs)
* `GET /v1/{ws}/crm/companies` - Search companies by name
* `GET /v1/{ws}/crm/companies/{id}` - Company detail
* `GET /v1/{ws}/crm/deals` - List deals with stage, amount, pipeline
* `GET /v1/{ws}/crm/deals/{id}` - Deal detail

#### Request Validation Hardening

{% hint style="warning" %}
**Potentially breaking**: Request fields that previously accepted arbitrary strings now enforce length bounds and format constraints. Requests with oversized or malformed fields will receive `422 Unprocessable Entity` responses.
{% endhint %}

All Platform API request models now enforce bounded string types and Literal enums:

| Constraint          | Applies To                                                                                    | Limit                      |
| ------------------- | --------------------------------------------------------------------------------------------- | -------------------------- |
| `NameString`        | Resource names (agents, skills, services, HSMs, integrations, data sources, monitor concepts) | 1-256 characters           |
| `DescriptionString` | Resource descriptions                                                                         | 0-2,000 characters         |
| `SearchString`      | All `search` query parameters                                                                 | 1-200 characters           |
| Literal enums       | Operator type, connection method, role, status, call mode, region, rule type                  | Restricted to valid values |
| E.164 validation    | Phone numbers in workspace test callers and purchase requests                                 | Standard E.164 format      |
| `max_length`        | Integration URLs, phone number notes, review queue reasons, batch IDs                         | Per-field limits           |

Search parameters are sanitized to prevent wildcard injection in queries.

#### Sort Parameter Support

All list endpoints now support a `sort_by` query parameter for controlling result ordering. Each resource type defines its own set of sortable fields. Format: `field_name` (ascending) or `-field_name` (descending).

</details>

<details>

<summary>v0.9.4 - Unified Connector Design (March 23, 2026)</summary>

#### Connector Type Vocabulary

The connector framework now uses formal types for data source and workspace configuration:

| Type             | Values                                                         | Purpose                                                         |
| ---------------- | -------------------------------------------------------------- | --------------------------------------------------------------- |
| `source_type`    | `ehr`, `fhir_store`, `crm`, `rest_api`, `webhook`, `file_drop` | Data source category; determines which adapter handles polling  |
| `connector_type` | EHR vendor types, `fhir_store`, `hubspot`, `salesforce`        | Workspace-level setting; determines outbound write-back routing |

#### Workspace `connector_type` (Breaking)

{% hint style="danger" %}
**Breaking change**: The workspace `ehr_type` field has been renamed to `connector_type`. The value `google_fhir` is now `fhir_store`. The `default_fhir_store_url` field has been removed from the Workspace model; FHIR store URLs are now configured in the data source's `connection_config`.
{% endhint %}

**Migration**: The rename is handled automatically on our end. Update any code that references `ehr_type` or `default_fhir_store_url` on workspace objects.

#### FHIR Store Promoted to Source Type

FHIR stores are now a first-class source type (`fhir_store`) instead of being treated as a special case of `ehr`. Data source configuration for FHIR stores uses typed fields:

* `fhir_store_url` - FHIR store endpoint URL
* `resource_types` - FHIR resource types to poll (defaults: Patient, Practitioner, Location, Appointment, Coverage, Encounter, Condition, AllergyIntolerance, MedicationRequest, Schedule)
* `poll_cadences` - Per-resource poll intervals in seconds
* `outbound_entity_types` - Entity types to write back

#### Multi-Sink Outbound

Workspaces can now write back to multiple external systems simultaneously. For example, a workspace can sync patient and appointment data to the EHR while syncing patient and contact data to the CRM. Each outbound sink is configured independently with its own entity types, and sync progress is tracked per-sink. A failure writing to one system does not block writes to others.

#### Cross-Source Entity Merge

When a workspace has multiple data sources, entity resolution now automatically detects and merges entities that represent the same real-world thing across sources. Patients are matched by phone number, email, or name + date of birth. Practitioners are matched by NPI or name + specialty. Merged entities produce a unified projection reflecting data from all connected systems.

#### Outbound Handler Registry

Outbound write-back routes through a handler registry that maps each sink's `connector_type` to the correct write-back handler, used by both the real-time sync path and the reconciliation safety net.

#### Configurable Poll Cadences

EHR and CRM data source configs now support a `poll_cadences` field: a dictionary mapping resource or object names to poll intervals in seconds. When omitted, adapters use their built-in defaults.

#### Removed

* `google_fhir` as a `connector_type` value (replaced by `fhir_store`)
* `ehr_type` field on Workspace (use `connector_type` instead)
* `default_fhir_store_url` field on Workspace (configure in data source `connection_config` instead)

</details>

<details>

<summary>v0.9.2 - Session Event Injection &#x26; Operator Guidance (March 23, 2026)</summary>

#### Session Event Injection

External systems can now inject events into active voice sessions in real time. The agent processes injected events and speaks a natural response without navigating the context graph state machine.

**New Endpoints:**

* `POST /voice-agent/sessions/{call_sid}/event` - Inject external event or guidance into active session (voice agent)
* `GET /v1/{workspace_id}/sessions/active` - List active voice sessions (platform API)
* `POST /v1/{workspace_id}/sessions/{call_sid}/inject` - Inject event into active session (platform API)

**Two event types:**

* `external_event` - Factual information (queues behind current speech)
* `guidance` - Instructions to the agent (interrupts current speech)

Cross-instance delivery ensures injection works regardless of which server instance handles the call. The connection reconnects automatically on transient infrastructure interruptions.

#### Operator Guidance

Operators can now send text guidance to the agent during live calls without taking over:

* `POST /v1/{workspace_id}/operators/{id}/send-guidance` - Send guidance scoped to operator identity (`Operator:Update` permission)

The agent receives the guidance as an injection event, interrupts its current speech, and acts on the instruction immediately. The caller does not know a human intervened.

#### Test-Call Scenarios

The test-call WebSocket endpoint now supports configurable scenarios for developer testing:

* `scenario` parameter: `inbound` (default), `outbound` (task context), `silent` (no greeting)
* `system_prompt` parameter: freeform prompt override for custom scenario testing
* `caller_id` and `outbound_task_entity_id` parameters for outbound scenario context

</details>

<details>

<summary>v0.9.0 - Voice Control Plane &#x26; Acoustic Intelligence (March 21, 2026)</summary>

#### Voice Control Plane

New workspace-level voice settings API for configuring the entire voice pipeline from a single endpoint.

**New Endpoints:**

* `GET /v1/workspaces/{workspace_id}/voice-settings`
* `PUT /v1/workspaces/{workspace_id}/voice-settings`

**Configurable Fields:** `voice_id`, `tone` (8 emotions), `speed`, `volume`, `language`, `keyterms` (speech recognition boost, max 200), `correction_categories` (domain hints for AI audio correction), `pronunciation_dict_id`, `sensitive_topics` (preemptive tone softening), `post_call_analysis_enabled`, `transcript_correction_enabled`.

#### Structured Action Model

Context Graph action states now use structured objects instead of plain strings.

**What Changed:**

* `actions` field: `list[string]` → `list[Action]` where `Action = { description: string, filler_hint: string | null }`
* `exit_conditions` filler field: `filler_hints: list[string]` → `filler_hint: string | null`
* Existing data is migrated automatically

**Filler hints** are semantic directions that guide filler generation alongside emotional context and latency state. They are not literal audio filler text.

#### Version Set Management (Platform API)

New endpoint for upserting version sets on workspace-scoped services:

* `PUT /v1/{workspace_id}/services/{service_id}/version-sets/{name}`

Includes server-side validation that pinned agent and context graph versions exist. The `edge` version set remains immutable (always latest).

#### Acoustic Intelligence Enhancements

* **Proactive emotional intelligence**: Detects sensitive topics from context graph actions and preemptively shifts to sympathetic tone before the caller shows distress
* **Tone momentum**: Maintains voice emotion continuity when real-time signals are weak, preventing jarring tone shifts
* **Enriched audio correction**: Speech comparison with confidence-gated spelling for improved transcript accuracy

#### Instant Greeting

Voice calls now begin generating the agent greeting during ring time, reducing perceived time-to-first-word to near-zero when the caller picks up.

#### Data Access (MCP)

New Model Context Protocol server for workspace data access. Compatible with any MCP client.

**Endpoint:** `POST /v1/mcp` (MCP Streamable HTTP transport)

**Available Tools:**

* `sql_query` - Execute read-only SELECT queries (1,000 row limit, 30s timeout)
* `describe_query` - Return query schema without execution
* `tables` - List available workspace tables
* `table_schema` - Column names and types for a table
* `sample_data` - Preview rows from a table
* `table_detail` - Extended table metadata and statistics
* `profile_column` - Statistical column profile (min, max, nulls, distinct, distribution)

Authentication: Bearer token plus `X-Workspace-Id` header. Stateless transport, so no session affinity is required.

{% hint style="info" %}
**New feature**: Structured Action model replaces plain string actions in Context Graphs. `actions` field changed from `list[string]` to `list[Action]`. Existing data is migrated automatically.
{% endhint %}

</details>

<details>

<summary>v0.8.4 - Data Pipeline &#x26; World Model (March 14, 2026)</summary>

#### Connector Runner

New data ingestion and sync engine providing a bidirectional pipeline between external systems (EHR platforms, REST APIs, FHIR stores) and the workspace world model.

**Capabilities:**

* Continuous, scheduled, manual, and webhook-triggered polling
* Deterministic entity resolution from FHIR references
* Confidence-gated EHR write-back (0.3 raw → 0.7 verified → 1.0 authoritative)
* Automated review loop for voice agent data quality
* Outbound call dispatch with business-hours gating

#### Data Sources & Unification Rules

New CRUD endpoints for managing external data feeds and field mapping rules:

* `POST/GET/PATCH/DELETE /v1/{workspace_id}/data-sources`
* Data source status and sync history endpoints
* `POST/GET/PATCH/DELETE /v1/{workspace_id}/unification-rules`

#### World Model

Unified entity graph aggregating data from all connected sources:

* Entity and event type registries with counts
* Entity query, detail, timeline, and relationship endpoints
* Sync queue management with retry capabilities
* Generic data query proxy with structured filtering

#### Safety & Monitor Concepts

New semantic monitoring system for conversation safety:

* `POST/GET/PATCH/DELETE /v1/{workspace_id}/monitor-concepts` - embedding-based concept detection
* Regulation templates with one-click apply
* Workspace safety configuration (triage, thresholds, accumulation windows)

#### Analytics & Review Queue

* Usage summary, call statistics, event breakdown, data quality endpoints
* Call listing with phone volume analytics
* Recording access with signed URLs
* QA review queue with approve/correct/reject workflow

</details>

<details>

<summary>v0.8.3 - Platform API &#x26; Operator System (March 10, 2026)</summary>

#### Platform API (New API Surface)

The **Platform API** at `api.platform.amigo.ai` is now available for workspace-scoped configuration and operations. This is a **separate API surface** from the Classic API, built for enterprise voice and traditional healthcare deployments.

**Key differences from Classic API:**

* **Workspace-scoped** (not organization-scoped)
* **API key authentication** (not per-user JWT)
* **Base URL:** `api.platform.amigo.ai/v1`

**Core resource endpoints:**

* Workspaces: tenant management and provisioning
* API Keys: workspace-scoped authentication with RBAC (owner, admin, member, viewer)
* Agents: persona definitions with immutable versioning
* Skills: LLM-backed companion agent capabilities with 4 execution tiers
* Services: agent plus context graph bindings with version sets
* Integrations: external API connections with health checks and endpoint testing
* Phone Numbers: voice line management, purchasing, and call forwarding

#### Operator System

Human-in-the-loop escalation management for live voice calls:

* Operator CRUD with availability tracking
* Call join (listen mode and takeover mode)
* Real-time mode switching: agent suspends during takeover, resumes on leave
* Escalation management (active, stats, lifecycle events)
* Operator dashboard and performance metrics
* Full audit log of all operator actions

#### Skill References

New endpoint to discover which context graphs and services depend on a skill:

* `GET /v1/{workspace_id}/skills/{skill_id}/references`

#### Call Forwarding

First-class call forwarding management on phone numbers:

* `PUT /v1/{workspace_id}/phone-numbers/{id}/forwarding`
* `DELETE /v1/{workspace_id}/phone-numbers/{id}/forwarding`

#### FHIR Clinical Data

FHIR endpoints for healthcare workspaces:

* Patient search, timeline, and clinical summary
* FHIR resource CRUD (search, get, create, update)
* Bundle import for bulk data loads
* Sync status and failure monitoring

</details>

<details>

<summary>v0.8.2 - SQL Validation Enhancement (February 18, 2026)</summary>

**SQL Validation Enhancement**

The `SubmitSQLQuery` endpoint now supports additional SQL syntax:

* `DESCRIBE TABLE EXTENDED <table> AS JSON`
* `DESCRIBE QUERY <select>`

These statements were previously rejected by the SQL validator.

</details>

<details>

<summary>v0.8.1 - ToolInvocation Inputs &#x26; API Key Webhook (February 11, 2026)</summary>

**ToolInvocation `inputs` Field**

Tool invocations now include the input parameters passed to the tool, for better debugging and auditing.

**What Changed**:

* New required field `inputs: dict[str, Any]` added to `ToolInvocation` model
* Exposed in `GetToolInvocations` and `SearchToolInvocations` response schemas
* Contains the full input parameters that were passed to the tool at invocation time

**API Key Expiration Webhook**

New webhook event type `api-key-expiration-soon` fires before API keys expire.

**Schema**: `APIKeyExpirationSoonWebhook` with fields: `type`, `org_id`, `api_key_id`, `expiration_time` (UTC datetime), `idempotent_key`

Subscribe via Settings → Webhooks and enable the 'API Key Expiration Soon' event type. Notifications fire at 14, 7, and 1 day before expiration.

{% hint style="warning" %}
**Deprecation**: The `ToolInvocation.logs` field is deprecated and will be removed from API responses in a future release.
{% endhint %}

**ToolInvocation `logs` Field Deprecated**

**Impact**: Low | **Action Required**: No immediate action

The `logs` field has been removed from the internal `ToolInvocation` model but is still returned in API responses defaulting to `[]`. This field will be removed from API responses in a future release.

</details>

<details>

<summary>v0.8.0 - GPT-5 Removal, Strict Output &#x26; Observability (February 4, 2026)</summary>

**HTTP Basic Authentication (Experimental)**

A new authentication method is available alongside the existing Bearer token flow.

**Format**: `Authorization: Basic base64({org_id}_{user_id}:{firebase_token})`

**Key Features**:

* Supports cross-organization authorization (user in org A authenticating against org B)
* Marked as experimental (subject to change)

**Prompt Log Tracings**

LLM prompt logs now include detailed tracing information for performance monitoring.

**New `TracingEvent` Fields**:

| Field                 | Type  | Description                      |
| --------------------- | ----- | -------------------------------- |
| `input_tokens`        | int   | Input token count                |
| `output_tokens`       | int   | Output token count               |
| `cached_tokens`       | int   | Cached token count               |
| `time_to_first_token` | float | Seconds to first token           |
| `total_duration`      | float | Total generation time in seconds |

Implemented across all LLM providers (OpenAI, Anthropic, AWS Bedrock, Google Gemini).

**OpenAI Strict Structured Output**

`strict: True` is now enabled on all OpenAI tool/function definitions, enforcing schema-compliant outputs. Internal schemas have been adjusted for compatibility.

**Arabic Accent Override Support**

Real-time voice conversations now support specifying Arabic accent variants via feature flags with improved language handling and error messages.

**Audio Keyterms in Voice Transcription**

The `keyterms` parameter is now passed to the transcription engine for English-language voice conversations, improving transcription accuracy for domain-specific terminology.

#### Breaking Changes

{% hint style="danger" %}
**Breaking change**: GPT-5 family models (`azure_gpt-5-2025-08-07`, `azure_gpt-5-mini-2025-08-07`, `azure_gpt-5-nano-2025-08-07`) have been removed. Migrate to `azure_gpt-5.1-2025-11-13` or OpenAI GPT-5.2.
{% endhint %}

**GPT-5 Family Models Removed**

**Impact**: High | **Action Required**: Yes, if using GPT-5 models

The following LLM types have been removed:

* `azure_gpt-5-2025-08-07`
* `azure_gpt-5-mini-2025-08-07`
* `azure_gpt-5-nano-2025-08-07`

**Migration**: Use `azure_gpt-5.1-2025-11-13` or OpenAI GPT-5.2 as replacements.

**`llm_provider_request_id` Renamed to Array**

**Impact**: Medium | **Action Required**: If parsing prompt log events

`FullResultAvailableEvent.llm_provider_request_id: str` changed to `llm_provider_request_ids: list[str]` - both the field name (singular → plural) and type (string → list of strings) have changed.

</details>

<details>

<summary>v0.7.0 - Permission System &#x26; Voice Configuration (January 30, 2026)</summary>

**Temporary Permission Grants**

Grant time-limited permissions to users without modifying their role. Temporary grants automatically expire, ideal for support escalations or temporary elevated privileges.

**New Endpoints**:

| Endpoint                                      | Method | Description                                 |
| --------------------------------------------- | ------ | ------------------------------------------- |
| `/v1/{org}/role/temporary_permission_grant/`  | POST   | Create a temporary permission grant         |
| `/v1/{org}/role/temporary_permission_grants/` | GET    | List and filter temporary permission grants |

**Key Features**:

* **Duration Control**: Grants last from 1 minute to 3 days (ISO8601 duration format)
* **Tags & Justification**: Attach metadata tags and require justification for audit trails
* **Filtering**: Query grants by user, permission, creator, expiration status, and tags
* **Permission Validation**: Creator must have greater privileges than the grant being issued

**Example Request** (Create Grant):

```json
POST /v1/{org}/role/temporary_permission_grant/
{
  "user_id": "support-agent-123",
  "duration": "PT2H",
  "permission_grant": {
    "permission_name": "Conversation:GetConversation",
    "conditions": {}
  },
  "tags": {"reason": "support_ticket", "ticket_id": "TICKET-456"},
  "justification": "Support agent needs access to review customer conversation for ticket TICKET-456"
}
```

**New Permissions**:

* `Role:CreateTemporaryPermissionGrant` - Required to create grants
* `Role:GetTemporaryPermissionGrant` - Controls which grants are visible in list queries

**Conversation Tags**

Tag conversations with key-value metadata for organization, filtering, and analytics.

**New Capabilities**:

* **Create with Tags**: Pass `tags` object when creating conversations
* **Filter by Tags**: Use `tags` query parameter in `GetConversations`
* **Modify Tags**: New `POST /{conversation_id}/tags/` endpoint for adding, updating, and removing tags

**Tag Constraints**:

* Maximum 20 tags per conversation
* Keys and values: alphanumeric characters, underscores, and spaces only
* Values can be `null` for flag-style tags

**Example** (Modify Tags):

```json
POST /v1/{org}/conversation/{conversation_id}/tags/
{
  "updates": {"department": "sales", "priority": "high"},
  "deletes": ["old_tag"]
}
```

**Change Tool Candidates Dynamic Behavior Action**

Dynamic behaviors now support the `change-tool-candidates` action type, allowing you to dynamically modify available tools based on conversation context.

**Example Configuration**:

```json
{
  "action": {
    "type": "change-tool-candidates",
    "tool_specs": [
      {
        "tool_id": "payment_processor",
        "version_constraint": ">=2.0.0"
      }
    ]
  }
}
```

**SSML Tag Support**

Audio fillers now support Speech Synthesis Markup Language (SSML) tags for fine-grained control over speech output in voice conversations.

**Supported Tags**:

* `<prosody>` - Control rate (0.6-1.5), volume (0.5-2.0)
* `<break>` - Insert pauses (e.g., `time="500ms"`)
* `<emotion>` - Apply emotional tone

**Constraints**: Audio fillers must be under 512 characters including SSML markup.

**Arabic Language Support**

Added `arabic` to supported voice languages for voice-enabled conversations.

**API Key Names**

API keys now support a `name` field for easier identification and management.

**Breaking Change**: The `name` parameter is now **required** when calling `CreateAPIKey`. Previously, a default name was generated automatically.

**Migration**:

```json
// Before (worked with default)
POST /v1/{org}/api_key/
{}

// After (name required)
POST /v1/{org}/api_key/
{
  "name": "Production Backend Key"
}
```

**Keyterms Field**

The `keyterms` field has been added to `GetService` and `GetUser` responses, providing extracted key terminology for context-aware interactions.

**New Permission: FinishConversation**

Added `Conversation:FinishConversation` permission for granular control over who can end conversations programmatically.

#### Breaking Changes

{% hint style="danger" %}
**Breaking changes in v0.7.0**: Voice config fields removed (`stability`, `similarity_boost`, `style`), deny permission grants removed, role inheritance removed, `CreateAPIKey` now requires a `name` parameter, and several legacy endpoints removed.
{% endhint %}

**Voice Configuration Simplified**

**Impact**: High | **Action Required**: Yes

Voice configuration has been simplified. Legacy voice configuration fields have been removed.

**What Changed**:

* Legacy fields removed from `VoiceConfig`: `stability`, `similarity_boost`, `style`
* Agent `voice_config` now only requires `voice_id`

**Migration**:

```json
// Updated voice_config format
"voice_config": {
  "voice_id": "your-voice-id"
}
```

1. Remove `stability`, `similarity_boost`, and `style` fields from voice configurations
2. Test voice output quality with the updated configuration

**Deny Permission Grants Removed**

**Impact**: High | **Action Required**: If using deny grants

The `"deny"` grant type has been removed from the permission system. Permissions now follow an allow-only model.

**What Changed**:

* `grant_type: "deny"` is no longer valid in role permission grants
* Existing deny grants will be ignored
* Permission checks use allow-only logic

**Migration**: Restructure role permissions to achieve the same access control using allow grants only. Consider using more specific conditions instead of broad allows with selective denies.

**Role Inheritance Removed**

**Impact**: Medium | **Action Required**: If using role inheritance

Roles no longer support inheritance from parent roles. Each role must define its complete permission set.

**What Changed**:

* `parent_role` field removed from role schema
* `CreateRole` and `ModifyRole` no longer accept parent role references
* Permissions are not inherited from other roles

**Migration**: Flatten inherited permissions directly into each role definition. Review and consolidate role hierarchies.

**GetRoles Response Schema Change**

**Impact**: Low | **Action Required**: If parsing `permission_grants` field

The backwards-compatibility `permission_grants` field has been removed from `GetRoles` responses. Use the `permissions` field instead.

**GetOrganizationMetrics Endpoint Removed**

**Impact**: Low | **Action Required**: If using this endpoint

The `GET /v1/{org}/metric/organization/` endpoint has been removed.

**External Event Message Field Rename**

**Impact**: Low | **Action Required**: If using external events

The `external_event_message` fields in `InteractWithConversation` request bodies have been renamed for consistency. Update your request payloads to use the corrected field names.

**CreateInvitedUser and UpdateUserInfo Endpoints Removed**

**Impact**: Low | **Action Required**: If using these endpoints

These legacy user management endpoints have been removed:

* `CreateInvitedUser` → Use `CreateUser` endpoint instead
* `UpdateUserInfo` → Use `ModifyUser` endpoint instead

#### Deprecations

{% hint style="warning" %}
**Deprecation**: The `tool_repo` field is deprecated. Use the `CreateToolVersion` endpoint to publish tool versions instead.
{% endhint %}

**tool\_repo Field**

The `tool_repo` field is deprecated and will be removed in a future release. Use the `CreateToolVersion` endpoint to publish tool versions instead.

**Audio Quality Adjustment**

The ability to adjust voice response audio quality (bitrate) has been deprecated. The platform now automatically selects optimal audio quality settings.

</details>

<details>

<summary>v0.6.1 - ToolCallState &#x26; Python 3.14 (November 20, 2025)</summary>

**ToolCallState Context Graph State Type**

The API supports a `ToolCallState` (type: `"tool-call"`), which enforces execution of a designated tool call before allowing state transitions. This provides deterministic control over agent workflows where specific tools must be invoked.

**Why This Matters**: Previous state types (ActionState, DecisionState, ReflectionState) allowed agents to opportunistically choose whether to call tools. ToolCallState guarantees a specific tool will be called, making it ideal for required data fetches, mandatory validations, or enforced workflow checkpoints.

**Key Features**:

* **Designated Tool Execution**: Specify exactly which tool must be called using `designated_tool`
* **Execution Guidance**: Provide `designated_tool_call_objective`, `designated_tool_call_context`, `designated_tool_call_guidances`, and `designated_tool_call_validations` to control how the agent uses the tool
* **Audio Support**: Configure audio fillers during tool call parameter generation with `designated_tool_call_params_generation_audio_fillers`
* **Additional Opportunistic Tools**: Allow supplementary tool calls via `tool_call_specs` while ensuring the designated tool is always executed
* **Persistence Requirement**: Designated tools must use `result_persistence: "persisted"` (validated at Context Graph creation)

**Example Configuration**:

```json
{
  "type": "tool-call",
  "name": "fetch_user_data",
  "next_state": "process_data",
  "designated_tool": {
    "tool_id": "get_user_profile",
    "version_constraint": ">=1.0.0",
    "additional_instruction": "Fetch the complete user profile",
    "result_persistence": "persisted"
  },
  "designated_tool_call_objective": "Retrieve user profile data for personalization",
  "designated_tool_call_context": "User has already authenticated and provided consent",
  "designated_tool_call_guidances": [
    "Use the user_id from the conversation context",
    "Request all profile fields including preferences"
  ],
  "designated_tool_call_validations": [
    "Verify user_id is present before calling",
    "Confirm response includes required fields: name, email, preferences"
  ],
  "designated_tool_call_params_generation_audio_fillers": [
    "Let me look up your information...",
    "Retrieving your profile..."
  ],
  "designated_tool_call_params_generation_audio_filler_triggered_after": 2.0,
  "tool_call_specs": []
}
```

**Use Cases**:

| Use Case                     | Why Use ToolCallState                               |
| ---------------------------- | --------------------------------------------------- |
| Required data fetches        | Ensure critical data is loaded before proceeding    |
| Mandatory compliance checks  | Guarantee validation steps are never skipped        |
| Workflow checkpoints         | Enforce specific actions at defined workflow stages |
| Authentication/authorization | Ensure security checks are always performed         |

**Related Documentation**:

* [Context Graph State Types](https://docs.amigo.ai/developer-guide/classic-api/core-api/agents-and-context-graphs) - Overview of all state types

**Python 3.14 Requirement for Tools**

The platform now requires Python 3.14 for all new tools and tool versions. This aligns tool development with the backend runtime environment upgrade completed in early November 2025.

**What Changed**:

* All new tools must specify `requires-python = ">=3.14"` in their `pyproject.toml`
* Ruff configuration must target Python 3.14: `target-version = "py314"`
* Existing deployed tools continue to function without modification

**Who This Affects**:

* ✅ **Action Required**: Developers creating new tools or publishing new tool versions
* ⚠️ **No Action Required**: Existing deployed tools and tool versions

**Migration Guide**:

Update your tool's `pyproject.toml` file before publishing new versions:

```toml
[project]
name = "my-tool"
version = "1.0.0"
requires-python = ">=3.14"  # Updated from >=3.13
# ... other settings

[tool.ruff]
target-version = "py314"  # Updated from py313
```

**Benefits**:

* Access to Python 3.14's performance improvements and new language features
* Consistent runtime environment between tool development and execution
* Better type checking and static analysis capabilities

</details>

<details>

<summary>v0.6.0 - Tool Call Result Persistence (November 13, 2025)</summary>

**Tool Call Result Persistence Implementation**

The `result_persistence` property gives you fine-grained control over tool call result visibility across agent interactions. This addresses the challenge of balancing context retention (persisting results for future reference) with performance (avoiding bloat from large outputs).

**Why This Matters**: Previously, all tool results were persisted regardless of size or relevance, leading to oversized conversation logs and degraded agent performance. Now you can optimize for your use case.

**What Changed**

**Persistence Behavior**

Tool call result persistence is now controlled by the `result_persistence` property, which accepts three modes:

| Mode                    | Output Storage                                          | Character Limit | Error on Exceed |
| ----------------------- | ------------------------------------------------------- | --------------- | --------------- |
| `"ephemeral"`           | Not persisted (only visible in current LLM interaction) | 20,000          | No              |
| `"persisted-preferred"` | Persisted if ≤ 5,000 characters, otherwise ephemeral    | 20,000          | No              |
| `"persisted"`           | Always persisted if ≤ 5,000 characters                  | 5,000           | Yes             |

{% hint style="danger" %}
**Breaking change**: `result_persistence` is now a required field on all tool call specs. Requests without this field return 400 Bad Request.
{% endhint %}

**Breaking Changes (Effective November 13, 2025)**

* **Required field**: `result_persistence` must be explicitly specified (previously had a default value of `"persisted"`)
* **Validation enforcement**: API requests without this field will fail with a 400 Bad Request error
* **Size validation**: Tool call results exceeding character limits will now fail for `"persisted"` mode (previously succeeded with truncation)

**Validation Rules**

* Designated tools in `ToolCallState` must use `result_persistence: "persisted"` (validation enforced at Context Graph creation)

**Migration Notes**

**Required Action** All tool call specifications in Context Graph definitions must now explicitly specify the `result_persistence` property. Configurations missing this field will be rejected.

**Recommended Values**

* Use `"persisted-preferred"` for most tools (provides graceful handling of large outputs)
* Use `"ephemeral"` for large datasets, file contents, or verbose debugging information
* Use `"persisted"` for critical context where outputs must always be available to the agent

**Related Documentation**

See the [Tool Result Persistence](https://docs.amigo.ai/developer-guide/classic-api/core-api/tools#tool-result-persistence) section in the Developer Guide for detailed configuration examples and best practices.

</details>


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.amigo.ai/api-reference/change-logs/amigo-api/amigo-api-archive-v0-6-v0-9-99.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
