From b68e8f99d1e4867f71737bdd9851b4cdf2dc4eff Mon Sep 17 00:00:00 2001 From: zhouli <1932489836@qq.com> Date: Sun, 12 Apr 2026 15:45:25 +0800 Subject: [PATCH] change(skills): move basic demo skills into main --- application/basic_demo/.gitignore | 1 + .../fatfs_image/skills/cap_im_feishu.md | 80 -------------- .../fatfs_image/skills/cap_im_qq.md | 81 -------------- .../fatfs_image/skills/cap_im_tg.md | 79 -------------- .../fatfs_image/skills/cap_im_wechat.md | 63 ----------- .../fatfs_image/skills/cap_llm_inspect.md | 35 ------ .../fatfs_image/skills/cap_lua_run.md | 69 ------------ .../fatfs_image/skills/lua_module_delay.md | 14 --- .../skills/lua_module_event_publisher.md | 21 ---- .../fatfs_image/skills/lua_module_gpio.md | 16 --- .../skills/lua_module_led_strip.md | 19 ---- .../fatfs_image/skills/lua_module_storage.md | 18 --- .../basic_demo/fatfs_image/skills/lua_run.md | 69 ------------ .../fatfs_image/skills/lua_write.md | 64 ----------- .../fatfs_image/skills/qq_send_file.md | 55 ---------- .../fatfs_image/skills/skills_list.json | 103 ------------------ .../basic_demo/main/skills/skills_list.json | 13 +++ .../{fatfs_image => main}/skills/weather.md | 0 .../basic_demo/tools/sync_component_skills.py | 29 ++--- 19 files changed, 30 insertions(+), 799 deletions(-) create mode 100644 application/basic_demo/.gitignore delete mode 100644 application/basic_demo/fatfs_image/skills/cap_im_feishu.md delete mode 100644 application/basic_demo/fatfs_image/skills/cap_im_qq.md delete mode 100644 application/basic_demo/fatfs_image/skills/cap_im_tg.md delete mode 100644 application/basic_demo/fatfs_image/skills/cap_im_wechat.md delete mode 100644 application/basic_demo/fatfs_image/skills/cap_llm_inspect.md delete mode 100644 application/basic_demo/fatfs_image/skills/cap_lua_run.md delete mode 100644 application/basic_demo/fatfs_image/skills/lua_module_delay.md delete mode 100644 application/basic_demo/fatfs_image/skills/lua_module_event_publisher.md delete mode 100644 application/basic_demo/fatfs_image/skills/lua_module_gpio.md delete mode 100644 application/basic_demo/fatfs_image/skills/lua_module_led_strip.md delete mode 100644 application/basic_demo/fatfs_image/skills/lua_module_storage.md delete mode 100644 application/basic_demo/fatfs_image/skills/lua_run.md delete mode 100644 application/basic_demo/fatfs_image/skills/lua_write.md delete mode 100644 application/basic_demo/fatfs_image/skills/qq_send_file.md delete mode 100644 application/basic_demo/fatfs_image/skills/skills_list.json create mode 100644 application/basic_demo/main/skills/skills_list.json rename application/basic_demo/{fatfs_image => main}/skills/weather.md (100%) diff --git a/application/basic_demo/.gitignore b/application/basic_demo/.gitignore new file mode 100644 index 0000000..7401846 --- /dev/null +++ b/application/basic_demo/.gitignore @@ -0,0 +1 @@ +fatfs_image/skills diff --git a/application/basic_demo/fatfs_image/skills/cap_im_feishu.md b/application/basic_demo/fatfs_image/skills/cap_im_feishu.md deleted file mode 100644 index 8b40fa7..0000000 --- a/application/basic_demo/fatfs_image/skills/cap_im_feishu.md +++ /dev/null @@ -1,80 +0,0 @@ -# Feishu Messaging - -Use this skill when the user wants to interact through Feishu, especially to reply in the current Feishu conversation or send local files back to Feishu. - -## When to use -- The user sends a message from Feishu and expects a reply in the same chat. -- The user asks to send a text, image, document, report, log, or other local file to a Feishu chat. -- The task is clearly Feishu-specific rather than QQ, Telegram, or WeChat. - -## Available capabilities -- `feishu_send_message`: send plain text to a Feishu chat. -- `feishu_send_image`: send a local image file to a Feishu chat. -- `feishu_send_file`: send a local non-image file to a Feishu chat. - -## Calling rules -- Call the direct Feishu capabilities. Do not route Feishu messaging through `cap_cli`. -- When replying to the current inbound Feishu conversation, you can omit `chat_id` if the runtime context already contains it. -- When starting a new outbound send or the target chat is ambiguous, pass an explicit `chat_id`. -- Use `feishu_send_message` for text only. -- Use `feishu_send_image` for image files such as `.jpg`, `.jpeg`, `.png`, `.gif`, or `.webp`. -- Use `feishu_send_file` for non-image files such as `.txt`, `.json`, `.log`, `.csv`, `.pdf`, or archives. -- `caption` is optional for image and file sends. In Feishu media send flow, caption is sent as a follow-up text message. - -## Chat ID guidance -- Feishu text send accepts either a chat id or a user `open_id`. -- If the target begins with `ou_`, the runtime treats it as a user `open_id`. -- Otherwise it is treated as a Feishu `chat_id`. -- For replies triggered by an inbound Feishu message, prefer using the current context instead of inventing a `chat_id`. - -## File path guidance -- `path` must be a real local filesystem path on the device. -- If the exact path is unknown, inspect storage first with file capabilities such as `list_dir`. -- Do not pass remote URLs directly to Feishu send capabilities. -- In this demo app, inbound Feishu attachments are typically saved under `/fatfs/data/inbox`. - -## Recommended workflow -1. Determine whether the user wants text, an image, or a generic file. -2. Resolve the target Feishu chat or `open_id`. -3. Resolve the local file path if sending media. -4. Call `feishu_send_message`, `feishu_send_image`, or `feishu_send_file` directly. -5. After the capability returns success, tell the user the reply or file has already been sent. - -## Examples - -Reply with text to the current Feishu chat: -```json -{ - "message": "The task has been completed." -} -``` - -Send text to an explicit Feishu user: -```json -{ - "chat_id": "ou_xxx123456", - "message": "Latest status: device is online." -} -``` - -Send an image: -```json -{ - "chat_id": "oc_xxx123456", - "path": "/fatfs/data/inbox/capture.jpg", - "caption": "Here is the image." -} -``` - -Send a file: -```json -{ - "chat_id": "oc_xxx123456", - "path": "/fatfs/data/reports/status.json", - "caption": "Latest report." -} -``` - -## Notes -- This skill is for Feishu only. If the user is on another IM channel, use that channel's capability group instead. -- Feishu send capabilities return JSON such as `{\"ok\":true}` on success. diff --git a/application/basic_demo/fatfs_image/skills/cap_im_qq.md b/application/basic_demo/fatfs_image/skills/cap_im_qq.md deleted file mode 100644 index c566002..0000000 --- a/application/basic_demo/fatfs_image/skills/cap_im_qq.md +++ /dev/null @@ -1,81 +0,0 @@ -# QQ Messaging - -Use this skill when the user wants to interact through QQ Bot channels, especially to reply in the current QQ conversation or send local files back to QQ. - -## When to use -- The user sends a message from QQ and expects a reply in the same chat. -- The user asks to send a text, image, screenshot, report, log, or other local file to a QQ chat. -- The task is clearly QQ-specific rather than Telegram, Feishu, or WeChat. - -## Available capabilities -- `qq_send_message`: send plain text to a QQ chat. -- `qq_send_image`: send a local image file to a QQ chat. -- `qq_send_file`: send a local non-image file to a QQ chat. - -## Calling rules -- Call the direct QQ capabilities. Do not route QQ messaging through `cap_cli`. -- When replying to the current inbound QQ conversation, you can omit `chat_id` if the runtime context already contains it. -- When starting a new outbound send or the target chat is ambiguous, pass an explicit `chat_id`. -- Use `qq_send_message` for text only. -- Use `qq_send_image` for image files such as `.jpg`, `.jpeg`, `.png`, `.gif`, or `.webp`. -- Use `qq_send_file` for non-image files such as `.txt`, `.json`, `.log`, `.csv`, `.pdf`, or archives. -- `caption` is optional for image and file sends. Include it only when the user wants accompanying text. - -## Chat ID guidance -- Private QQ chats are normalized as `c2c:`. -- Group QQ chats are normalized as `group:`. -- For replies triggered by an inbound QQ message, prefer using the current context instead of inventing a `chat_id`. -- If the user explicitly provides a QQ target, preserve it exactly when it already matches the expected `c2c:` or `group:` format. - -## File path guidance -- `path` must be a real local filesystem path on the device. -- If the exact path is unknown, inspect storage first with file capabilities such as `list_dir`. -- Do not attempt to send remote URLs directly. Download or locate the file on local storage first. -- In this demo app, inbound QQ attachments are typically saved under `/fatfs/data/inbox`. - -## Recommended workflow -1. Determine whether the user wants text, an image, or a generic file. -2. Resolve the target chat. -3. Resolve the local file path if sending media. -4. Call `qq_send_message`, `qq_send_image`, or `qq_send_file` directly. -5. After the capability returns success, tell the user the reply or file has already been sent. - -## Examples - -Reply with text to the current QQ chat: -```json -{ - "message": "The task has been completed." -} -``` - -Send text to an explicit QQ group: -```json -{ - "chat_id": "c2c:1234567890", - "message": "Latest status: device is online." -} -``` - -Send an image: -```json -{ - "chat_id": "c2c:1234567890", - "path": "/fatfs/data/inbox/capture.jpg", - "caption": "Here is the image." -} -``` - -Send a file: -```json -{ - "chat_id": "c2c:abcdefg123456", - "path": "/fatfs/data/reports/status.json", - "caption": "Latest report." -} -``` - -## Notes -- This skill is for QQ only. If the user is on another IM channel -- The capability returns success text like `reply already sent to user`; do not repeat the same content again as if it still needs to be delivered. -- Generic file delivery may still depend on QQ platform-side support. If `qq_send_file` fails, report the failure clearly and consider whether the file can be sent as an image instead. diff --git a/application/basic_demo/fatfs_image/skills/cap_im_tg.md b/application/basic_demo/fatfs_image/skills/cap_im_tg.md deleted file mode 100644 index fa5d306..0000000 --- a/application/basic_demo/fatfs_image/skills/cap_im_tg.md +++ /dev/null @@ -1,79 +0,0 @@ -# Telegram Messaging - -Use this skill when the user wants to interact through Telegram, especially to reply in the current Telegram conversation or send local files back to Telegram. - -## When to use -- The user sends a message from Telegram and expects a reply in the same chat. -- The user asks to send a text, image, screenshot, report, log, or other local file to a Telegram chat. -- The task is clearly Telegram-specific rather than QQ, Feishu, or WeChat. - -## Available capabilities -- `tg_send_message`: send plain text to a Telegram chat. -- `tg_send_image`: send a local image file to a Telegram chat. -- `tg_send_file`: send a local non-image file to a Telegram chat. - -## Calling rules -- Call the direct Telegram capabilities. Do not route Telegram messaging through `cap_cli`. -- When replying to the current inbound Telegram conversation, you can omit `chat_id` if the runtime context already contains it. -- When starting a new outbound send or the target chat is ambiguous, pass an explicit `chat_id`. -- Use `tg_send_message` for text only. -- Use `tg_send_image` for image files such as `.jpg`, `.jpeg`, `.png`, `.gif`, or `.webp`. -- Use `tg_send_file` for non-image files such as `.txt`, `.json`, `.log`, `.csv`, `.pdf`, or archives. -- `caption` is optional for image and file sends. Include it only when the user wants accompanying text. - -## Chat ID guidance -- Telegram `chat_id` is usually a numeric string such as `"123456789"` or `"-1001234567890"`. -- For replies triggered by an inbound Telegram message, prefer using the current context instead of reconstructing the `chat_id`. -- If the user gives a Telegram target explicitly, preserve it exactly. - -## File path guidance -- `path` must be a real local filesystem path on the device. -- If the exact path is unknown, inspect storage first with file capabilities such as `list_dir`. -- Do not pass remote URLs directly to Telegram send capabilities. -- In this demo app, inbound Telegram attachments are typically saved under `/fatfs/data/inbox`. - -## Recommended workflow -1. Determine whether the user wants text, an image, or a generic file. -2. Resolve the target Telegram chat. -3. Resolve the local file path if sending media. -4. Call `tg_send_message`, `tg_send_image`, or `tg_send_file` directly. -5. After the capability returns success, tell the user the reply or file has already been sent. - -## Examples - -Reply with text to the current Telegram chat: -```json -{ - "message": "Task completed." -} -``` - -Send text to an explicit Telegram chat: -```json -{ - "chat_id": "-1001234567890", - "message": "Latest status: device is online." -} -``` - -Send an image: -```json -{ - "chat_id": "123456789", - "path": "/fatfs/data/inbox/capture.jpg", - "caption": "Here is the image." -} -``` - -Send a file: -```json -{ - "chat_id": "123456789", - "path": "/fatfs/data/reports/status.json", - "caption": "Latest report." -} -``` - -## Notes -- This skill is for Telegram only. If the user is on another IM channel, use that channel's capability group instead. -- The capability returns success text like `reply already sent to user`; do not phrase the result as a pending action. diff --git a/application/basic_demo/fatfs_image/skills/cap_im_wechat.md b/application/basic_demo/fatfs_image/skills/cap_im_wechat.md deleted file mode 100644 index 64f6b54..0000000 --- a/application/basic_demo/fatfs_image/skills/cap_im_wechat.md +++ /dev/null @@ -1,63 +0,0 @@ -# WeChat Messaging - -Use this skill when the user wants to interact through WeChat, especially to send text or a local image to a WeChat contact or group. - -## When to use -- The user asks to send a text reply or image through WeChat. -- The task is clearly WeChat-specific rather than QQ, Telegram, or Feishu. -- The target WeChat `chat_id` is known or can be taken from the current workflow context outside the capability call. - -## Available capabilities -- `wechat_send_message`: send plain text to a WeChat chat. -- `wechat_send_image`: send a local image file to a WeChat chat. -- `wechat_gateway`: WeChat inbound event source. This is infrastructure, not a capability the model should call directly. - -## Calling rules -- Call the direct WeChat capabilities. Do not route WeChat messaging through `cap_cli`. -- `wechat_send_message` requires explicit `chat_id` and `message`. -- `wechat_send_image` requires explicit `chat_id` and `path`, with optional `caption`. -- Unlike Telegram, QQ, and Feishu, the current WeChat callable implementation does not fall back to `ctx->chat_id`. Always pass `chat_id` explicitly. -- Use `wechat_send_message` for text only. -- Use `wechat_send_image` for image files such as `.jpg`, `.jpeg`, `.png`, `.gif`, or `.webp`. - -## Chat ID guidance -- WeChat inbound routing uses the group id when present, otherwise the sender user id. -- In practice, `chat_id` is typically a room id or a user id string already known by the integration. -- If the user gives a concrete WeChat target such as a room id or contact id, preserve it exactly. - -## File path guidance -- `path` must be a real local filesystem path on the device. -- If the exact image path is unknown, inspect storage first with file capabilities such as `list_dir`. -- Do not pass remote URLs directly to WeChat send capabilities. -- In this demo app, inbound WeChat media is typically saved under `/fatfs/data/inbox`. - -## Recommended workflow -1. Confirm that the target channel is WeChat. -2. Resolve the explicit WeChat `chat_id`. -3. Resolve the local image path if sending media. -4. Call `wechat_send_message` or `wechat_send_image` directly. -5. After the capability returns success, tell the user the message or image has already been sent. - -## Examples - -Send text to a WeChat chat: -```json -{ - "chat_id": "room123", - "message": "Latest status: device is online." -} -``` - -Send an image: -```json -{ - "chat_id": "wxid_abc123", - "path": "/fatfs/data/inbox/capture.jpg", - "caption": "Here is the image." -} -``` - -## Notes -- This skill is for WeChat only. If the user is on another IM channel, use that channel's capability group instead. -- The current capability surface supports text and image send, but not generic non-image file send. -- WeChat send capabilities return `{\"ok\":true}` on success. diff --git a/application/basic_demo/fatfs_image/skills/cap_llm_inspect.md b/application/basic_demo/fatfs_image/skills/cap_llm_inspect.md deleted file mode 100644 index 6c71f02..0000000 --- a/application/basic_demo/fatfs_image/skills/cap_llm_inspect.md +++ /dev/null @@ -1,35 +0,0 @@ -# Image Inspection - -Use this skill when the user wants the device to inspect a local image and describe what is visible. - -## When to use -- The user asks what is in an image, photo, screenshot, or camera frame. -- The image already exists on the device filesystem. -- The task needs visual analysis rather than plain file reading. - -## Available capability -- `inspect_image`: analyze one local image from an absolute path using a prompt that says what to inspect. - -## Calling rules -- Call `inspect_image` directly. -- Always pass an absolute local file path in `path`. -- Always pass a clear `prompt` that tells the model what to look for. -- Confirm or discover the image path first if it is not already known. -- Do not pass remote URLs or non-image files. - -## Path guidance -- Prefer real local paths already stored on the device. -- If the exact path is unknown, inspect storage first with file capabilities such as `list_dir`. -- Common roots in this demo include `/fatfs/data/inbox`, `/fatfs/data`, or other application-managed storage paths. - -## Example -```json -{ - "path": "/fatfs/data/inbox/photo.jpg", - "prompt": "Describe the main objects in this image and mention any visible text." -} -``` - -## Notes -- Keep the prompt specific. For example: identify objects, read visible text, describe a scene, or check whether a target item appears. -- If the image is blurry or uncertain, report that uncertainty instead of over-claiming. diff --git a/application/basic_demo/fatfs_image/skills/cap_lua_run.md b/application/basic_demo/fatfs_image/skills/cap_lua_run.md deleted file mode 100644 index 3acfa92..0000000 --- a/application/basic_demo/fatfs_image/skills/cap_lua_run.md +++ /dev/null @@ -1,69 +0,0 @@ -# Lua Script Execution - -Use this skill when the user wants to see existing Lua scripts, run one, or inspect async execution jobs. - -## Command Rule -- The LLM should call Lua through the direct capability execute entrypoints, not through `cap_cli`. -- Use `lua_list_scripts` to inspect scripts. -- Use `lua_run_script` for synchronous execution. -- Use `lua_run_script_async` for long-running or continuous scripts. -- Use `lua_list_async_jobs` and `lua_get_async_job` to inspect async jobs. - -## Running a Script Synchronously -Use `lua_run_script` when the user wants immediate output. -- Required: `path` -- Optional: `args`, `timeout_ms` -- Prefer relative paths such as `hello.lua` - -Examples: -```json -{ - "path": "hello.lua" -} -``` - -```json -{ - "path": "blink.lua", - "args": { - "pin": 2 - }, - "timeout_ms": 3000 -} -``` - -If the script expects structured inputs, pass them through `args`. The runtime exposes them to Lua as the global `args`. - -## Running a Script Asynchronously -Use `lua_run_script_async` for long-running or continuous scripts. -- Required: `path` -- Optional: `args`, `timeout_ms` - -Examples: -```json -{ - "path": "blink.lua" -} -``` - -```json -{ - "path": "blink.lua", - "args": { - "pin": 2 - }, - "timeout_ms": 3000 -} -``` - -After starting an async script: -- Use `lua_list_async_jobs` -- Use `lua_list_async_jobs` with `{"status":"running"}` -- Use `lua_get_async_job` with `{"job_id":""}` - -## Execution Notes -- Paths must resolve under `/spiffs/lua` and end with `.lua`. -- `--timeout-ms` must be a positive integer when provided. -- Prefer synchronous run for short scripts that should finish and return text. -- Prefer async run for loops, animations, watchers, or long-running device behaviors. -- If the user asks to run a script that does not exist yet, switch to the Lua authoring flow first. diff --git a/application/basic_demo/fatfs_image/skills/lua_module_delay.md b/application/basic_demo/fatfs_image/skills/lua_module_delay.md deleted file mode 100644 index a186617..0000000 --- a/application/basic_demo/fatfs_image/skills/lua_module_delay.md +++ /dev/null @@ -1,14 +0,0 @@ -# Lua Delay - -This skill describes how to correctly use delay when writing Lua scripts. - -## How to call -- Import it with `local delay = require("delay")` -- Call `delay.delay_ms(ms)` to sleep for a number of milliseconds -- `ms` should be an integer greater than or equal to `0` - -## Example -```lua -local delay = require("delay") -delay.delay_ms(500) -``` diff --git a/application/basic_demo/fatfs_image/skills/lua_module_event_publisher.md b/application/basic_demo/fatfs_image/skills/lua_module_event_publisher.md deleted file mode 100644 index 6e1010c..0000000 --- a/application/basic_demo/fatfs_image/skills/lua_module_event_publisher.md +++ /dev/null @@ -1,21 +0,0 @@ -# Lua Event Publisher - -This skill describes how to correctly use event_publisher when writing Lua scripts. - -## How to call -- Import it with `local event_publisher = require("event_publisher")` -- Call `event_publisher.publish_message({...})` to publish a message event -- Call `event_publisher.publish_trigger({...})` to publish a trigger event -- Call `event_publisher.publish({...})` to publish a full custom event - -## Example -```lua -local event_publisher = require("event_publisher") - -event_publisher.publish_message({ - source_cap = "lua_script", - channel = "custom", - chat_id = "demo", - text = "hello" -}) -``` diff --git a/application/basic_demo/fatfs_image/skills/lua_module_gpio.md b/application/basic_demo/fatfs_image/skills/lua_module_gpio.md deleted file mode 100644 index ec5361e..0000000 --- a/application/basic_demo/fatfs_image/skills/lua_module_gpio.md +++ /dev/null @@ -1,16 +0,0 @@ -# Lua GPIO - -This skill describes how to correctly use gpio when writing Lua scripts. - -## How to call -- Import it with `local gpio = require("gpio")` -- Call `gpio.set_direction(pin, mode)` to set pin mode -- Call `gpio.set_level(pin, level)` to set output level -- Call `gpio.get_level(pin)` to read pin level - -## Example -```lua -local gpio = require("gpio") -gpio.set_direction(2, "output") -gpio.set_level(2, 1) -``` diff --git a/application/basic_demo/fatfs_image/skills/lua_module_led_strip.md b/application/basic_demo/fatfs_image/skills/lua_module_led_strip.md deleted file mode 100644 index 8bbe88d..0000000 --- a/application/basic_demo/fatfs_image/skills/lua_module_led_strip.md +++ /dev/null @@ -1,19 +0,0 @@ -# Lua LED Strip - -This skill describes how to correctly use led_strip when writing Lua scripts. - -## How to call -- Import it with `local led_strip = require("led_strip")` -- Call `local strip = led_strip.new(gpio, max_leds)` to create a strip handle -- Call `strip:set_pixel(index, r, g, b)` to set one pixel -- Call `strip:refresh()` to apply changes -- Call `strip:clear()` or `strip:close()` when needed - -## Example -```lua -local led_strip = require("led_strip") - -local strip = led_strip.new(8, 1) -strip:set_pixel(0, 255, 0, 0) -strip:refresh() -``` diff --git a/application/basic_demo/fatfs_image/skills/lua_module_storage.md b/application/basic_demo/fatfs_image/skills/lua_module_storage.md deleted file mode 100644 index ecd9746..0000000 --- a/application/basic_demo/fatfs_image/skills/lua_module_storage.md +++ /dev/null @@ -1,18 +0,0 @@ -# Lua Storage - -This skill describes how to correctly use storage when writing Lua scripts. - -## How to call -- Import it with `local storage = require("storage")` -- Call `storage.mkdir(path)` to create a directory -- Call `storage.write_file(path, content)` to write a file -- Call `storage.read_file(path)` to read a file - -## Example -```lua -local storage = require("storage") - -storage.mkdir("/fatfs/data/demo") -storage.write_file("/fatfs/data/demo/test.txt", "hello") -local text = storage.read_file("/fatfs/data/demo/test.txt") -``` diff --git a/application/basic_demo/fatfs_image/skills/lua_run.md b/application/basic_demo/fatfs_image/skills/lua_run.md deleted file mode 100644 index d9579eb..0000000 --- a/application/basic_demo/fatfs_image/skills/lua_run.md +++ /dev/null @@ -1,69 +0,0 @@ -# Lua Script Execution - -Use this skill when the user wants to see existing Lua scripts, run one, or inspect async execution jobs. - -## Command Rule -- The LLM should call Lua through the direct capability execute entrypoints. -- Use `lua_list_scripts` to inspect scripts. -- Use `lua_run_script` for synchronous execution. -- Use `lua_run_script_async` for long-running or continuous scripts. -- Use `lua_list_async_jobs` and `lua_get_async_job` to inspect async jobs. - -## Running a Script Synchronously -Use `lua_run_script` when the user wants immediate output. -- Required: `path` -- Optional: `args`, `timeout_ms` -- Prefer relative paths such as `hello.lua` - -Examples: -```json -{ - "path": "hello.lua" -} -``` - -```json -{ - "path": "blink.lua", - "args": { - "pin": 2 - }, - "timeout_ms": 3000 -} -``` - -If the script expects structured inputs, pass them through `args`. The runtime exposes them to Lua as the global `args`. - -## Running a Script Asynchronously -Use `lua_run_script_async` for long-running or continuous scripts. -- Required: `path` -- Optional: `args`, `timeout_ms` - -Examples: -```json -{ - "path": "blink.lua" -} -``` - -```json -{ - "path": "blink.lua", - "args": { - "pin": 2 - }, - "timeout_ms": 3000 -} -``` - -After starting an async script: -- Use `lua_list_async_jobs` -- Use `lua_list_async_jobs` with `{"status":"running"}` -- Use `lua_get_async_job` with `{"job_id":""}` - -## Execution Notes -- Paths must resolve under `/spiffs/lua` and end with `.lua`. -- `--timeout-ms` must be a positive integer when provided. -- Prefer synchronous run for short scripts that should finish and return text. -- Prefer async run for loops, animations, watchers, or long-running device behaviors. -- If the user asks to run a script that does not exist yet, switch to the Lua authoring flow first. diff --git a/application/basic_demo/fatfs_image/skills/lua_write.md b/application/basic_demo/fatfs_image/skills/lua_write.md deleted file mode 100644 index 1dd964d..0000000 --- a/application/basic_demo/fatfs_image/skills/lua_write.md +++ /dev/null @@ -1,64 +0,0 @@ -# Lua Script Authoring - -Use this skill when the user wants to write, generate, or modify a managed Lua script for this device. - -## Runtime Constraints -- Managed Lua scripts must stay under `/spiffs/lua`. -- The script path must end with `.lua`. -- Prefer relative paths such as `blink.lua` or `rainbow.lua`; the runtime resolves them under `/spiffs/lua`. -- Use `lua_write_script` to save or overwrite script content. - -## Available Lua Modules -The runtime includes these built-in and application-registered modules: - -### `delay` -- `delay.delay_ms(ms)` -- Use for short blocking delays inside a script. - -### `storage` -- `storage.mkdir(path)` -- `storage.write_file(path, content)` -- `storage.read_file(path)` -- Use only for files the script needs to manage. - -### `gpio` -- `gpio.set_direction(pin, mode)` -- `gpio.set_level(pin, level)` -- `gpio.get_level(pin)` -- Supported modes: `input`, `output`, `input_output`, `output_od`, `input_output_od`, `disable` - -### `led_strip` -- `local strip = led_strip.new(gpio_pin, max_leds)` -- `strip:set_pixel(index, r, g, b)` -- `strip:refresh()` -- `strip:clear()` -- `strip:close()` -- This is for WS2812-style LED strips on a GPIO pin. - -## Writing Guidance -- Write plain Lua script files, not markdown or pseudocode. -- Keep dependencies limited to standard Lua plus the modules listed above. -- Prefer small scripts with a clear entry flow and explicit comments for pin usage. -- If the script touches GPIO or LED hardware, state the pin numbers and expected electrical behavior in comments. -- If a requested peripheral is not covered by `gpio` or `led_strip`, say that the current runtime does not expose that peripheral module. - -## Example Shape -```lua -local gpio = require("gpio") -local delay = require("delay") - -gpio.set_direction(2, "output") - -while true do - gpio.set_level(2, 1) - delay.delay_ms(500) - gpio.set_level(2, 0) - delay.delay_ms(500) -end -``` - -## Save Rule -When the script is ready, call `lua_write_script` with: -- `path`: relative `.lua` path under `/spiffs/lua` -- `content`: full Lua source -- `overwrite`: `true` only when replacing an existing script intentionally diff --git a/application/basic_demo/fatfs_image/skills/qq_send_file.md b/application/basic_demo/fatfs_image/skills/qq_send_file.md deleted file mode 100644 index 6d52b38..0000000 --- a/application/basic_demo/fatfs_image/skills/qq_send_file.md +++ /dev/null @@ -1,55 +0,0 @@ -# QQ File Return - -Use this skill when the user wants the device to send a local file or image back to a QQ chat. - -## When to use -- The user asks to send back a file, attachment, image, photo, log, or generated output through QQ. -- The target conversation is already the active QQ chat, or the user provides an explicit QQ `chat_id`. - -## Available tools -- `list_dir`: inspect device storage and confirm the file path -- `read_file`: inspect small text files before sending when needed -- Direct QQ capabilities: `qq_send_image` and `qq_send_file` - -## Path guidance -- Prefer real local paths already stored on the device. -- Common roots in this demo are `/spiffs`, `/spiffs/qq`, `/spiffs/lua`, or other application-managed storage paths. -- Use `list_dir` first if the exact file path is unknown. -- Use `read_file` only for small text inspection, not for binary payloads. - -## Sending rules -- Use `qq_send_image` for image files such as `.jpg`, `.jpeg`, `.png`, `.gif`, or `.webp`. -- Use `qq_send_file` for non-image files such as `.txt`, `.json`, `.log`, `.csv`, or archives. -- Execute the chosen QQ capability directly. -- Pass `caption` only when the user wants an accompanying message. -- The JSON payload should include an explicit QQ `chat_id`, `path`, and optional `caption`. - -## Examples - -Send an image to a QQ chat: -```json -{ - "chat_id": "group123", - "path": "/spiffs/qq/capture.jpg", - "caption": "Here is the image." -} -``` - -Send a file to a QQ group: -```json -{ - "chat_id": "group1234567890", - "path": "/spiffs/reports/status.json", - "caption": "Latest status report." -} -``` - -## Workflow -1. Confirm the target file exists with `list_dir` if needed. -2. Choose `qq_send_image` or `qq_send_file` based on file type. -3. Execute the QQ capability directly with `chat_id`, `path`, and optional `caption`. -4. Tell the user whether the send succeeded. - -## Notes -- This skill only sends files that already exist on the device filesystem. -- QQ generic file delivery may depend on platform-side enablement. If `qq_send_file` fails, prefer falling back to `qq_send_image` for images or explain that QQ rejected generic file upload. diff --git a/application/basic_demo/fatfs_image/skills/skills_list.json b/application/basic_demo/fatfs_image/skills/skills_list.json deleted file mode 100644 index c9b5478..0000000 --- a/application/basic_demo/fatfs_image/skills/skills_list.json +++ /dev/null @@ -1,103 +0,0 @@ -{ - "skills": [ - { - "id": "cap_im_feishu", - "file": "cap_im_feishu.md", - "title": "cap_im_feishu", - "summary": "How to reply and send text, images, and files through Feishu capabilities.", - "cap_groups": [ - "cap_im_feishu" - ] - }, - { - "id": "cap_im_qq", - "file": "cap_im_qq.md", - "title": "cap_im_qq", - "summary": "Reply in the QQ conversation or send local files back to QQ", - "cap_groups": [ - "cap_im_qq" - ] - }, - { - "id": "cap_im_tg", - "file": "cap_im_tg.md", - "title": "cap_im_tg", - "summary": "How to reply and send text, images, and files through Telegram capabilities.", - "cap_groups": [ - "cap_im_tg" - ] - }, - { - "id": "cap_im_wechat", - "file": "cap_im_wechat.md", - "title": "cap_im_wechat", - "summary": "How to send text and images through WeChat capabilities.", - "cap_groups": [ - "cap_im_wechat" - ] - }, - { - "id": "cap_llm_inspect_image", - "file": "cap_llm_inspect.md", - "title": "cap_llm_inspect_image", - "summary": "How to inspect a local image with inspect_image.", - "cap_groups": [ - "cap_llm_inspect" - ] - }, - { - "id": "cap_lua_run", - "file": "cap_lua_run.md", - "title": "cap_lua_run", - "summary": "This Files describes how to correctly use Lua scripts.", - "cap_groups": [ - "cap_lua" - ] - }, - { - "id": "lua_module_delay", - "file": "lua_module_delay.md", - "title": "lua_module_delay", - "summary": "How to call delay.delay_ms(ms) from Lua after loading the delay module.", - "cap_groups": [ - "cap_lua" - ] - }, - { - "id": "lua_module_event_publisher", - "file": "lua_module_event_publisher.md", - "title": "lua_module_event_publisher", - "summary": "How to publish message, trigger, and custom events from Lua.", - "cap_groups": [ - "cap_lua" - ] - }, - { - "id": "lua_module_gpio", - "file": "lua_module_gpio.md", - "title": "lua_module_gpio", - "summary": "How to set GPIO direction, write level, and read level from Lua.", - "cap_groups": [ - "cap_lua" - ] - }, - { - "id": "lua_module_led_strip", - "file": "lua_module_led_strip.md", - "title": "lua_module_led_strip", - "summary": "How to create and control an LED strip from Lua.", - "cap_groups": [ - "cap_lua" - ] - }, - { - "id": "lua_module_storage", - "file": "lua_module_storage.md", - "title": "lua_module_storage", - "summary": "How to create directories and read or write files from Lua.", - "cap_groups": [ - "cap_lua" - ] - } - ] -} diff --git a/application/basic_demo/main/skills/skills_list.json b/application/basic_demo/main/skills/skills_list.json new file mode 100644 index 0000000..16fee65 --- /dev/null +++ b/application/basic_demo/main/skills/skills_list.json @@ -0,0 +1,13 @@ +{ + "skills": [ + { + "id": "weather_search", + "file": "weather.md", + "title": "weather", + "summary": "How to answer current weather, temperature, and forecast queries through direct web search capabilities.", + "cap_groups": [ + "web_search" + ] + } + ] +} diff --git a/application/basic_demo/fatfs_image/skills/weather.md b/application/basic_demo/main/skills/weather.md similarity index 100% rename from application/basic_demo/fatfs_image/skills/weather.md rename to application/basic_demo/main/skills/weather.md diff --git a/application/basic_demo/tools/sync_component_skills.py b/application/basic_demo/tools/sync_component_skills.py index a28fd6d..4c28109 100755 --- a/application/basic_demo/tools/sync_component_skills.py +++ b/application/basic_demo/tools/sync_component_skills.py @@ -43,9 +43,9 @@ def load_json_file(path: Path) -> object: try: return json.loads(path.read_text(encoding='utf-8')) except FileNotFoundError: - fail(f"Missing JSON file: {path}") + fail(f'Missing JSON file: {path}') except json.JSONDecodeError as exc: - fail(f"Invalid JSON in {path}: {exc}") + fail(f'Invalid JSON in {path}: {exc}') def load_manifest(path: Path) -> dict: @@ -54,7 +54,7 @@ def load_manifest(path: Path) -> dict: data = load_json_file(path) if not isinstance(data, dict): - fail(f"Manifest must be a JSON object: {path}") + fail(f'Manifest must be a JSON object: {path}') return { 'component_entries': list(data.get('component_entries', [])), 'component_files': list(data.get('component_files', [])), @@ -109,9 +109,12 @@ def recover_demo_entries( def load_demo_entries(skills_list_path: Path, manifest: dict, component_entries: list[dict]) -> list[dict]: + if not skills_list_path.exists(): + return [] + data = load_json_file(skills_list_path) if not isinstance(data, dict): - fail(f"{skills_list_path} must be a JSON object.") + fail(f'{skills_list_path} must be a JSON object.') skills = data.get('skills') if not isinstance(skills, list): @@ -140,7 +143,7 @@ def collect_component_skills( data = load_json_file(json_path) if not isinstance(data, dict): - fail(f"{json_path} must be a JSON object.") + fail(f'{json_path} must be a JSON object.') skills = data.get('skills') if not isinstance(skills, list): @@ -161,17 +164,17 @@ def collect_component_skills( if skill_path.parent != skills_dir.resolve(): fail( f"Component '{component_name}' declares skill file outside its skills directory: " - f"{skill_file} ({json_path})" + f'{skill_file} ({json_path})' ) if not skill_path.is_file(): fail( f"Component '{component_name}' references missing skill file '{skill_file}' " - f"in {json_path}" + f'in {json_path}' ) if skill_path.suffix.lower() != '.md': fail( f"Component '{component_name}' declares non-markdown skill file '{skill_file}' " - f"in {json_path}" + f'in {json_path}' ) previous_id = skill_id_sources.get(skill_id) @@ -233,7 +236,7 @@ def merge_entries( for entry in demo_entries: skill_file = entry.get('file') - register(entry, f"demo skills list ({demo_skills_dir / skill_file})") + register(entry, f'demo skills list ({demo_skills_dir / skill_file})') for entry in component_entries: entry_key = (str(entry.get('id')), str(entry.get('file'))) @@ -249,7 +252,7 @@ def validate_demo_markdown_files(demo_entries: list[dict], demo_skills_dir: Path if not skill_path.is_file(): fail( f"Demo skills_list.json references missing skill file '{skill_file}' " - f"at {skill_path}" + f'at {skill_path}' ) @@ -261,6 +264,8 @@ def sync_markdown_files( merged_entries: list[dict], component_entries: list[dict], ) -> None: + demo_skills_dir.mkdir(parents=True, exist_ok=True) + for old_file in manifest.get('component_files', []): if old_file not in copy_map: stale_path = demo_skills_dir / old_file @@ -290,8 +295,6 @@ def sync_markdown_files( def main() -> int: args = parse_args() demo_skills_dir = Path(args.demo_skills_dir).resolve() - if not demo_skills_dir.is_dir(): - fail(f"Demo skills directory does not exist: {demo_skills_dir}") skills_list_path = demo_skills_dir / SKILLS_LIST_FILE manifest_path = Path(args.manifest_path).resolve() @@ -324,5 +327,5 @@ if __name__ == '__main__': try: sys.exit(main()) except SkillSyncError as exc: - print(f"sync_component_skills.py: error: {exc}", file=sys.stderr) + print(f'sync_component_skills.py: error: {exc}', file=sys.stderr) sys.exit(1)