From eaacd432e8249fddf966c38ab7277821e383bc4e Mon Sep 17 00:00:00 2001 From: indifferentketchup Date: Mon, 18 May 2026 01:10:51 +0000 Subject: [PATCH] feat(web): skills API types + client methods --- apps/web/src/api/client.ts | 19 +++++++++++++++++++ apps/web/src/api/types.ts | 10 ++++++++++ 2 files changed, 29 insertions(+) diff --git a/apps/web/src/api/client.ts b/apps/web/src/api/client.ts index 1212de6..fae6375 100644 --- a/apps/web/src/api/client.ts +++ b/apps/web/src/api/client.ts @@ -10,6 +10,7 @@ import type { ViewFileResult, AgentsResponse, GitMeta, + Skill, } from './types'; export class ApiError extends Error { @@ -187,6 +188,20 @@ export const api = { method: 'POST', body: JSON.stringify({ message_id: body.messageId, name: body.name }), }), + // Batch 9.6: slash-command invocation. Server loads the skill body + // authoritatively (client doesn't get to forge file contents), persists + // a synthetic skill_use tool_use + tool_result + user message + streaming + // assistant, and enqueues inference. Returns all 4 new message IDs. + skillInvoke: (chatId: string, skillName: string, userMessage: string | null) => + request<{ + synth_assistant_id: string; + tool_message_id: string; + user_message_id: string; + assistant_message_id: string; + }>(`/api/chats/${chatId}/skill_invoke`, { + method: 'POST', + body: JSON.stringify({ skill_name: skillName, user_message: userMessage }), + }), }, messages: { @@ -218,6 +233,10 @@ export const api = { request(`/api/projects/${projectId}/agents`), }, + skills: { + list: () => request<{ skills: Skill[] }>('/api/skills'), + }, + settings: { get: () => request>('/api/settings'), patch: (body: Record) => diff --git a/apps/web/src/api/types.ts b/apps/web/src/api/types.ts index 7745527..3dbf4a4 100644 --- a/apps/web/src/api/types.ts +++ b/apps/web/src/api/types.ts @@ -231,6 +231,16 @@ export interface GitMeta { behind: number; } +// Batch 9.6: skill catalog row. Returned by GET /api/skills and consumed by +// the slash-command dropdown. `path` and `mtime` are exposed for debug surface +// (/api/skills) but the dropdown only renders name + description. +export interface Skill { + name: string; + description: string; + path: string; + mtime: number; +} + // v1.9: 'settings' is an ephemeral pane kind — never persisted, always // singleton per workspace. The pane hook filters it out before writing to // localStorage and dedupes on insertion via toggleSettingsPane().