Skip to navigation

Changelog

View as Markdown

Release history for the AgentDuet Python SDK. Each release lists new features, behavior changes, fixes, and any action needed when you upgrade. The current documentation targets 1.1.0b10.

The 1.1.0b* versions are pre-releases. Install the documented version with pip install agentduet==1.1.0b10. A plain pip install agentduet does not select pre-releases by default.

1.1.0b10 — 2026-10-26

Documentation

  • Updated the PyPI package description to list every trigger-condition option, including fallback recording and spoken drop messages.
  • No SDK behavior changed from 1.1.0b9.

Known issue

VoiceAgent.call_out(), dial(), and place_call() use the wrong incoming audio track for agent-placed outgoing calls. The call can connect and play model audio, but the model does not receive the callee’s audio correctly. Versions 1.1.0b2 through 1.1.0b10 are affected. The fix is not included in this release.

For outbound two-way audio, use Session.make_call() and Call.dial() directly. Read the remote audio from call.callee.audio_stream(). See the outbound Quick Start.

1.1.0b9 — 2026-10-26

Added

  • Fallback call recordings: Set fallback_recording(True) to record calls that the fallback connects without an agent. Register @sm.on_call_recording to receive recording details, then use sm.download_recording() to get stereo Ogg Opus audio.
  • Recording acknowledgment: By default, a successful recording handler acknowledges and deletes the recording on the server. Use auto_ack=False to control deletion after you store the recording. list_call_recordings() lists pending recordings; ack_call_recordings() acknowledges them and returns a count.
  • Spoken drop messages: Use drop_message(text) with CallFallback.DROP to play a message before the server ends the call. The message must contain 1 to 500 characters after trimming.

Changed

  • A notified call must be claimed within 10 seconds of delivery, reduced from 60 seconds.
  • At the session limit, the server waits up to 15 seconds for a slot, reduced from 30 seconds. The claim period starts when the notification arrives.

Upgrade action: Call session.process_call(noti) before slow setup, database requests, or model connections. Review your fallback policy because an unclaimed call can connect without the agent or end.

See Trigger Conditions and Event Handling.

1.1.0b8 — 2026-10-13

Added

  • DDUET conversation handover: Use Session.hand_over_conversation() to transfer a conversation to staff. Send the closing message first. You can include a staff-only summary. The method returns ConversationHandoverResult; inspect success and the error fields.

After handover, conversation messages stop reaching the agent and further sends return FORBIDDEN. Only staff can assign the conversation back to the agent. DDUET voice calls and remote function calls can still reach the agent.

Changed

  • Control connections now reconnect with full-jitter exponential backoff: a random delay within an increasing window, capped at 8 seconds.
  • Heartbeat pings run every 15 seconds with a 5-second response timeout.

Removed

  • Removed TriggerConditionsBuilder.call_log() and TriggerConditions.call_log. Do not post a call-log message part from your application.

See DDUET conversation handover and connection recovery.

1.1.0b7 — 2026-10-06

Added

  • Server-bound sessions: Incoming messages, call notifications, and function calls include an optional session_id. Reuse this ID when the server supplies one.
  • Participant attachment: Pass participant=Address(...) to open_session() to attach the remote party immediately.
  • Session keep-alive: Use async with session.keep_alive(): during slow work to refresh an existing session slot. The default refresh interval is 20 seconds. It does not restore an expired slot.
  • Conversation association: Echo an incoming conversation value on related send_message() and make_call() operations. On DDUET, this also identifies the conversation for the call-log entry.
  • Call fallback: Configure CallFallback.DROP or CONNECT_TO_DESTINATION for calls that no agent claims.
  • Conversation ID aliases: DDUET parsing reads convoId first and falls back to sessionUid. The convo_id and dduet_convo_id properties expose the same values under the new name.

Changed

  • Opening a new session without participant= does not yet create a server session or consume a session slot. The first claim or send creates it.
  • The server applies fallback when a call remains unclaimed. An incoming call connects to its destination only when inbound_call is ALL and the fallback permits connection. Otherwise, the server ends the call.

Upgrade action: Reuse server-provided session and conversation IDs. Set every trigger option that your application needs; each setup replaces the full configuration. The call timing was reduced again in 1.1.0b9, as listed above.

See Sessions and Call Handoff and Trigger Conditions.

1.1.0b6 — 2026-10-05

