@coze-arch/cli 0.0.19-beta.1 → 0.0.20-alpha.d2b336

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/lib/__templates__/nuxt-vue/app/pages/index.vue +6 -0
  2. package/lib/__templates__/nuxt-vue/nuxt.config.ts +2 -2
  3. package/lib/__templates__/pi-agent/AGENTS.md +7 -2
  4. package/lib/__templates__/pi-agent/README.md +2 -0
  5. package/lib/__templates__/pi-agent/docs/project-overview.md +9 -15
  6. package/lib/__templates__/pi-agent/docs/user/getting-started.md +3 -4
  7. package/lib/__templates__/pi-agent/pi-resources/skills/coze-asr/SKILL.md +4 -10
  8. package/lib/__templates__/pi-agent/pi-resources/skills/coze-image-gen/SKILL.md +6 -18
  9. package/lib/__templates__/pi-agent/pi-resources/skills/coze-tts/SKILL.md +9 -37
  10. package/lib/__templates__/pi-agent/pi-resources/skills/coze-video-gen/SKILL.md +17 -30
  11. package/lib/__templates__/pi-agent/src/config.ts +60 -19
  12. package/lib/__templates__/pi-agent/src/core.ts +1 -0
  13. package/lib/__templates__/pi-agent/src/dashboard/index.ts +39 -4
  14. package/lib/__templates__/pi-agent/src/dashboard/server.ts +0 -12
  15. package/lib/__templates__/pi-agent/src/dashboard/web/src/components/app-layout.tsx +1 -15
  16. package/lib/__templates__/pi-agent/src/dashboard/web/src/main.tsx +0 -6
  17. package/lib/__templates__/pi-agent/src/dashboard/web/src/pages/chat-page.tsx +0 -11
  18. package/lib/__templates__/pi-agent/src/dashboard/web/src/pages/overview-page.tsx +268 -72
  19. package/lib/__templates__/pi-agent/src/dashboard/web/src/styles.css +0 -91
  20. package/lib/__templates__/pi-agent/tests/config.test.ts +63 -1
  21. package/lib/cli.js +814 -89
  22. package/package.json +1 -1
  23. package/lib/__templates__/pi-agent/pi-resources/skills/coze-asr/scripts/asr.mjs +0 -9
  24. package/lib/__templates__/pi-agent/pi-resources/skills/coze-image-gen/scripts/gen.mjs +0 -9
  25. package/lib/__templates__/pi-agent/pi-resources/skills/coze-tts/scripts/tts.mjs +0 -9
  26. package/lib/__templates__/pi-agent/pi-resources/skills/coze-video-gen/scripts/gen.mjs +0 -9
  27. package/lib/__templates__/pi-agent/src/dashboard/api/docs.ts +0 -204
  28. package/lib/__templates__/pi-agent/src/dashboard/web/src/pages/channels-page.tsx +0 -188
  29. package/lib/__templates__/pi-agent/src/dashboard/web/src/pages/docs-page.tsx +0 -65
  30. package/lib/__templates__/pi-agent/src/dashboard/web/src/pages/models-page.tsx +0 -122
  31. package/lib/__templates__/pi-agent/tests/dashboard-docs-api.test.ts +0 -125
@@ -1,3 +1,9 @@
1
+ <script setup lang="ts">
2
+ // 显式声明多词组件名,否则 index.vue 会命中 vue/multi-word-component-names,导致 lint 报错。
3
+ defineOptions({
4
+ name: 'LandingPage',
5
+ });
6
+ </script>
1
7
  <template>
2
8
  <div class="flex min-h-screen items-center justify-center">
3
9
  <main class="flex w-full max-w-3xl flex-col items-center justify-center px-16 py-32">
