feat(host): user-invocable skill listing and skill.invoke injection RPC

skill.list now serves every user-invocable skill and carries modelInvocable
so menus can mark user-only entries; the old model-and-user intersection
hid disable-model-invocation skills from their only legitimate entry point
(issue #1470). skill.invoke enforces user-invocation policy at the host
boundary, renders the canonical <skill_content> body, and injects it as a
user-role message carrying the skill-invocation source before starting a
turn. The connection fixture mirrors both faces for client tests.
This commit is contained in:
Yichen Jiang
2026-08-08 00:51:24 +08:00
parent 62c308f415
commit 85422f44dc
13 changed files with 261 additions and 16 deletions
@@ -14,6 +14,7 @@ export const skillEntrySchema = z.object({
name: z.string().min(1),
description: z.string(),
whenToUse: z.string().optional(),
modelInvocable: z.boolean(),
}) satisfies z.ZodType<Wire<SkillEntry>>
/** skill.list request payload. */
@@ -25,3 +26,15 @@ export const skillListRequestSchema = z.object({
export const skillListValueSchema = z.object({
skills: z.array(skillEntrySchema),
}) satisfies z.ZodType<Wire<ResponseValue<'skill.list'>>>
/** skill.invoke request payload. */
export const skillInvokeRequestSchema = z.object({
sessionId: sessionIdSchema,
name: z.string().min(1),
text: z.string().optional(),
}) satisfies z.ZodType<Wire<RequestPayload<'skill.invoke'>>>
/** skill.invoke response value. */
export const skillInvokeValueSchema = z.object({
accepted: z.literal(true),
}) satisfies z.ZodType<Wire<ResponseValue<'skill.invoke'>>>