Changelog

Changelog

v1.5.0-SNAPSHOT (Current Development)

⚠️ This is an in-development (SNAPSHOT) release. The v1.5.0 additions below (teleop / extended skills) are not yet released and the interfaces may change.

Release Date: In Development

🆕 New capability: beyond-line-of-sight teleop

v1.5.0 opens a third interaction path on top of passive / active — remote-operator teleop.

  • New classes:
    • linksoul_agentsdk.TeleopRequest — session entity: enter / start_audio(param) / append_audio_delta / done_audio / keepalive / exit
    • linksoul_agentsdk.TeleopEnterCallback — on_enter_ack(teleop_id, event_id, code, msg)
    • linksoul_agentsdk.TeleopKeepaliveCallback — on_keepalive_ack(teleop_id, event_id, code, msg); robot online probe, recommend calling every 10 seconds during the session, code != 0 means the robot is offline
    • linksoul_agentsdk.TeleopExitCallback — on_exit_ack(teleop_id, event_id, code, msg)
    • linksoul_agentsdk.mgr.AgentSdkTeleopMgr — global request index, 7200 s idle sweeper
  • New AgentSdk public methods:
    • register_teleop(TeleopRequest)
    • unregister_teleop(teleop_id: str)
  • New policy enum: AgentPolicy.TELEOP (wire value "teleop")
  • Nine new event types under AGENTSDK_TELEOP_* (includes agentsdk.teleop.keepalive / agentsdk.teleop.keepalive_ack)
  • New id-prefix generator: IdGenerator.generate_teleop_id() → "teleop_<21 chars>"
  • New docs: Teleop guide · Teleop API · Teleop example

🆕 New capability: Extended Skills (ExtSkill)

v1.5.0 also introduces ExtSkill — query the robot's available skill list and remotely invoke a specific skill (three-phase acknowledgement: ack → state → result). During execution the skill side may report progress repeatedly via agentsdk.ext_skill.report_state (mapped to on_state). Uses agentId + requestId to identify each request.

  • New classes:
    • linksoul_agentsdk.ExtSkillRequest — skill request entity: query / invoke
    • linksoul_agentsdk.ExtSkillQueryCallback — on_query_result(request_id, event_id, code, msg, skills)
    • linksoul_agentsdk.ExtSkillInvokeCallback — on_invoke_ack(request_id, event_id, code, msg) + on_state(agent_id, request_id, event_id, state_name, state_value) + on_invoke_result(request_id, event_id, code, msg, result)
  • New AgentSdk public methods:
    • register_ext_skill(ExtSkillRequest)
    • unregister_ext_skill(request_id: str)
  • New policy enum: AgentPolicy.EXT_SKILL (wire value "extskill")
  • Six new event types:
    • agentsdk.ext_skill.query / agentsdk.ext_skill.query_result
    • agentsdk.ext_skill.invoke / agentsdk.ext_skill.invoke_ack / agentsdk.ext_skill.report_state / agentsdk.ext_skill.invoke_result
  • New id-prefix generator: IdGenerator.generate_ext_skill_request_id() → "extskill_<21 chars>"
  • New docs: ExtSkill guide · ExtSkill API · ExtSkill example

⚠️ Breaking change: console "Skill Invocation Method = Agent Invocation" removed (v1.5.0 required)

With the introduction of Function Call + Arbiter in v1.5.0, the platform's skill-forwarding mode — setting Skill Invocation Method to Agent Invocation in the custom-agent configuration — has been removed:

  • Before (≤ v1.4.0): with Skill Invocation Method set to Agent Invocation, the platform forwarded triggered skill requests to your agent (SDK) for custom handling.
  • Now (v1.5.0): the platform no longer forwards skills. It surfaces pending skill requests as function calls to the SDK (on_function_call), and your agent decides delegation explicitly via the Arbiter interface (response.on_arbiter(...)): ArbiterDecision.DELEGATE (hand off to the default chain) or ArbiterDecision.OVERRIDE (agent takes over).

If your agent relies on the "Skill Invocation Method = Agent Invocation" forwarding behaviour, you must upgrade to v1.5.0 and reimplement skill delegation on top of Function Call + Arbiter, otherwise skills will no longer be handled.

Contract

text
register_teleop → enter → (start_audio(param) → append_audio_delta* → done_audio)+ → exit → unregister_teleop

Call keepalive at any frequency during the session (recommended every 10 seconds). If any on_keepalive_ack returns code != 0, treat the robot as offline and exit + unregister_teleop immediately.

  • enter / keepalive / exit are ack'd via callback (code == 0 OK, code == 1000 local close, code == -1 server reject).
  • start_audio / append_audio_delta / done_audio are fire-and-forget.
  • start_audio(param) supports voice / VAD tuning per segment: role ("male" / "female"), threshold (-14 ~ 14).
  • timeout is a placeholder (clamped to >=50 ms) — no timeout callback yet.

🆕 New capability: Function Call dispatch & Arbiter arbitration

v1.5.0 opens Function Call dispatch and Arbiter arbitration on the passive interaction path (in-development capability, not yet released).

  • New callback (on all 8 passive callbacks): on_function_call(agent_id, event_id, function_call, response) — the gateway forwards a pending function call
  • New response method (on all 8 Response classes): on_arbiter(event_id, decision, arb_param) — returns the decision, emits agentsdk.function_call.arbiter
  • New data class: linksoul_agentsdk.FunctionCallInfo (source / policy / type / value / param)
  • New enum: linksoul_agentsdk.ArbiterDecision (DELEGATE / OVERRIDE / ILLEGAL)
  • Two new event types: agentsdk.function_call.expose / agentsdk.function_call.arbiter

