ExtSkill guide (extended skills)

ExtSkill guide (extended skills)

⚠️ Not yet released: in-development v1.5.0-SNAPSHOT capability; interface and protocol may change. Do not use in production before the official release.

New in v1.5.0. ExtSkill = extended skills: the application attaches custom skills to an agent, then at runtime first query the list of extended skills currently available on that agent, and invoke one of them to run. It sits alongside passive / active / teleop, using its own event family and the AgentPolicy.EXT_SKILL policy (wire value "extskill"). The Python API mirrors Java 1:1 with PEP 8 snake_case naming.

When to use

  • The application has configured extended skills for an agent on the LinkSoul platform (weather lookup, ticket creation, device control, etc.) and needs to discover the list at runtime and trigger them on demand.
  • You need to bypass the dialogue chain and call a deterministic capability directly (structured input, structured output) instead of LLM free-form generation.
  • One invoke returns in three stages: on_invoke_ack first (gateway accepted the request), then on_state for execution-time progress reports (optional), then on_invoke_result (the skill's actual execution output).

Flow

After register_ext_skill, call query to fetch the list and invoke to trigger execution any number of times; unregister_ext_skill to release when done.

text
   ┌─────────────────────────────┐
   │  ExtSkillRequest.query       │  fetch available extended-skill list
   │    (on_query_result)         │
   └─────────────────────────────┘

   ┌─────────────────────────────┐
   │  ExtSkillRequest.invoke      │  trigger a skill to run
   │    (on_invoke_ack)           │  ← stage 1: gateway accepted
   │    (on_state)                │  ← stage 2: execution-time state report (0..n)
   │    (on_invoke_result)        │  ← stage 3: execution output
   └─────────────────────────────┘
  • query returns once via on_query_result; when code == 0, result carries the skill list and related content.
  • invoke returns in three stages: on_invoke_ack (accept), then on_state (execution-time progress reported via agentsdk.ext_skill.report_state, zero or more times), then on_invoke_result (output; param carries the result when code == 0).
  • If the SDK connection is already closed at send time, the query / invoke callback fires synchronously on the calling thread once with code == 1000 + msg == "Agentsdk connection is closed".

Event family & protocol

Python event-type enum lives at linksoul_agentsdk.enums.AgentEventType:

Enum memberEvent type stringMeaning
AGENTSDK_EXT_SKILL_QUERYagentsdk.ext_skill.queryQuery available extended skills (SDK → gateway)
AGENTSDK_EXT_SKILL_QUERY_RESULTagentsdk.ext_skill.query_resultQuery result (gateway → SDK)
AGENTSDK_EXT_SKILL_INVOKEagentsdk.ext_skill.invokeTrigger a skill (SDK → gateway)
AGENTSDK_EXT_SKILL_INVOKE_ACKagentsdk.ext_skill.invoke_ackAccept receipt (gateway → SDK)
AGENTSDK_EXT_SKILL_REPORT_STATEagentsdk.ext_skill.report_stateExecution-time state report (gateway → SDK)
AGENTSDK_EXT_SKILL_INVOKE_RESULTagentsdk.ext_skill.invoke_resultExecution result (gateway → SDK)

Wire structure of every ExtSkill message:

json
{
  "type": "<event type>",
  "agentId": "<target agent agentId>",
  "eventId": "event_xxxxxxxxxxxxxxxxxxxxx",
  "agentMode": "extskill",
  "requestId": "extskill_xxxxxxxxxxxxxxxxxxxxx"
}
  • Unlike Teleop (which uses sn), ExtSkill uses agentId as the agent identity field.
  • requestId comes from IdGenerator.generate_ext_skill_request_id(); it is the identity of one extended-skill session and is reused by query / invoke.
  • invoke additionally carries extSkillId (the skill to trigger) and input (flat input key-values, matching input_param.get_ext_param()).
  • agentMode is always "extskill" (matching AgentPolicy.EXT_SKILL).

invoke input

The input_param of invoke(ext_skill_id, input_param, invoke_callback, timeout) is an AgentParam carrying the skill's structured input; the exact keys are defined by the skill. Example:

python
input_param = (
    AgentParam.create()
    .set_string("city", "shanghai")
    .set_integer("days", 3)
)
event_id = ext_skill_request.invoke("skill_weather", input_param, invoke_callback, 2000)

It is sent as flat key-values on the wire ({"input": {"city": "shanghai", "days": 3}}), matching dict(input_param.get_ext_param()).

Result codes

The code of query / invoke callbacks is uniform:

codeMeaning
0Success (result / param carries returned content)
-1Server returned failure; msg carries errorMsg
1000Local failure: LinkskyClient was closed at send time; the SDK invokes this code synchronously on the calling thread

When code != 0, both result (in on_query_result) and param (in on_invoke_result) are None.

API cheat-sheet

  • Request class: linksoul_agentsdk.ExtSkillRequest
  • Callback bases: ExtSkillQueryCallback (on_query_result) / ExtSkillInvokeCallback (on_invoke_ack + on_state + on_invoke_result)
  • Register: AgentSdk.register_ext_skill(ExtSkillRequest) / AgentSdk.unregister_ext_skill(request_id)
  • ID: IdGenerator.generate_ext_skill_request_id()

Full signatures: ExtSkill API. Runnable example: ExtSkill examples.

Lifecycle & cleanup

  • AgentSdkExtSkillMgr tracks active requests keyed by request_id. Always register_ext_skill(...) before calling query / invoke.
  • Every request method call refreshes an internal update_ts; requests idle for 7200 s are GC'd by a background sweeper.
  • When done, call agent_sdk.unregister_ext_skill(request_id) to release eagerly.
  • AgentSdk.release() clears all ExtSkill requests owned by this instance.

ExtSkill vs. Teleop

AspectTeleopExtSkill
PolicyAgentPolicy.TELEOP ("teleop")AgentPolicy.EXT_SKILL ("extskill")
Identity fieldssn + teleop_idagentId + request_id
Core actionsenter / audio / keepalive / exitquery / invoke
Result modelsingle ACKquery: single result; invoke: three stages (ack + state + result)

Java ↔ Python mapping

JavaPython
ExtSkillRequest.query(cb, timeout)ExtSkillRequest.query(query_callback, timeout)
ExtSkillRequest.invoke(extSkillId, input, cb, timeout)ExtSkillRequest.invoke(ext_skill_id, input_param, invoke_callback, timeout)
ExtSkillQueryCallback.onQueryResult(...)ExtSkillQueryCallback.on_query_result(...)
ExtSkillInvokeCallback.onInvokeAck(...)ExtSkillInvokeCallback.on_invoke_ack(...)
ExtSkillInvokeCallback.onState(...)ExtSkillInvokeCallback.on_state(...)
ExtSkillInvokeCallback.onInvokeResult(...)ExtSkillInvokeCallback.on_invoke_result(...)
AgentSdk.registerExtSkill(...)AgentSdk.register_ext_skill(...)
AgentSdk.unregisterExtSkill(...)AgentSdk.unregister_ext_skill(...)
IdGenerator.generateExtSkillRequestId()IdGenerator.generate_ext_skill_request_id()