Automate 21risk tasks via Rube MCP (Composio). Always search tools first for current schemas.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Add or modify an AI chat tool ("Ask Ryo" capability) in ryOS. Covers the server-side tool definition (Zod schema + description + optional execute) and the client-side handler dispatch, plus the server-vs-client execution split. Use when giving the AI a new capability, adding a tool to the chat agent, or editing chat/tool schemas, descriptions, or handlers.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
실행 점수 미검증
설치 방법 보기설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.
ryOS chat tools follow the Vercel AI SDK tool-loop pattern. A tool is defined on the server (name + description + Zod inputSchema), and is either:
execute fn that runs in api/chat/tools/ (needs Redis, secrets, server fetch). Add the name to SERVER_EXECUTED_TOOL_NAMES.execute. The model emits a tool call, the browser runs a handler in src/apps/chats/tools/, and the result is sent back via addToolOutput (needs Zustand stores, IndexedDB, media/DOM APIs).| Concern | File |
|---|---|
| Server: input schemas (Zod) | api/chat/tools/schemas.ts |
| Server: descriptions + tool object + profile filtering | api/chat/tools/index.ts (TOOL_DESCRIPTIONS, createChatTools) |
| Server: shared types/constants | api/chat/tools/types.ts |
Server: execute logic | api/chat/tools/executors.ts, app-state-executors.ts, maps-executor.ts |
| Server/client: execution split source of truth | src/shared/tools/serverExecuted.ts |
| Client: per-tool handlers | src/apps/chats/tools/<name>Handler.ts |
| Client: handler types/registry | src/apps/chats/tools/types.ts, index.ts |
Client: dispatch (switch on tool name) | src/apps/chats/hooks/useAiChat.ts |
| Needs… | Execution |
|---|---|
| Redis, secrets, server-only fetch, SSRF-safe fetch | Server (execute) |
| Zustand store mutation, IndexedDB/VFS, media playback, app windows, DOM | Client (handler) |
Some tools run both ways (e.g. stickiesControl, calendarControl, contactsControl): client in web chat, server in the Telegram profile. In that case provide both a handler and an executor.
api/chat/tools/schemas.ts)Schemas are Zod. Keep action-style tools as a discriminated/enum action plus optional params, and use .superRefine for cross-field rules so the model gets a clear error before the handler runs.
export const myFeatureControlSchema = z.object({
action: z.enum(["list", "create", "delete"]),
id: z.string().optional(),
content: z.string().optional(),
});
Add any shared enums/constants to types.ts and import them here (mirrors CALENDAR_ACTIONS, TV_ACTIONS, etc.).
api/chat/tools/index.ts)TOOL_DESCRIPTIONS (the model relies heavily on this — describe each action, required params, and when NOT to use it).allTools object inside createChatTools.Client-executed (no execute):
myFeatureControl: {
description: TOOL_DESCRIPTIONS.myFeatureControl,
inputSchema: schemas.myFeatureControlSchema,
// No execute — handled client-side (requires Zustand store access)
},
Server-executed:
myFeatureControl: {
description: TOOL_DESCRIPTIONS.myFeatureControl,
inputSchema: schemas.myFeatureControlSchema,
execute: async (input: MyFeatureControlInput) => executeMyFeatureControl(input, context),
},
If the tool should be available to the Telegram/memory profiles, also add it to the relevant branch in createChatTools (the telegram profile object or MEMORY_TOOL_NAMES). Tools default to the "all" profile.
src/shared/tools/serverExecuted.ts)If (and only if) the tool is server-executed, add it to TOOL_EXECUTION_METADATA with execution: "server". The client uses SERVER_EXECUTED_TOOL_NAME_SET to skip client dispatch for these (it returns early without running a handler).
export const TOOL_EXECUTION_METADATA = [
// ...
{ name: "myFeatureControl", execution: "server" },
] as const;
Client-executed tools do NOT go here.
Create src/apps/chats/tools/myFeatureHandler.ts. The handler reads/writes Zustand stores and reports a result through context.addToolOutput.
import type { ToolContext } from "./types";
import { useMyFeatureStore } from "@/stores/useMyFeatureStore";
import { useAppStore } from "@/stores/useAppStore";
import i18n from "@/lib/i18n";
export interface MyFeatureControlInput {
action: "list" | "create" | "delete";
id?: string;
content?: string;
}
export const handleMyFeatureControl = (
input: MyFeatureControlInput,
toolCallId: string,
context: ToolContext
): void => {
const store = useMyFeatureStore.getState();
try {
switch (input.action) {
case "list": {
context.addToolOutput({
tool: "myFeatureControl",
toolCallId,
output: JSON.stringify(store.items, null, 2),
});
break;
}
// create / delete ...
default:
context.addToolOutput({
tool: "myFeatureControl",
toolCallId,
state: "output-error",
errorText: i18n.t("apps.chats.toolCalls.unknownError"),
});
}
} catch (error) {
context.addToolOutput({
tool: "myFeatureControl",
toolCallId,
state: "output-error",
errorText: error instanceof Error ? error.message : "error",
});
}
};
Handler conventions (match existing handlers like stickiesHandler.ts):
addToolOutput per call — a success output string or an { state: "output-error", errorText }.i18n.t(...) (apps.chats.toolCalls.*).context.launchApp("myfeature") / guard with useAppStore.getState().getInstancesByAppId).createShortIdMap / resolveId from ./helpers to keep token usage low.ToolContext provides { launchApp, addToolOutput, detectUserOS }.
src/apps/chats/tools/index.ts, export the handler and its input type.src/apps/chats/tools/dispatchToolCall.ts (shared by the Chats app and the desktop assistant), add a case to the switch (toolCall.toolName):case "myFeatureControl": {
handleMyFeatureControl(
toolCall.input as MyFeatureControlInput,
toolCall.toolCallId,
toolContext
);
result = ""; // handler already called addToolOutput
break;
}
Dispatch is an explicit
switch— there is no handler registry. Add thecase, otherwise the tool falls through to thedefaultbranch and reports "Unhandled tool". Setresult = ""when the handler emits its own output (return a non-empty string only for trivial tools that don't calladdToolOutput). VFS tools (list/open/read/write/edit) live invfsHandlers.tsand receive aVfsToolContextwithsaveFile+recordOpenedInstance.
Add executeMyFeatureControl(input, context) to executors.ts (or app-state-executors.ts for app-state tools), export it from api/chat/tools/index.ts, and reference it in the tool's execute. The executor receives the server context (MemoryToolContext: logging, env, redis/auth helpers) and must return a JSON-serializable result.
For tools that return images to the model (like infiniteMacControl's readScreen), add a toModelOutput that converts the result into multimodal content.
tests/unit/<domain>/test-<feature>-schema.test.ts that safeParses valid and invalid inputs (see tests/unit/media/test-media-control-unified.test.ts). Unit suites are auto-discovered. See the write-tests skill.test:ai) where applicable.- [ ] Schema in api/chat/tools/schemas.ts (+ shared enums in types.ts)
- [ ] Description in TOOL_DESCRIPTIONS + entry in createChatTools (right profile)
- [ ] If server-executed: add to TOOL_EXECUTION_METADATA (serverExecuted.ts) + write executor
- [ ] If client-executed: handler in src/apps/chats/tools/ + export + switch case in useAiChat.ts
- [ ] Localize tool-call strings (apps.chats.toolCalls.*)
- [ ] Schema unit test in tests/ (registered in test:unit)
아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.
로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.
아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.
Automate 21risk tasks via Rube MCP (Composio). Always search tools first for current schemas.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Automate 2chat tasks via Rube MCP (Composio). Always search tools first for current schemas.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Set up and use 1Password CLI for sign-in, desktop integration, and reading or injecting secrets.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Build integrated IS/BS/CF financial workbooks in Excel.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Entry point for 9Router — local/remote AI gateway with OpenAI-compatible REST for chat, image, TTS, embeddings, web search, web fetch. Use when the user mentions 9Router, NINEROUTER_URL, or wants AI without writing provider boilerplate. This skill covers setup + indexes capability skills; fetch the relevant capability SKILL.md from the URLs below when needed.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Chat / code generation via 9Router using OpenAI /v1/chat/completions or Anthropic /v1/messages format with streaming + auto-fallback combos. Use when the user wants to ask an LLM, generate code, summarize text, or run prompts through 9Router.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.