opencode and native tasks

This commit is contained in:
2026-02-16 20:20:09 +00:00
parent 9ab0940ca4
commit dca4743e8b
3 changed files with 31 additions and 4 deletions
+1 -1
View File
@@ -26,7 +26,7 @@ Transcribe an audio file to text using whisper.cpp.
## Steps
1. Determine the user's root directory by navigating one level up from the current working directory. Read `settings.json` from the root directory and extract the `languages` section.
1. Starting from the directory containing the audio file, walk up parent by parent until you find a directory whose name is an email address. This is the user's root directory. Read `settings.json` from it and extract the `languages` section.
2. Detect the language of the audio file using the whisper.cpp skill with `detect_language=true` and `response_format=verbose_json`.
3. Compare the detected language against the user's `languages.spoken` list. If the detected language is in the list, skip translation. Otherwise, set `translate=true`.
4. Use the whisper.cpp skill to transcribe the audio file at `file_path`, passing the detected language as the `language` parameter and the `translate` flag from the previous step.
File diff suppressed because one or more lines are too long
+29 -2
View File
@@ -2,7 +2,8 @@ import type { ServerWebSocket } from 'bun';
import { mkdir, rename } from 'node:fs/promises';
import { join } from 'node:path';
import type { ClientMessage, ServerMessage, ImageData, TaskInfo } from '@@/api/chat-types';
import { getTmpAttachmentsDir, getAttachmentsDir } from '@@/data-path';
import { getTmpAttachmentsDir, getAttachmentsDir, getNativeSkillsDir, getGlobalSkillsDir, getUserSkillsDir } from '@@/data-path';
import { readSkillDirs, parseFrontmatter } from '@@/api/skills/skills';
import { createTaskLog, appendToLog, finalizeLog } from '@@/api/task-logger';
const OPENCODE_PORT = process.env.OPENCODE_PORT ?? '10006';
@@ -303,6 +304,29 @@ function handleSSEEvent(ws: ServerWebSocket<WSData>, event: string, data: any) {
}
}
async function buildSkillsPrompt(email: string): Promise<string> {
const nativeSkills = await readSkillDirs(getNativeSkillsDir());
const globalSkills = await readSkillDirs(getGlobalSkillsDir());
const userSkills = await readSkillDirs(getUserSkillsDir(email));
const merged = new Map(nativeSkills);
for (const [name, path] of globalSkills) merged.set(name, path);
for (const [name, path] of userSkills) merged.set(name, path);
if (merged.size === 0) return '';
const lines = await Promise.all(
Array.from(merged.entries()).map(async ([dirName, filePath]) => {
const raw = await Bun.file(filePath).text();
const { frontmatter } = parseFrontmatter(raw);
const name = frontmatter.name || dirName;
return `- ${name}: ${frontmatter.description} (read ${filePath} for full instructions)`;
}),
);
return `\n\nYou have access to the following skills. When a user's request matches a skill, read its SKILL.md file for detailed instructions before proceeding.\n\nAvailable skills:\n${lines.join('\n')}`;
}
type HandleChatParams = {
ws: ServerWebSocket<WSData>;
prompt: string;
@@ -368,6 +392,9 @@ async function handleChat({ ws, prompt, sessionId, model, attachmentIds, images,
}
}
const skillsAppend = await buildSkillsPrompt(ws.data.email);
const fullPrompt = skillsAppend ? `${skillsAppend}\n\n${prompt}` : prompt;
const parts: Record<string, unknown>[] = [];
if (images?.length) {
for (const img of images) {
@@ -378,7 +405,7 @@ async function handleChat({ ws, prompt, sessionId, model, attachmentIds, images,
});
}
}
parts.push({ type: 'text', text: prompt });
parts.push({ type: 'text', text: fullPrompt });
const promptBody: Record<string, unknown> = { parts };
if (modelSelection.modelId) {