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
querythe list of extended skills currently available on that agent, andinvokeone of them to run. It sits alongside passive / active / teleop, using its own event family and theAgentPolicy.EXT_SKILLpolicy (wire value"extskill"). The Python API mirrors Java 1:1 with PEP 8snake_casenaming.
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
invokereturns in three stages:on_invoke_ackfirst (gateway accepted the request), thenon_statefor execution-time progress reports (optional), thenon_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.
┌─────────────────────────────┐
│ 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
└─────────────────────────────┘
queryreturns once viaon_query_result; whencode == 0,resultcarries the skill list and related content.invokereturns in three stages:on_invoke_ack(accept), thenon_state(execution-time progress reported viaagentsdk.ext_skill.report_state, zero or more times), thenon_invoke_result(output;paramcarries the result whencode == 0).- If the SDK connection is already closed at send time, the
query/invokecallback fires synchronously on the calling thread once withcode == 1000+msg == "Agentsdk connection is closed".
Event family & protocol
Python event-type enum lives at linksoul_agentsdk.enums.AgentEventType:
| Enum member | Event type string | Meaning |
|---|---|---|
AGENTSDK_EXT_SKILL_QUERY | agentsdk.ext_skill.query | Query available extended skills (SDK → gateway) |
AGENTSDK_EXT_SKILL_QUERY_RESULT | agentsdk.ext_skill.query_result | Query result (gateway → SDK) |
AGENTSDK_EXT_SKILL_INVOKE | agentsdk.ext_skill.invoke | Trigger a skill (SDK → gateway) |
AGENTSDK_EXT_SKILL_INVOKE_ACK | agentsdk.ext_skill.invoke_ack | Accept receipt (gateway → SDK) |
AGENTSDK_EXT_SKILL_REPORT_STATE | agentsdk.ext_skill.report_state | Execution-time state report (gateway → SDK) |
AGENTSDK_EXT_SKILL_INVOKE_RESULT | agentsdk.ext_skill.invoke_result | Execution result (gateway → SDK) |
Wire structure of every ExtSkill message:
{
"type": "<event type>",
"agentId": "<target agent agentId>",
"eventId": "event_xxxxxxxxxxxxxxxxxxxxx",
"agentMode": "extskill",
"requestId": "extskill_xxxxxxxxxxxxxxxxxxxxx"
}
- Unlike Teleop (which uses
sn), ExtSkill usesagentIdas the agent identity field. requestIdcomes fromIdGenerator.generate_ext_skill_request_id(); it is the identity of one extended-skill session and is reused byquery/invoke.invokeadditionally carriesextSkillId(the skill to trigger) andinput(flat input key-values, matchinginput_param.get_ext_param()).agentModeis always"extskill"(matchingAgentPolicy.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:
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:
code | Meaning |
|---|---|
0 | Success (result / param carries returned content) |
-1 | Server returned failure; msg carries errorMsg |
1000 | Local 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
AgentSdkExtSkillMgrtracks active requests keyed byrequest_id. Alwaysregister_ext_skill(...)before callingquery/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
| Aspect | Teleop | ExtSkill |
|---|---|---|
| Policy | AgentPolicy.TELEOP ("teleop") | AgentPolicy.EXT_SKILL ("extskill") |
| Identity fields | sn + teleop_id | agentId + request_id |
| Core actions | enter / audio / keepalive / exit | query / invoke |
| Result model | single ACK | query: single result; invoke: three stages (ack + state + result) |
Java ↔ Python mapping
| Java | Python |
|---|---|
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() |