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.
中文简介正在准备中。当前显示原文说明。
实测评分 未实测
查看安装方法安装前可以查看交给 AI 代理的指令内容。
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.
中文简介正在准备中。当前显示原文说明。