Added

  • DDUET remote function calls: Register @sm.on_function_call(name) to receive an IncomingFunctionCall. Claim the call with session.process_function_call(fn) before doing the work. Answer with session.send_function_result() or reject it with fn.reject().
  • Delivery reporting: The SDK reports message receipt and processing outcomes to the service. Outcomes include successful handling, handler errors, and dropped messages. Applications do not need a new callback for these reports.

Changed

Renamed identity fields to make message and call direction explicit:

Previous nameCurrent name
subscriber on models and supported method parameterssubscriber_id
IncomingMessage.participantIncomingMessage.from_address
IncomingCallNotification.participantIncomingCallNotification.from_address
OutgoingCallNotification.participantOutgoingCallNotification.to_address

Notifications also expose the opposite address as to_address or from_address. Call.caller, Call.callee, Call.participant, and SendDduetMessage.participant keep their names.

Deprecated

  • Previous identity properties remain as read-only aliases in this release and emit DeprecationWarning.
  • The old subscriber= keyword remains accepted where its replacement is subscriber_id=. Passing both spellings raises TypeError.

Fixed

  • Fixed incoming event delivery stopping after the 100th frame.

Upgrade action: Use the current field and parameter names. To find deprecated usage, run your tests with -W error::DeprecationWarning.

See Participant Model and remote function calls.

1.1.0b5 — 2026-09-14

Added

  • DDUET media upload: Use Session.upload_media(UploadDduetMedia(...)) to upload a file. Reference the returned UploadedMedia in a message with SendDduetMessage.compose() or UploadedMedia.as_part().
  • Media downloads through sessions: Session.download_media() returns one attachment’s bytes. download_media_all() returns ordered DownloadedMedia results, including individual failures.
  • Call origin: Call.origin identifies whether the agent, subscriber, or external participant started the call. Only an agent-originated call uses dial().

Breaking changes

  • Replaced the media URL helpers introduced in 1.1.0b4 with session upload and download methods. Removed SessionManager.get_dduet_media_urls(), get_media_urls(), MediaUrl, and the module-level download_media() helper.
  • Renamed DduetMediaUid to DduetMediaAttachment. Attachments now carry the metadata and routing needed to download them.
  • Removed ba_uid from outgoing DDUET messages. Open the session for the acting business account; the session supplies its identity on each send.
  • Changed the serialized call origin from _origin to origin, using AGENT, SUBSCRIBER, or PARTICIPANT. Earlier JSON handoff payloads are incompatible with this format.

Upgrade action: Replace the removed media helpers and outgoing-message ba_uid= arguments. Drain pending call handoffs before upgrading across the origin-format change. Use the same SDK version on both nodes that exchange serialized calls.

See DDUET media and Sessions and Call Handoff.

1.1.0b4 — 2026-09-03

Added

  • Added DDUET media-download URL resolution and a download helper.

These original media APIs were replaced in 1.1.0b5. For current applications, use the Session media methods.

1.1.0b3 — 2026-08-25

Added

  • Token-provider authentication: Pass a zero-argument sync or async function to SessionManagerConfig.create(token_provider=...). It must return a non-empty bearer token.
  • The SDK requests a fresh token before each control connection attempt and authenticated HTTP request.
  • TokenProviderError reports a failed provider or an invalid token value. A provider failure during reconnection stops retries and surfaces through run_forever() and sm.fatal_error.

This is a third authentication option alongside API key authentication and mTLS. Use an async provider for long waits, such as interactive sign-in.

See Token provider authentication.

1.1.0b2 — 2026-08-21

Breaking changes

  • Removed the nested DDUET address object introduced in 1.1.0b1.
  • Replaced IncomingMessage.address and IncomingMessage.dduet_session_uid with the typed msg.dduet view.
  • Outgoing DDUET messages use session_uid and participant to address replies. The temporary outgoing ba_uid argument was later removed in 1.1.0b5.
  • SendMessageResult.dduet_session_uid reads the conversation identifier from the send response.

Documentation

  • Updated the DDUET quick start and reference tables to use the flat message format.
  • Documented the user_uid and ba_uid comparison for identifying the message author. DDUET reply handlers should ignore messages authored by their own business-account staff.

WhatsApp message routing and voice calling were unaffected by the DDUET message-format change. See DDUET messages.

1.1.0b1 — 2026-08-17

