feat(server): skills v1 — parser, tools, /api/skills, mount
- /data/skills mount (host: /opt/skills) - skill_find, skill_use, skill_resource added to default read-only tool set; opt-in for agents with explicit tools: whitelist - AGENTS.md builtin agents drop explicit tools: arrays to inherit the new default (now includes skill tools) - POST /api/chats/:id/skill_invoke for slash-command flow - 19 SKILL.md files seeded at /opt/skills/ across 6 source groups
This commit is contained in:
@@ -15,8 +15,10 @@ import { registerSidebarRoutes } from './routes/sidebar.js';
|
||||
import { registerWebSocket } from './routes/ws.js';
|
||||
import { registerModelRoutes } from './routes/models.js';
|
||||
import { registerAgentRoutes } from './routes/agents.js';
|
||||
import { registerSkillsRoutes } from './routes/skills.js';
|
||||
import { createInferenceRunner } from './services/inference.js';
|
||||
import { createBroker } from './services/broker.js';
|
||||
import { listSkills } from './services/skills.js';
|
||||
|
||||
async function main() {
|
||||
const config = loadConfig();
|
||||
@@ -62,6 +64,15 @@ async function main() {
|
||||
registerSidebarRoutes(app, sql);
|
||||
registerChatRoutes(app, sql, broker);
|
||||
|
||||
// Batch 9.6: warm the skills cache at boot and surface the count. Empty or
|
||||
// missing /data/skills is non-fatal — the skill tools just return empty.
|
||||
try {
|
||||
const skills = await listSkills();
|
||||
app.log.info(`skills loaded: ${skills.length}`);
|
||||
} catch (err) {
|
||||
app.log.warn({ err }, 'skills boot walk failed');
|
||||
}
|
||||
|
||||
const inference = createInferenceRunner(
|
||||
{
|
||||
sql,
|
||||
@@ -113,6 +124,33 @@ async function main() {
|
||||
});
|
||||
},
|
||||
});
|
||||
registerSkillsRoutes(app, sql, {
|
||||
enqueueInference: (sessionId, chatId, assistantId, user) => {
|
||||
inference.enqueue(sessionId, chatId, assistantId, user);
|
||||
},
|
||||
publishUserMessage: (sessionId, chatId, userMessageId, content) => {
|
||||
broker.publish(sessionId, {
|
||||
type: 'message_started',
|
||||
message_id: userMessageId,
|
||||
chat_id: chatId,
|
||||
role: 'user',
|
||||
});
|
||||
broker.publish(sessionId, {
|
||||
type: 'delta',
|
||||
message_id: userMessageId,
|
||||
chat_id: chatId,
|
||||
content,
|
||||
});
|
||||
broker.publish(sessionId, {
|
||||
type: 'message_complete',
|
||||
message_id: userMessageId,
|
||||
chat_id: chatId,
|
||||
});
|
||||
},
|
||||
publishSessionFrame: (sessionId, frame) => {
|
||||
broker.publish(sessionId, frame);
|
||||
},
|
||||
});
|
||||
registerWebSocket(app, sql, broker);
|
||||
|
||||
const webDist = process.env.WEB_DIST_PATH ?? resolve(process.cwd(), '../web/dist');
|
||||
|
||||
Reference in New Issue
Block a user