@@ -9,7 +9,8 @@ export default defineNuxtConfig({
9
9
  compatibilityDate: '2025-07-15',
10
10
  // Disable devtools in CI/test environments (prevents hanging in headless mode)
11
11
  devtools: {
12
- enabled: process.env.CI !== 'true' && process.env.COZE_PROJECT_ENV !== 'PROD',
12
+ enabled:
13
+ process.env.CI !== 'true' && process.env.COZE_PROJECT_ENV !== 'PROD',
13
14
  },
14
15
  telemetry: false,
15
16
 
@@ -79,7 +80,6 @@ export default defineNuxtConfig({
79
80
  // Vite configuration (similar to Next.js allowedDevOrigins)
80
81
  vite: {
81
82
  server: {
82
- host: '0.0.0.0',
83
83
  cors: {
84
84
  origin: ['*.dev.coze.site'],
85
85
  credentials: true,
@@ -93,9 +93,14 @@
93
93
  - 新增 skill:
94
94
  - `pi-resources/skills/<skill-name>/SKILL.md`
95
95
  - 必要的 `scripts/*`
96
- - 用户要求新建 Markdown 文档、方案、总结、设计稿等 `.md` 文件:
96
+ - 用户运行时要求产出 Markdown 文档、方案、总结、设计稿等 `.md` 文件:
97
97
  - 默认放在 `cwd`
98
- - 不要默认放进 `src/` 或其他源码目录
98
+ - 只有当用户明确指定路径时,才放到对应位置
99
+ - 二次开发过程中新增给开发者看的 Markdown 文档,例如功能使用说明、代码上下文说明、设计约束、排障手册:
100
+ - 默认放在 `docs/` 下,按内容选择合适的子目录
101
+ - 文件名使用小写 kebab-case,不要使用大写字母命名
102
+ - 如果该文档会成为后续开发过程中的长期参考资料,同步更新 `docs/project-overview.md`,写明推荐阅读时机
103
+ - 不要默认放进 repo 根目录、`src/` 或其他源码目录
99
104
  - 新增 extension / runtime tool:
100
105
  - `pi-resources/extensions/<extension-name>/index.ts`
101
106
  - 或 `pi-resources/extensions/*.ts`
@@ -49,6 +49,8 @@ npm run dev
49
49
  `npm run dev` 会先按顺序加载 `.env` 和 `.env.local`,然后启动 `src/index.ts`。
50
50
  默认会使用 `pi` runtime;如果你只是想走本地 mock 链路,可以额外设置 `PI_BOT_AGENT_MODE=mock`。
51
51
 
52
+ 如果默认的 `<%= workspaceDir %>/config.json` 不存在,启动时会输出 warning,并自动回退到最小 mock 配置;此时默认会以 `mock` runtime 运行。
53
+
52
54
  ## 用户文档
53
55
 
54
56
  启动后,可以在 Dashboard 的 `Docs` 页面查看当前项目的用户指引,默认地址是:
@@ -52,7 +52,6 @@
52
52
  │ │ ├── config-store.ts
53
53
  │ │ ├── api
54
54
  │ │ │ ├── channels.ts
55
- │ │ │ ├── docs.ts
56
55
  │ │ │ ├── models.ts
57
56
  │ │ │ └── overview.ts
58
57
  │ │ ├── web
@@ -131,8 +130,7 @@
131
130
  - `src/channels/wechat`
132
131
  - 微信消息标准化和回复发送
133
132
  - `src/dashboard/*`
134
- - 本地 Dashboard(HTTP + WebSocket),用于查看运行状态、编辑配置、以及以 UI 方式调试聊天会话
135
- - 同时提供 `Docs` 页面,直接展示项目内的快速开始文档
133
+ - 本地 Dashboard(HTTP + WebSocket),用于查看运行状态、编辑配置(默认模型、飞书渠道)、以及以 UI 方式调试聊天会话
136
134
  - 开发态通过 Vite middleware 提供前端资源;生产态直接托管 `src/dashboard/web/dist`
137
135
  - `src/dashboard/config-store.ts`
138
136
  - Dashboard 配置存储抽象
@@ -153,8 +151,6 @@
153
151
  - `coze_web_fetch` 工具单测:覆盖 text/markdown/json 格式渲染、textOnly 模式、链接过滤、图片尺寸、并发抓取、异常处理
154
152
  - `tests/web-search.test.ts`
155
153
  - `coze_web_search` 工具单测:覆盖基本搜索、摘要、内容包含、图片搜索、路由判断、默认参数、空结果、异常处理
156
- - `tests/dashboard-docs-api.test.ts`
157
- - Dashboard docs API 测试
158
154
  - `tests/dashboard-models-api.test.ts`
159
155
  - Dashboard models API 测试
160
156
  - `tests/feishu-channel.test.ts`
@@ -204,18 +200,16 @@ Dashboard 是一个「和 Bot 同进程」启动的本地 HTTP 服务,默认
204
200
 
205
201
  前端路由位于 `src/dashboard/web/src/main.tsx`,当前页面:
206
202
 
207
- - `/overview`:运行状态与关键路径(workspace/agent dir 等)
208
- - `/docs`:项目快速开始文档
209
- - `/models`:切换默认模型
210
- - `/channels`:编辑渠道配置
203
+ - `/overview`:系统摘要(运行状态、启用渠道)、默认模型切换、飞书渠道配置
211
204
  - `/chat`:调试聊天会话(含历史、reset、WebSocket 流式)
212
205
 
206
+ 导航栏仅包含「聊天」和「概览」两个入口,md 断点及以上直接展示带文字标签的侧边栏。
207
+
213
208
  ### 3.3 HTTP API(服务端)
214
209
 
215
210
  当前主要接口(均在同一进程内,不做鉴权):
216
211
 
217
- - `GET /api/overview`:运行状态/路径/启用渠道等
218
- - `GET /api/docs`:读取 `docs/user/` 下的用户文档并返回当前文档内容
212
+ - `GET /api/overview`:运行状态/启用渠道等
219
213
  - `GET /api/models`:通过 `ConfigStore` 读取配置并返回默认模型与可选模型列表(用于下拉选择)
220
214
  - `POST /api/models`:仅写回默认模型(请求体只包含 `defaultModel`;服务端会基于当前配置扫描列表做校验)
221
215
  - `GET /api/channels`:通过 `ConfigStore` 读取配置并返回可编辑结构
@@ -230,13 +224,13 @@ Dashboard 是一个「和 Bot 同进程」启动的本地 HTTP 服务,默认
230
224
  - `createBotApp(..., { dashboardConfigStore })` 可注入自定义存储实现
231
225
  - `tests/smoke/run-smoke.ts` 当前使用内存型 `ConfigStore`,直接验证 dashboard 配置的读写 API 行为
232
226
 
233
- ### 3.4 模型配置页能力边界
227
+ ### 3.4 模型配置能力边界
234
228
 
235
- 当前 `/models` 页面的目标,是以 UI 方式快速切换默认模型,降低直接手改 JSON 的成本。当前页面支持:
229
+ 概览页面中的「默认模型」区域,以 UI 方式快速切换默认模型,降低直接手改 JSON 的成本。当前支持:
236
230
 
237
231
  - 修改默认模型(写回 `agents.defaults.model.primary`)
238
232
 
239
- 当前页面不支持:
233
+ 当前不支持:
240
234
 
241
235
  - 编辑 Provider 配置
242
236
  - 编辑模型参数
@@ -369,6 +363,6 @@ npm run dashboard:build
369
363
  - `docs/project-overview.md`
370
364
  - 面向维护者的架构介绍
371
365
  - `docs/user/getting-started.md`
372
- - 面向项目使用者的快速开始文档,Dashboard 的 `Docs` 页面会直接读取并展示
366
+ - 面向项目使用者的快速开始文档
373
367
 
374
368
  最贴近现状的介绍文档是这份 `docs/project-overview.md`。如果其他文档与当前目录结构冲突,应以当前源码、`README.md` 和本文件为准。
@@ -9,11 +9,10 @@ title: 快速开始
9
9
 
10
10
  ## 接入飞书机器人
11
11
 
12
- 1. 打开 [渠道](/channels) 页面。
12
+ 1. 打开 [概览](/overview) 页面的「飞书配置」区域。
13
13
  2. 填写 `App ID` 和 `App Secret`。
14
- 3. 按需填写 `domain`、`encryptKey`、`verificationToken`。
15
- 4. 点击保存。
16
- 5. 重启应用让配置生效。
14
+ 3. 点击保存。
15
+ 4. 重启应用让配置生效。
17
16
 
18
17
  ### 飞书机器人配置
19
18
 
@@ -10,14 +10,15 @@ Transcribe audio from a URL or local file using Coze ASR.
10
10
  ## Quick start
11
11
 
12
12
  ```bash
13
- node {skillDir}/scripts/asr.mjs --url "https://example.com/audio.mp3"
14
- node {skillDir}/scripts/asr.mjs --file ./recording.mp3
13
+ npx coze-coding-ai asr --url "https://example.com/audio.mp3"
14
+ npx coze-coding-ai asr --file ./recording.mp3
15
15
  ```
16
16
 
17
17
  ## Options
18
18
 
19
19
  - `--url <url>`, `-u <url>` remote audio URL
20
- - `--file <path>`, `-f <path>` local audio file
20
+ - `--file <path>`, `-f <path>` local audio file path (will be base64 encoded)
21
+ - `--header <key:value>`, `-H <key:value>` custom HTTP header; repeatable
21
22
 
22
23
  ## Behavior
23
24
 
@@ -27,10 +28,3 @@ node {skillDir}/scripts/asr.mjs --file ./recording.mp3
27
28
  - Supported audio formats follow the SDK/API capability: WAV, MP3, OGG Opus, M4A.
28
29
  - Recommended limits from the SDK docs: duration up to 2 hours, size up to 100MB.
29
30
  - The CLI prints recognized `text`, and may also print `duration` and `segments`.
30
- - The CLI does not print full `utterances` details or raw response payload.
31
- - This skill does not expose custom headers such as `--header`, `-H`, or mock mode.
32
-
33
- ## Notes
34
-
35
- - `{skillDir}` means the directory containing this `SKILL.md`.
36
- - Local files are read and uploaded as base64 audio content.
@@ -7,35 +7,23 @@ description: Generate one or more images from text prompts using Coze image gene
7
7
 
8
8
  Generate one or more images from a prompt using Coze.
9
9
 
10
- This skill runs as a Node CLI wrapper around the backend SDK. Do not use the SDK from client-side code.
11
-
12
10
  ## Quick start
13
11
 
14
12
  ```bash
15
- node {skillDir}/scripts/gen.mjs --prompt "A futuristic city at sunset"
16
- node {skillDir}/scripts/gen.mjs --prompt "A serene mountain landscape" --count 2 --size 4K
17
- node {skillDir}/scripts/gen.mjs --prompt "A hero's journey through magical lands" --sequential --max-sequential 5
18
- node {skillDir}/scripts/gen.mjs --prompt "Transform into anime style" --image "https://example.com/input.jpg"
19
- node {skillDir}/scripts/gen.mjs --prompt "A modern office workspace" --response-format url
13
+ npx coze-coding-ai image --prompt "A futuristic city at sunset"
14
+ npx coze-coding-ai image --prompt "A serene mountain landscape" --size 4K
15
+ npx coze-coding-ai image --prompt "Transform into anime style" --size 2K
20
16
  ```
21
17
 
22
18
  ## Options
23
19
 
24
- - `--prompt <text>` required prompt text
25
- - `--count <n>` number of independent generation requests, default `1`
20
+ - `--prompt <text>`, `-p <text>` required prompt text
26
21
  - `--size <size>` image size: `2K`, `4K`, or `WIDTHxHEIGHT`, default `2K`
27
- - `--image <url>` reference image URL; repeat the flag to pass multiple images
28
- - `--response-format <format>` only supports `url`
29
- - `--watermark <true|false>` whether to keep watermark
30
- - `--optimize-prompt-mode <mode>` prompt optimization mode passed through to the SDK
31
- - `--sequential` enable sequential image generation
32
- - `--max-sequential <n>` max sequential frames, default `15`
33
- - `--header <key:value>` custom HTTP header; repeatable, alias `-H`
22
+ - `--output <path>`, `-o <path>` output file path (optional)
23
+ - `--header <key:value>`, `-H <key:value>` custom HTTP header; repeatable
34
24
 
35
25
  ## Notes
36
26
 
37
- - `{skillDir}` means the directory containing this `SKILL.md`.
38
27
  - Successful runs print generated URLs directly.
39
28
  - Printed image URLs must be kept exactly intact, complete, and accurate. All URL parameters must be preserved without truncation, rewriting, omission, or reordering; in particular, parameters inside the query string such as `sign` must not be dropped, otherwise the image may be inaccessible.
40
29
  - Unless the user explicitly asks to download the URL content, only return the complete URL link to the user.
41
- - This skill does not expose base64 output.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: coze-tts
3
- description: Convert text to speech using Coze TTS. Use when you need to synthesize spoken audio from one text input or multiple text segments, optionally with a specific speaker, format, sample rate, or speech settings.
3
+ description: Convert text to speech using Coze TTS. Use when you need to synthesize spoken audio from text input, optionally with a specific speaker voice.
4
4
  ---
5
5
 
6
6
  # Coze TTS
@@ -10,43 +10,15 @@ Generate speech audio URLs from text using Coze TTS.
10
10
  ## Quick start
11
11
 
12
12
  ```bash
13
- node {skillDir}/scripts/tts.mjs --text "Hello, welcome to our service"
14
- node {skillDir}/scripts/tts.mjs --texts "Chapter 1" "Chapter 2" --speaker zh_male_m191_uranus_bigtts
15
- node {skillDir}/scripts/tts.mjs --text "Fast announcement" --speech-rate 30 --format mp3 --sample-rate 48000
13
+ npx coze-coding-ai tts --text "Hello, welcome to our service"
14
+ npx coze-coding-ai tts --text "你好,欢迎使用我们的服务" --speaker zh_male_m191_uranus_bigtts
16
15
  ```
17
16
 
18
17
  ## Options
19
18
 
20
- - `--text <text>` single text input. If both `--text` and `--texts` are provided, `--text` takes precedence.
21
- - `--texts <texts...>` multiple text inputs. Values are read until the next `--flag`.
22
- - `--speaker <id>` speaker id, default `zh_female_xiaohe_uranus_bigtts`
23
- - `--format <fmt>` audio format: `mp3`, `pcm`, or `ogg_opus`. Default is SDK default (`mp3`).
24
- - `--sample-rate <hz>` sample rate. Supported values: `8000`, `16000`, `22050`, `24000`, `32000`, `44100`, `48000`. Default is SDK default (`24000`).
25
- - `--speech-rate <n>` speech rate adjustment, range `-50` to `100`, default `0`
26
- - `--loudness-rate <n>` loudness adjustment, range `-50` to `100`, default `0`
27
-
28
- ## Behavior
29
-
30
- - At least one of `--text` or `--texts` is required.
31
- - This skill currently supports plain text input only. It does not expose `ssml`, `--header`, `-H`, or `--mock`.
32
- - The CLI prints one audio URL per generated segment. It does not download audio files locally.
33
- - Printed audio URLs must be kept exactly intact, complete, and accurate. All URL parameters must be preserved without truncation, rewriting, omission, or reordering; in particular, parameters inside the query string such as `sign` must not be dropped, otherwise the audio may be inaccessible.
34
- - Unless the user explicitly asks to download the URL content, only return the complete URL link to the user.
35
- - The CLI does not print `audioSize`, even though the underlying SDK returns it.
36
- - Invalid ranges or unsupported values are passed through to the SDK and may fail there.
37
-
38
- ## Sample Rates
39
-
40
- Supported: `8000`, `16000`, `22050`, `24000`, `32000`, `44100`, `48000` Hz
41
-
42
- - `8000-16000`: Phone quality
43
- - `22050-24000`: Standard quality (default)
44
- - `32000-48000`: High quality
45
-
46
- ## Tuning
47
-
48
- - `speechRate`: range `-50` to `100`, default `0`. Negative values slow speech down, positive values speed it up.
49
- - `loudnessRate`: range `-50` to `100`, default `0`. Negative values make output quieter, positive values make it louder.
19
+ - `--text <text>`, `-t <text>` text to convert to speech (required)
20
+ - `--speaker <id>` speaker voice id, default `zh_female_xiaohe_uranus_bigtts`
21
+ - `--header <key:value>`, `-H <key:value>` custom HTTP header; repeatable
50
22
 
51
23
  ## Voices
52
24
 
@@ -80,6 +52,6 @@ Supported: `8000`, `16000`, `22050`, `24000`, `32000`, `44100`, `48000` Hz
80
52
 
81
53
  ## Notes
82
54
 
83
- - `{skillDir}` means the directory containing this `SKILL.md`.
84
- - The script prints one audio URL per generated segment.
85
- - The returned URL must be used as-is, in full, and with every parameter preserved exactly, especially query parameters such as `sign`, otherwise the audio may not be accessible.
55
+ - The CLI prints one audio URL per generated segment. It does not download audio files locally.
56
+ - Printed audio URLs must be kept exactly intact, complete, and accurate. All URL parameters must be preserved without truncation, rewriting, omission, or reordering; in particular, parameters inside the query string such as `sign` must not be dropped, otherwise the audio may be inaccessible.
57
+ - Unless the user explicitly asks to download the URL content, only return the complete URL link to the user.
@@ -7,47 +7,34 @@ description: Generate a video from text prompts and/or image inputs using Coze v
7
7
 
8
8
  Generate a video URL from text and image inputs using Coze.
9
9
 
10
- This skill runs as a Node CLI wrapper around the backend SDK. Do not use the SDK from client-side code.
11
-
12
10
  ## Quick start
13
11
 
14
12
  ```bash
15
- node {skillDir}/scripts/gen.mjs --prompt "A serene mountain landscape with flowing clouds"
16
- node {skillDir}/scripts/gen.mjs --prompt "A cinematic robot walking through neon rain" --duration 6 --ratio 9:16 --resolution 1080p
17
- node {skillDir}/scripts/gen.mjs --prompt "Animate this concept art" --first-frame "https://example.com/first.png"
18
- node {skillDir}/scripts/gen.mjs --prompt "Transition from sunrise to night" --first-frame "https://example.com/start.png" --last-frame "https://example.com/end.png" --return-last-frame true
13
+ npx coze-coding-ai video --prompt "A serene mountain landscape with flowing clouds"
14
+ npx coze-coding-ai video --prompt "A cinematic robot walking through neon rain" --duration 6 --size 1080x1920
15
+ npx coze-coding-ai video --prompt "Animate this concept art" --image-url "https://example.com/first.png"
16
+ npx coze-coding-ai video --prompt "Transition from sunrise to night" --image-url "https://example.com/start.png,https://example.com/end.png" --return-last-frame
19
17
  ```
20
18
 
21
19
  ## Options
22
20
 
23
- - `--prompt <text>` text prompt
24
- - `--image <url>` reference image URL; repeat the flag to pass multiple images
25
- - `--first-frame <url>` first frame image URL
26
- - `--last-frame <url>` last frame image URL
27
- - `--model <id>` model id, default SDK model is `doubao-seedance-1-5-pro-251215`
28
- - `--duration <seconds>` video duration in seconds
29
- - `--ratio <ratio>` one of `16:9`, `9:16`, `1:1`, `4:3`, `3:4`, `21:9`, `adaptive`
30
- - `--resolution <value>` one of `480p`, `720p`, `1080p`
31
- - `--watermark <true|false>` whether to keep watermark
32
- - `--seed <n>` fixed random seed for reproducibility
33
- - `--camera-fixed <true|false>` whether to fix the camera
34
- - `--generate-audio <true|false>` whether to generate synced audio
35
- - `--return-last-frame <true|false>` whether to return the last-frame image URL
36
- - `--max-wait-time <seconds>` max synchronous wait time
37
- - `--callback-url <url>` async callback URL passed through to the SDK
38
- - `--header <key:value>` custom HTTP header; repeatable, alias `-H`
21
+ - `--prompt <text>`, `-p <text>` text prompt
22
+ - `--image-url <url>`, `-i <url>` image URL (single or comma-separated two URLs for first/last frame)
23
+ - `--size <size>`, `-s <size>` video resolution (e.g., `1920x1080`)
24
+ - `--duration <seconds>`, `-d <seconds>` video duration in seconds (`5`-`10`), default `5`
25
+ - `--model <model>`, `-m <model>` model name, default `doubao-seedance-1-0-pro-fast-251015`
26
+ - `--callback-url <url>` async callback URL
27
+ - `--return-last-frame` return last frame image URL
28
+ - `--watermark` add watermark
29
+ - `--seed <number>` fixed random seed for reproducibility
30
+ - `--camerafixed` fix the camera
31
+ - `--output <path>`, `-o <path>` output file path (JSON)
32
+ - `--header <key:value>`, `-H <key:value>` custom HTTP header; repeatable
39
33
 
40
34
  ## Behavior
41
35
 
42
- - At least one of `--prompt`, `--image`, `--first-frame`, or `--last-frame` is required.
36
+ - At least one of `--prompt` or `--image-url` is required.
43
37
  - Successful runs print `Task ID`, `Status`, `Video URL`, and optionally `Last Frame URL`.
44
38
  - The CLI does not download video files locally.
45
39
  - Printed video URLs and frame URLs must be kept exactly intact, complete, and accurate. All URL parameters must be preserved without truncation, rewriting, omission, or reordering; in particular, parameters inside the query string such as `sign` must not be dropped, otherwise the asset may be inaccessible.
46
40
  - Unless the user explicitly asks to download the URL content, only return the complete URL link to the user.
47
-
48
- ## Notes
49
-
50
- - `{skillDir}` means the directory containing this `SKILL.md`.
51
- - The default model `doubao-seedance-1-5-pro-251215` supports text input plus `first_frame` and `last_frame`. Generic `reference_image` inputs from `--image` may be rejected by that model.
52
- - Only use `--image` when you have selected a model that explicitly supports `reference_image`.
53
- - The returned video URL is already hosted with a valid expiration period. Unless the user explicitly needs rehosting or download, use it directly.
@@ -93,6 +93,7 @@ export interface LoadedConfig {
93
93
  path: string;
94
94
  directory: string;
95
95
  workspaceDir: string;
96
+ source: "file" | "fallback-mock";
96
97
  thinkingLevel?: ThinkingLevel;
97
98
  config: Config;
98
99
  providers: Record<string, ProviderConfig>;
@@ -127,6 +128,56 @@ const DEFAULT_APP_NAME = "starter-bot";
127
128
  const DEFAULT_CONFIG_FILENAME = "config.json";
128
129
  const MODULE_DIR = dirname(fileURLToPath(import.meta.url));
129
130
 
131
+ function createMockConfig(): Config {
132
+ return {
133
+ agents: {
134
+ defaults: {
135
+ workspace: ".",
136
+ model: {
137
+ primary: "openai/gpt-5-mini"
138
+ }
139
+ }
140
+ },
141
+ channels: {
142
+ feishu: {
143
+ enabled: false,
144
+ requireMention: true,
145
+ thinkingReaction: {
146
+ enabled: true,
147
+ emojiType: "OneSecond"
148
+ }
149
+ },
150
+ wechat: {
151
+ enabled: false,
152
+ requireMention: false
153
+ }
154
+ }
155
+ };
156
+ }
157
+
158
+ function createLoadedConfig(
159
+ configPath: string,
160
+ parsed: Config,
161
+ source: LoadedConfig["source"]
162
+ ): LoadedConfig {
163
+ const directory = dirname(configPath);
164
+ const workspaceDir = resolve(directory, parsed.agents?.defaults?.workspace ?? ".");
165
+ const defaultModelReference = parsed.agents?.defaults?.model?.primary;
166
+
167
+ return {
168
+ path: configPath,
169
+ directory,
170
+ workspaceDir,
171
+ source,
172
+ thinkingLevel: parsed.agents?.defaults?.thinkingLevel,
173
+ config: parsed,
174
+ providers: parsed.models?.providers ?? {},
175
+ defaultModel: defaultModelReference
176
+ ? parseModelReference(defaultModelReference, "agents.defaults.model.primary")
177
+ : undefined
178
+ };
179
+ }
180
+
130
181
  export function parseModelReference(reference: string, description = "model reference"): ModelReference {
131
182
  const normalized = reference.trim();
132
183
  const splitIndex = normalized.indexOf("/");
@@ -145,7 +196,8 @@ export function parseModelReference(reference: string, description = "model refe
145
196
 
146
197
  export function loadConfig(configPath: string): LoadedConfig {
147
198
  if (!existsSync(configPath)) {
148
- throw new Error(`Config not found: ${configPath}`);
199
+ console.warn(`[pi-bot] Config not found: ${configPath}. Falling back to mock config.`);
200
+ return createLoadedConfig(configPath, createMockConfig(), "fallback-mock");
149
201
  }
150
202
 
151
203
  let parsed: Config;
@@ -160,25 +212,11 @@ export function loadConfig(configPath: string): LoadedConfig {
160
212
  );
161
213
  }
162
214
 
163
- const directory = dirname(configPath);
164
- const workspaceDir = resolve(directory, parsed.agents?.defaults?.workspace ?? ".");
165
- const defaultModelReference = parsed.agents?.defaults?.model?.primary;
166
-
167
- return {
168
- path: configPath,
169
- directory,
170
- workspaceDir,
171
- thinkingLevel: parsed.agents?.defaults?.thinkingLevel,
172
- config: parsed,
173
- providers: parsed.models?.providers ?? {},
174
- defaultModel: defaultModelReference
175
- ? parseModelReference(defaultModelReference, "agents.defaults.model.primary")
176
- : undefined
177
- };
215
+ return createLoadedConfig(configPath, parsed, "file");
178
216
  }
179
217
 
180
218
  export function loadOptionalConfig(configPath: string | undefined): LoadedConfig | undefined {
181
- if (!configPath || !existsSync(configPath)) {
219
+ if (!configPath) {
182
220
  return undefined;
183
221
  }
184
222
 
@@ -261,11 +299,14 @@ export function loadBotAppConfig(
261
299
 
262
300
  return {
263
301
  appName: DEFAULT_APP_NAME,
302
+ configRoot: loadedConfig.config as Record<string, unknown>,
264
303
  agent: {
265
- mode: (env.PI_BOT_AGENT_MODE as BotAppConfig["agent"]["mode"] | undefined) ?? "pi",
304
+ mode:
305
+ (env.PI_BOT_AGENT_MODE as BotAppConfig["agent"]["mode"] | undefined) ??
306
+ (loadedConfig.source === "fallback-mock" ? "mock" : "pi"),
266
307
  provider: defaultModel?.provider ?? "openai",
267
308
  model: defaultModel?.modelId ?? "gpt-5-mini",
268
- configPath,
309
+ configPath: loadedConfig.source === "file" ? configPath : undefined,
269
310
  thinkingLevel: loadedConfig.thinkingLevel,
270
311
  cwd: workspaceDir,
271
312
  agentDir: workspaceDir
@@ -108,6 +108,7 @@ export interface BotRoutingConfig {
108
108
 
109
109
  export interface BotAppConfig {
110
110
  appName: string;
111
+ configRoot?: Record<string, unknown>;
111
112
  agent: AgentRuntimeConfig;
112
113
  routing: BotRoutingConfig;
113
114
  channels: {
@@ -4,9 +4,47 @@ import type { DashboardServer } from "./types.js";
4
4
  import type { PiAgentRuntime } from "../agent.js";
5
5
  import {
6
6
  createFileConfigStore,
7
+ createMemoryConfigStore,
7
8
  type ConfigStore,
8
9
  } from "./config-store.js";
9
10
 
11
+ function createFallbackConfigRoot(botConfig: BotAppConfig): Record<string, unknown> {
12
+ return {
13
+ agents: {
14
+ defaults: {
15
+ model: {
16
+ primary:
17
+ botConfig.agent.provider && botConfig.agent.model
18
+ ? `${botConfig.agent.provider}/${botConfig.agent.model}`
19
+ : ""
20
+ }
21
+ }
22
+ },
23
+ models: {
24
+ providers: {}
25
+ },
26
+ channels: {
27
+ feishu: {
28
+ enabled: botConfig.channels.feishu?.enabled ?? false,
29
+ requireMention: botConfig.routing.feishuGroupRequireMention,
30
+ appId: botConfig.channels.feishu?.appId,
31
+ appSecret: botConfig.channels.feishu?.appSecret,
32
+ domain: botConfig.channels.feishu?.domain,
33
+ encryptKey: botConfig.channels.feishu?.encryptKey,
34
+ verificationToken: botConfig.channels.feishu?.verificationToken,
35
+ thinkingReaction: {
36
+ enabled: botConfig.channels.feishu?.thinkingReaction?.enabled ?? true,
37
+ emojiType: botConfig.channels.feishu?.thinkingReaction?.emojiType
38
+ }
39
+ },
40
+ wechat: {
41
+ enabled: botConfig.channels.wechat?.enabled ?? false,
42
+ requireMention: botConfig.routing.wechatGroupRequireMention
43
+ }
44
+ }
45
+ };
46
+ }
47
+
10
48
  export function createDashboard(args: {
11
49
  botConfig: BotAppConfig;
12
50
  channels: { feishu?: unknown; wechat?: unknown };
@@ -17,10 +55,7 @@ export function createDashboard(args: {
17
55
  args.configStore ??
18
56
  (args.botConfig.agent.configPath
19
57
  ? createFileConfigStore(args.botConfig.agent.configPath)
20
- : undefined);
21
- if (!configStore) {
22
- throw new Error("Missing botConfig.agent.configPath for dashboard.");
23
- }
58
+ : createMemoryConfigStore(args.botConfig.configRoot ?? createFallbackConfigRoot(args.botConfig)));
24
59
 
25
60
  return createDashboardServer({
26
61
  runtime: {
@@ -6,7 +6,6 @@ import express from "express";
6
6
  import { createServer as createViteServer, type ViteDevServer } from "vite";
7
7
  import { WebSocketServer, type RawData, type WebSocket } from "ws";
8
8
  import type { DashboardServer, DashboardServerOptions } from "./types.js";
9
- import { readDocsResponse } from "./api/docs.js";
10
9
  import { buildOverviewResponse } from "./api/overview.js";
11
10
  import { readChannelsResponse, saveChannelsRequest } from "./api/channels.js";
12
11
  import { ValidationError, readModelsResponse, saveModelsRequest } from "./api/models.js";
@@ -34,8 +33,6 @@ function readHost(explicitHost: string | undefined): string {
34
33
  }
35
34
 
36
35
  const DASHBOARD_DIR = dirname(fileURLToPath(import.meta.url));
37
- const PROJECT_ROOT = resolve(DASHBOARD_DIR, "..", "..");
38
- const USER_DOCS_DIR = resolve(PROJECT_ROOT, "docs", "user");
39
36
  const WEB_ROOT = resolve(DASHBOARD_DIR, "web");
40
37
  const WEB_DIST = resolve(WEB_ROOT, "dist");
41
38
 
@@ -229,15 +226,6 @@ export function createDashboardServer(options: DashboardServerOptions): Dashboar
229
226
  }
230
227
  });
231
228
 
232
- app.get("/api/docs", (req, res) => {
233
- try {
234
- const slug = typeof req.query.slug === "string" ? req.query.slug : undefined;
235
- res.json(readDocsResponse({ docsDir: USER_DOCS_DIR, slug }));
236
- } catch (err) {
237
- res.status(500).json({ ok: false, error: String(err) });
238
- }
239
- });
240
-
241
229
  app.get("/api/chat/sessions", (_req, res) => {
242
230
  try {
243
231
  const sessions = options.agentRuntime.listSessionKeys();
@@ -1,12 +1,9 @@
1
1
  import React from "react";
2
2
  import {
3
- BookOpenText as DocsIcon,
4
- Cpu as CpuIcon,
5
3
  LayoutDashboard as OverviewIcon,
6
4
  Menu as MenuIcon,
7
5
  MessageSquare as MessageIcon,
8
6
  Moon as MoonIcon,
9
- Settings as SettingsIcon,
10
7
  Sun as SunIcon,
11
8
  } from "lucide-react";
12
9
  import { NavLink, useLocation } from "react-router-dom";
@@ -18,9 +15,6 @@ import { useLocalStorageState } from "../hooks/use-local-storage-state";
18
15
  const navItems = [
19
16
  { to: "/chat", label: "聊天", icon: MessageIcon },
20
17
  { to: "/overview", label: "概览", icon: OverviewIcon },
21
- { to: "/docs", label: "文档", icon: DocsIcon },
22
- { to: "/models", label: "模型", icon: CpuIcon },
23
- { to: "/channels", label: "渠道", icon: SettingsIcon },
24
18
  ];
25
19
 
26
20
  export function AppLayout(props: { children: React.ReactNode }) {
@@ -132,15 +126,7 @@ export function AppLayout(props: { children: React.ReactNode }) {
132
126
  ) : null}
133
127
 
134
128
  <div className="flex min-h-0 flex-1 items-stretch">
135
- <aside className="hidden shrink-0 p-2 md:block xl:hidden">
136
- <nav className="grid gap-1">
137
- {navItems.map((item) => (
138
- <NavItem key={item.to} item={item} compact={true} />
139
- ))}
140
- </nav>
141
- </aside>
142
-
143
- <aside className="hidden shrink-0 p-3 xl:block">
129
+ <aside className="hidden shrink-0 p-3 md:block">
144
130
  <nav className="grid gap-1">
145
131
  {navItems.map((item) => (
146
132
  <NavItem key={item.to} item={item} compact={false} />
@@ -4,10 +4,7 @@ import "./styles.css";
4
4
  import "streamdown/styles.css";
5
5
  import { AppLayout } from "./components/app-layout";
6
6
  import { OverviewPage } from "./pages/overview-page";
7
- import { ChannelsPage } from "./pages/channels-page";
8
7
  import { ChatPage } from "./pages/chat-page";
9
- import { DocsPage } from "./pages/docs-page";
10
- import { ModelsPage } from "./pages/models-page";
11
8
 
12
9
  function App() {
13
10
  return (
@@ -16,9 +13,6 @@ function App() {
16
13
  <Routes>
17
14
  <Route path="/" element={<Navigate to="/chat" replace />} />
18
15
  <Route path="/overview" element={<OverviewPage />} />
19
- <Route path="/docs" element={<DocsPage />} />
20
- <Route path="/models" element={<ModelsPage />} />
21
- <Route path="/channels" element={<ChannelsPage />} />
22
16
  <Route path="/chat" element={<ChatPage />} />
23
17
  </Routes>
24
18
  </AppLayout>