Added

  • DDUET chat: Added a messaging channel for text and media, including Network.DDUET, Address.dduet(), and SendDduetMessage.
  • Outgoing-call notifications: Added @sm.on_outgoing_call for calls that the subscriber starts outside the SDK. Enable these notifications with outbound_call(True).
  • Outgoing message idempotency: Added client_msg_id to session.send_message(). Reuse the same ID when retrying one logical message so the server can identify a completed send.

Breaking changes

  • Introduced a nested DDUET address object for message routing. That format was replaced in 1.1.0b2 and must not be used with 1.1.0b10.

1.0.0 — 2026-08-10

First stable release under the agentduet package name. This release redesigns the earlier telcoflow-sdk API around connector notifications, subscriber sessions, and calls.

Added

  • SessionManager for the control connection and incoming call and message handlers.
  • Session for claiming calls, creating outgoing calls, and sending messages for a subscriber.
  • Call and CallParty for call control and separate caller and callee audio streams.
  • VoiceAgent for model-adapter-based voice agents. Ready-made adapters ship in the separate agentduet-adapters package.
  • CallAudioConfig for sample rate, outgoing buffer size, and incoming audio queue limits.
  • Trigger conditions for connector routing, API key and mTLS authentication, and JSON call handoff between workers.

Changed

  • Call states are NEW, OPENING, RINGING, LIVE, and TERMINATED.
  • Expected command failures return an unsuccessful CommandResult. State errors, closed calls, and full audio buffers raise exceptions.
  • Call audio uses separate party tracks. The previous audio-mode setting is no longer required.

Removed

  • Removed the ActiveCall API and the SDK TTS methods introduced in 0.27.1.
  • Removed CloseReason, the public voice-connection property, and the top-level BufferClosedError export.

Migration from telcoflow-sdk

  1. Replace the package dependency and imports with agentduet.
  2. Register notification handlers on SessionManager.
  3. Open a session for the subscriber, then claim or create a call through that session.
  4. Read party audio through call.caller.audio_stream() or call.callee.audio_stream().
  5. Catch TransportError for control-connection failures and CallClosedError when a voice call ends.
  6. Replace WSS_BASE_URL with AGENTDUET_BASE_URL.

DDUET messaging and application-supplied client_msg_id were added in the 1.1.0 pre-release series, not in 1.0.0.

Earlier telcoflow-sdk releases

Versions 0.27.1 and earlier used the telcoflow-sdk package name. The following entries describe that historical API. They are not instructions for the current agentduet release.

0.27.1 — 2026-05-06

Added

  • Voice cloning through ActiveCall.enable_tts(voice_id) and ActiveCall.send_tts(text).
  • CallEvent.CALL_ERROR, CallErrorCode.TTS_SESSION_ERROR, and ActiveCall.on_error() for non-fatal call errors.

These SDK TTS methods were removed in agentduet 1.0.0.

0.27.0 — 2026-04-13

Added

  • Channel selection on ActiveCall.audio_stream(channel_id=...) for mixed and separate party audio.
  • AudioMode.MIXED and AudioMode.ISOLATED configuration.

Current AgentDuet calls use separate CallParty streams instead of this API.

0.26.1 — 2026-04-06

Fixed

  • Restored control-connection reconnection after transient failures.

0.26.0 — 2026-03-26

Fixed

  • Sent the interruption command to the server when an interruption occurred.

0.25.0 — 2026-03-25

Changed

  • Renamed ActiveCall.force_disconnect() to the private _force_close() method.
  • Added automatic cleanup when a call ends.

Upgrade action: Remove application calls to force_disconnect() and let the SDK manage cleanup.

0.24.0 — 2026-03-19

Added

  • Support for 8000 Hz audio alongside 16000 Hz and 24000 Hz.

Fixed

  • Minor bugs.

0.21.0 — 2026-03-16

Changed

  • Renamed the command-response timeout parameter to response_timeout_seconds.

Added

  • BufferClosedError and ActiveCall.force_disconnect() for the APIs available at that time.

0.20.0 — 2026-03-10

Changed

  • Introduced enum-based event registration and improved signal and connection handling.
  • Changed ActiveCall.close() so the agent leaves while the server manages media shutdown.

Added

  • ActiveCall.disconnect() to end a call for all parties.

Removed

  • Removed ActiveCall.hangup(), deprecated event constants, and ActiveCall.is_connected().

0.18.0 — 2026-03-07

Changed

  • An unanswered connect() reports CALL_UNANSWERED through CallCommandError in this historical API. Applications could handle the error and decide whether to retry or end the call.