🆕 New capability: conversation history passthrough (onHistories)

  • New shared base callback: on_histories(agent_id, event_id, histories) (default log-only impl on PassiveCallback; override as needed)
  • New data class: linksoul_agentsdk.HistoryInfo (timestamp / query / answer / complete / event_id / skill)
  • One new event type: agentsdk.histories.expose (gateway → SDK)

Compatibility

  • API-level fully backward-compatible with v1.4.0: existing register_auth, passive callbacks, and task-flow APIs are unchanged. Bump pip package version from 1.4.0 → 1.5.0.
  • If you don't use teleop or Function Call, runtime behaviour is identical to v1.4.0.
  • One breaking change applies: agents that relied on the console's "Skill Invocation Method = Agent Invocation" forwarding must be migrated to Function Call + Arbiter as described above.

Dependencies

Same as v1.4.0 — no third-party upgrades.


v1.4.0 (alpha)

Release date: in development

⚠️ Breaking change — auth/signing standardised (NOT compatible with v1.3.0 or earlier)

v1.4.0 standardises the AgentSDK signing scheme to align with the LinkSoul open-platform spec. The Python SDK ships the change together with the Java SDK; v1.3.0 (and earlier) clients cannot upgrade in place:

Itemv1.3.0 and earlierv1.4.0
Gateway URLwss://agentsdk.agibot.com/v1/agentsdkwss://open.agibot.com/api/V1/open-portal/app/wss/agent-sdk
Credential sourceLegacy custom-agent templateApplication on the LinkSoul open platform (adds app_key)
FactoryAgentSdk.create(url, app_id, app_secret)AgentSdk.create(url, app_id, app_key, app_secret)
AlgorithmJWT (HS256) sent via AGIBOT_AUTHORIZATIONHMAC-SHA256("GET\n{path}\n{timestamp}\n{nonce}"), delivered across five signed headers
Auth headers1 header: AGIBOT_AUTHORIZATION5 headers: X-App-Id / X-App-Key / X-Timestamp / X-Nonce / X-Signature
callback_types transportJWT payload fieldStandalone header X-Callback-Types (JSON array string)
Implementation impactLinkskyClient depends on jwt_util.pyLinkskyClient switches to hmac + hashlib; AgentSdk no longer exposes app_secret

Migration checklist:

  1. Re-issue app_id / app_key / app_secret from the open-platform application page; old credentials are not accepted.
  2. Switch the WebSocket gateway URL to wss://open.agibot.com/api/V1/open-portal/app/wss/agent-sdk.
  3. Replace every AgentSdk.create(url, app_id, app_secret) call with AgentSdk.create(url, app_id, app_key, app_secret).
  4. If you proxy SDK traffic through a custom gateway, parse and propagate the new five-header signature plus X-Callback-Types, and stop relying on AGIBOT_AUTHORIZATION.
  5. Make sure no code still reads AgentSdk.app_secret — the attribute has been removed.

Equivalent to the Java SDK v1.4.0 — refer to the Java CHANGELOG for the complete protocol-level change list. This page only enumerates Python-specific notes.

Python-specific implementation

  • Package name: linksoul_agentsdk (PEP 8 snake_case), 1-to-1 mapped from the Java packages
  • Public modules: linksoul_agentsdk.passive / .active / .client / .mgr
  • WebSocket client: built on websocket-client>=1.7, synchronous blocking, running run_forever in a dedicated daemon thread
  • Heartbeat: handled by websocket-client (ping_interval=10s, ping_timeout=5s)
  • Reconnect: automatically scheduled by a threading.Timer 3 s after disconnect
  • Threading: AgentThreadMgr uses single-thread ThreadPoolExecutor instances, one per agent_id (matching Java AgentThreadMgr)
  • Auth: built on hmac + hashlib (HMAC-SHA256), matching Java LinkskyClient.hmacSha256. The signature is delivered through five request headers — X-App-Id / X-App-Key / X-Timestamp / X-Nonce / X-Signature — and the set of registered callback types travels in X-Callback-Types

Public API naming

Java camelCase is translated to Python snake_case, with full typing annotations:

JavaPython
AgentSdk.create(url, appId, appKey, appSecret)AgentSdk.create(url, app_id, app_key, app_secret)
registerAuth(AgentAuthCallback)register_auth(AgentAuthCallback)
registerAsr2Llm(Asr2LlmCallback)register_asr2_llm(Asr2LlmCallback)
onRequest(agentId, eventId, ...)on_request(agent_id, event_id, ...)
response.onLlmItemDelta(...)response.on_llm_item_delta(...)
response.onInterrupt(...)response.on_interrupt(...)
response.onSkill(...)response.on_skill(...)
IdGenerator.generateEventId()IdGenerator.generate_event_id()
AgentParam.create().setString(k, v)AgentParam.create().set_string(k, v)

Dependencies

DependencyVersion
Python3.9+
websocket-client≥ 1.7.0

Tests

  • 73+ unit tests using pytest + a mock LinkskyClient — no real WebSocket server required in CI
  • Run via pip install -e ".[dev]" && pytest

Historical versions

Java & Python stay version-aligned — see the Java SDK v1.4.0 CHANGELOG for the protocol changes that landed in earlier releases (v1.0.0 / v1.1.0 / v1.3.0).