@monkey-mini-app/dsh-mini-app 0.1.0
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.
- package/cordis.patch.yml +6 -0
- package/lib/client.d.cts +35 -0
- package/lib/client.js +5462 -0
- package/lib/index.d.ts +140 -0
- package/lib/index.js +1094 -0
- package/package.json +90 -0
- package/skills/monkey-mini-app/SKILL.md +209 -0
- package/skills/monkey-mini-app/references/catalog.md +99 -0
- package/skills/monkey-mini-app/references/contracts/activity-feed.md +24 -0
- package/skills/monkey-mini-app/references/contracts/app-shell.md +28 -0
- package/skills/monkey-mini-app/references/contracts/attachment-gallery.md +22 -0
- package/skills/monkey-mini-app/references/contracts/autocomplete.md +16 -0
- package/skills/monkey-mini-app/references/contracts/cascader.md +25 -0
- package/skills/monkey-mini-app/references/contracts/code-block.md +15 -0
- package/skills/monkey-mini-app/references/contracts/code-editor.md +17 -0
- package/skills/monkey-mini-app/references/contracts/color-picker.md +14 -0
- package/skills/monkey-mini-app/references/contracts/comment-thread.md +24 -0
- package/skills/monkey-mini-app/references/contracts/confirm-dialog.md +19 -0
- package/skills/monkey-mini-app/references/contracts/copyable.md +13 -0
- package/skills/monkey-mini-app/references/contracts/currency-input.md +15 -0
- package/skills/monkey-mini-app/references/contracts/data-grid.md +87 -0
- package/skills/monkey-mini-app/references/contracts/date-picker.md +17 -0
- package/skills/monkey-mini-app/references/contracts/date-range-picker.md +26 -0
- package/skills/monkey-mini-app/references/contracts/date-time-picker.md +18 -0
- package/skills/monkey-mini-app/references/contracts/date-time-range-picker.md +24 -0
- package/skills/monkey-mini-app/references/contracts/description-list.md +13 -0
- package/skills/monkey-mini-app/references/contracts/detail-panel.md +27 -0
- package/skills/monkey-mini-app/references/contracts/diff-viewer.md +16 -0
- package/skills/monkey-mini-app/references/contracts/donut-chart.md +31 -0
- package/skills/monkey-mini-app/references/contracts/duration-input.md +14 -0
- package/skills/monkey-mini-app/references/contracts/env-badge.md +13 -0
- package/skills/monkey-mini-app/references/contracts/event-calendar.md +50 -0
- package/skills/monkey-mini-app/references/contracts/file-dropzone.md +14 -0
- package/skills/monkey-mini-app/references/contracts/file-tree.md +23 -0
- package/skills/monkey-mini-app/references/contracts/filter-bar.md +26 -0
- package/skills/monkey-mini-app/references/contracts/gantt.md +24 -0
- package/skills/monkey-mini-app/references/contracts/gauge.md +14 -0
- package/skills/monkey-mini-app/references/contracts/jira-wiki.md +53 -0
- package/skills/monkey-mini-app/references/contracts/jql-input.md +37 -0
- package/skills/monkey-mini-app/references/contracts/json-viewer.md +13 -0
- package/skills/monkey-mini-app/references/contracts/kanban-issue-panel.md +45 -0
- package/skills/monkey-mini-app/references/contracts/kanban.md +64 -0
- package/skills/monkey-mini-app/references/contracts/log-viewer.md +13 -0
- package/skills/monkey-mini-app/references/contracts/markdown-editor.md +24 -0
- package/skills/monkey-mini-app/references/contracts/markdown.md +14 -0
- package/skills/monkey-mini-app/references/contracts/mini-calendar.md +15 -0
- package/skills/monkey-mini-app/references/contracts/notification-center.md +23 -0
- package/skills/monkey-mini-app/references/contracts/number-field.md +17 -0
- package/skills/monkey-mini-app/references/contracts/page-header.md +25 -0
- package/skills/monkey-mini-app/references/contracts/password-field.md +14 -0
- package/skills/monkey-mini-app/references/contracts/phone-input.md +14 -0
- package/skills/monkey-mini-app/references/contracts/progress-ring.md +13 -0
- package/skills/monkey-mini-app/references/contracts/radar-chart.md +23 -0
- package/skills/monkey-mini-app/references/contracts/rating.md +15 -0
- package/skills/monkey-mini-app/references/contracts/relative-date-picker.md +24 -0
- package/skills/monkey-mini-app/references/contracts/request-inspector.md +16 -0
- package/skills/monkey-mini-app/references/contracts/rich-text-editor.md +15 -0
- package/skills/monkey-mini-app/references/contracts/run-timeline.md +24 -0
- package/skills/monkey-mini-app/references/contracts/scrollspy.md +13 -0
- package/skills/monkey-mini-app/references/contracts/search-input.md +17 -0
- package/skills/monkey-mini-app/references/contracts/severity-chip.md +13 -0
- package/skills/monkey-mini-app/references/contracts/slider-range.md +16 -0
- package/skills/monkey-mini-app/references/contracts/sortable-list.md +23 -0
- package/skills/monkey-mini-app/references/contracts/sparkline.md +13 -0
- package/skills/monkey-mini-app/references/contracts/stacked-bar-chart.md +23 -0
- package/skills/monkey-mini-app/references/contracts/stat-card.md +27 -0
- package/skills/monkey-mini-app/references/contracts/status-badge.md +24 -0
- package/skills/monkey-mini-app/references/contracts/stepper.md +26 -0
- package/skills/monkey-mini-app/references/contracts/tag-input.md +15 -0
- package/skills/monkey-mini-app/references/contracts/terminal.md +13 -0
- package/skills/monkey-mini-app/references/contracts/test-step-list.md +23 -0
- package/skills/monkey-mini-app/references/contracts/time-picker.md +18 -0
- package/skills/monkey-mini-app/references/contracts/time-range-picker.md +23 -0
- package/skills/monkey-mini-app/references/contracts/time-wheel.md +29 -0
- package/skills/monkey-mini-app/references/contracts/timeline.md +24 -0
- package/skills/monkey-mini-app/references/contracts/timezone-select.md +27 -0
- package/skills/monkey-mini-app/references/contracts/transfer.md +24 -0
- package/skills/monkey-mini-app/references/contracts/tree-view.md +23 -0
- package/skills/monkey-mini-app/references/contracts/trend-card.md +26 -0
- package/skills/monkey-mini-app/references/contracts/user-picker.md +24 -0
- package/skills/monkey-mini-app/references/ctx.md +137 -0
- package/skills/monkey-mini-app/references/history.md +10 -0
- package/skills/monkey-mini-app/references/icons.md +83 -0
- package/skills/monkey-mini-app/references/llm-json.md +69 -0
- package/skills/monkey-mini-app/references/loader.md +30 -0
- package/skills/monkey-mini-app/references/test.md +30 -0
- package/skills/monkey-mini-app/references/tools.md +21 -0
- package/skills/monkey-mini-app/references/troubleshoot.md +12 -0
- package/skills/monkey-mini-app/templates/README.md +24 -0
- package/skills/monkey-mini-app/templates/agentrun/main.api.ts +78 -0
- package/skills/monkey-mini-app/templates/agentrun/manifest.json +9 -0
- package/skills/monkey-mini-app/templates/agentrun/ui.tsx +125 -0
- package/skills/monkey-mini-app/templates/insights/lib/sample.ts +17 -0
- package/skills/monkey-mini-app/templates/insights/main.api.ts +101 -0
- package/skills/monkey-mini-app/templates/insights/manifest.json +9 -0
- package/skills/monkey-mini-app/templates/insights/ui.tsx +138 -0
- package/skills/monkey-mini-app/templates/jira/main.api.ts +115 -0
- package/skills/monkey-mini-app/templates/jira/manifest.json +9 -0
- package/skills/monkey-mini-app/templates/jira/ui.tsx +318 -0
- package/skills/monkey-mini-app/templates/minimal/main.api.ts +16 -0
- package/skills/monkey-mini-app/templates/minimal/manifest.json +8 -0
- package/skills/monkey-mini-app/templates/minimal/ui.tsx +74 -0
- package/skills/monkey-mini-app/templates/monitor/main.api.ts +91 -0
- package/skills/monkey-mini-app/templates/monitor/manifest.json +9 -0
- package/skills/monkey-mini-app/templates/monitor/ui.tsx +176 -0
- package/skills/monkey-mini-app/templates/review/main.api.ts +68 -0
- package/skills/monkey-mini-app/templates/review/manifest.json +9 -0
- package/skills/monkey-mini-app/templates/review/ui.tsx +159 -0
- package/skills/monkey-mini-app/templates/todo/main.api.ts +83 -0
- package/skills/monkey-mini-app/templates/todo/manifest.json +8 -0
- package/skills/monkey-mini-app/templates/todo/ui.tsx +177 -0
- package/tsup.config.ts +68 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<!-- generated by scripts/generate-skill.mjs — do not edit -->
|
|
2
|
+
|
|
3
|
+
# Timeline
|
|
4
|
+
|
|
5
|
+
`import { Timeline, TimelineItem } from "@monkey-mini-app/ui"`
|
|
6
|
+
|
|
7
|
+
`packages/ui/src/products/timeline.tsx` · products
|
|
8
|
+
|
|
9
|
+
## Props
|
|
10
|
+
|
|
11
|
+
| field | type | required | note |
|
|
12
|
+
|---|---|:---:|---|
|
|
13
|
+
| `items` | `TimelineItem[]` | ✓ | |
|
|
14
|
+
|
|
15
|
+
## Types
|
|
16
|
+
|
|
17
|
+
### `TimelineItem`
|
|
18
|
+
|
|
19
|
+
| field | type | required | note |
|
|
20
|
+
|---|---|:---:|---|
|
|
21
|
+
| `description` | `string \| undefined` | | |
|
|
22
|
+
| `id` | `string` | ✓ | |
|
|
23
|
+
| `time` | `string \| undefined` | | |
|
|
24
|
+
| `title` | `string` | ✓ | |
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
<!-- generated by scripts/generate-skill.mjs — do not edit -->
|
|
2
|
+
|
|
3
|
+
# TimezoneSelect
|
|
4
|
+
|
|
5
|
+
`import { TimezoneSelect, ZoneInfo } from "@monkey-mini-app/ui"`
|
|
6
|
+
|
|
7
|
+
`packages/ui/src/composites/timezone-select.tsx` · composites
|
|
8
|
+
|
|
9
|
+
## Props
|
|
10
|
+
|
|
11
|
+
| field | type | required | note |
|
|
12
|
+
|---|---|:---:|---|
|
|
13
|
+
| `className` | `string \| undefined` | | |
|
|
14
|
+
| `onChange` | `((zone: string) => void) \| undefined` | | |
|
|
15
|
+
| `value` | `string \| undefined` | | |
|
|
16
|
+
|
|
17
|
+
## Types
|
|
18
|
+
|
|
19
|
+
### `ZoneInfo`
|
|
20
|
+
|
|
21
|
+
| field | type | required | note |
|
|
22
|
+
|---|---|:---:|---|
|
|
23
|
+
| `city` | `string` | ✓ | |
|
|
24
|
+
| `id` | `string` | ✓ | |
|
|
25
|
+
| `offset` | `string` | ✓ | |
|
|
26
|
+
| `region` | `string` | ✓ | |
|
|
27
|
+
| `search` | `string` | ✓ | |
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<!-- generated by scripts/generate-skill.mjs — do not edit -->
|
|
2
|
+
|
|
3
|
+
# Transfer
|
|
4
|
+
|
|
5
|
+
`import { Transfer, TransferItem } from "@monkey-mini-app/ui"`
|
|
6
|
+
|
|
7
|
+
`packages/ui/src/composites/transfer.tsx` · composites
|
|
8
|
+
|
|
9
|
+
## Props
|
|
10
|
+
|
|
11
|
+
| field | type | required | note |
|
|
12
|
+
|---|---|:---:|---|
|
|
13
|
+
| `items` | `TransferItem[]` | ✓ | |
|
|
14
|
+
| `onChange` | `((value: string[]) => void) \| undefined` | | |
|
|
15
|
+
| `value` | `string[] \| undefined` | | |
|
|
16
|
+
|
|
17
|
+
## Types
|
|
18
|
+
|
|
19
|
+
### `TransferItem`
|
|
20
|
+
|
|
21
|
+
| field | type | required | note |
|
|
22
|
+
|---|---|:---:|---|
|
|
23
|
+
| `id` | `string` | ✓ | |
|
|
24
|
+
| `label` | `string` | ✓ | |
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
<!-- generated by scripts/generate-skill.mjs — do not edit -->
|
|
2
|
+
|
|
3
|
+
# TreeView
|
|
4
|
+
|
|
5
|
+
`import { TreeView, TreeNode } from "@monkey-mini-app/ui"`
|
|
6
|
+
|
|
7
|
+
`packages/ui/src/products/tree-view.tsx` · products
|
|
8
|
+
|
|
9
|
+
## Props
|
|
10
|
+
|
|
11
|
+
| field | type | required | note |
|
|
12
|
+
|---|---|:---:|---|
|
|
13
|
+
| `nodes` | `TreeNode[]` | ✓ | |
|
|
14
|
+
|
|
15
|
+
## Types
|
|
16
|
+
|
|
17
|
+
### `TreeNode`
|
|
18
|
+
|
|
19
|
+
| field | type | required | note |
|
|
20
|
+
|---|---|:---:|---|
|
|
21
|
+
| `children` | `TreeNode[] \| undefined` | | |
|
|
22
|
+
| `id` | `string` | ✓ | |
|
|
23
|
+
| `label` | `string` | ✓ | |
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
<!-- generated by scripts/generate-skill.mjs — do not edit -->
|
|
2
|
+
|
|
3
|
+
# TrendCard
|
|
4
|
+
|
|
5
|
+
`import { TrendCard, TrendPoint } from "@monkey-mini-app/ui"`
|
|
6
|
+
|
|
7
|
+
`packages/ui/src/blocks/trend-card.tsx` · blocks
|
|
8
|
+
|
|
9
|
+
## Props
|
|
10
|
+
|
|
11
|
+
| field | type | required | note |
|
|
12
|
+
|---|---|:---:|---|
|
|
13
|
+
| `data` | `TrendPoint[]` | ✓ | |
|
|
14
|
+
| `delta` | `string \| undefined` | | |
|
|
15
|
+
| `title` | `string` | ✓ | |
|
|
16
|
+
| `trend` | `"up" \| "down" \| "flat" \| undefined` | | |
|
|
17
|
+
| `value` | `ReactNode` | ✓ | |
|
|
18
|
+
|
|
19
|
+
## Types
|
|
20
|
+
|
|
21
|
+
### `TrendPoint`
|
|
22
|
+
|
|
23
|
+
| field | type | required | note |
|
|
24
|
+
|---|---|:---:|---|
|
|
25
|
+
| `label` | `string` | ✓ | |
|
|
26
|
+
| `value` | `number` | ✓ | |
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<!-- generated by scripts/generate-skill.mjs — do not edit -->
|
|
2
|
+
|
|
3
|
+
# UserPicker
|
|
4
|
+
|
|
5
|
+
`import { UserPicker, UserOption } from "@monkey-mini-app/ui"`
|
|
6
|
+
|
|
7
|
+
`packages/ui/src/composites/user-picker.tsx` · composites
|
|
8
|
+
|
|
9
|
+
## Props
|
|
10
|
+
|
|
11
|
+
| field | type | required | note |
|
|
12
|
+
|---|---|:---:|---|
|
|
13
|
+
| `onChange` | `((id: string) => void) \| undefined` | | |
|
|
14
|
+
| `users` | `UserOption[]` | ✓ | |
|
|
15
|
+
| `value` | `string \| undefined` | | |
|
|
16
|
+
|
|
17
|
+
## Types
|
|
18
|
+
|
|
19
|
+
### `UserOption`
|
|
20
|
+
|
|
21
|
+
| field | type | required | note |
|
|
22
|
+
|---|---|:---:|---|
|
|
23
|
+
| `id` | `string` | ✓ | |
|
|
24
|
+
| `name` | `string` | ✓ | |
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# RunContext `ctx`
|
|
2
|
+
|
|
3
|
+
每个 `api.*` / `onMount` / `onUnmount` 都拿到同一个 `ctx`。
|
|
4
|
+
|
|
5
|
+
## 总是可用
|
|
6
|
+
|
|
7
|
+
| API | 返回 | 说明 |
|
|
8
|
+
|-----|------|------|
|
|
9
|
+
| `ctx.appId` | string | 当前小程序 reverse-DNS id |
|
|
10
|
+
| `ctx.appDir` | string | 当前小程序绝对目录(`runtime/apps/<appId>`) |
|
|
11
|
+
| `ctx.storage.get(key)` | value 或 `null` | `storage/main.storage.json` |
|
|
12
|
+
| `ctx.storage.set(key, value)` | | JSON 可序列化 |
|
|
13
|
+
| `ctx.storage.delete` / `clear` | | |
|
|
14
|
+
| `ctx.storage.table(name)` | 同样 API | `{name}.storage.json`,name=`[A-Za-z0-9_-]` |
|
|
15
|
+
| `ctx.state` | object | 内存,与 defineDashboard.state 同一引用 |
|
|
16
|
+
| `ctx.config` | `{ theme, palette, chatLanguage, hostPort, llm }` | 只含本 Host 配置(设置页 / 顶栏配色可改),**不是** dsh 设置 dump。`theme`=`light`/`dark`;`palette`=`default`/`ocean`/`violet`/`slate`(默认/海蓝/青紫/石墨) |
|
|
17
|
+
| `ctx.credentials` | `Record<string,string>` | 声明过的密钥 |
|
|
18
|
+
| `ctx.log(...args)` | | console |
|
|
19
|
+
| `ctx.signal` | AbortSignal 或 undefined | 当前调用的取消信号(chat 点「停止」时 abort)。长任务在批次/循环间 `if (ctx.signal?.aborted) throw new Error("cancelled")`,`sleep` 也传它 |
|
|
20
|
+
| `ctx.push(method, params)` | | 常为 no-op |
|
|
21
|
+
| `ctx.system.metrics()` | os 快照 | |
|
|
22
|
+
|
|
23
|
+
## Host 能力
|
|
24
|
+
|
|
25
|
+
| API | 签名 | 返回 | Fallback | 失败 |
|
|
26
|
+
|-----|------|------|----------|------|
|
|
27
|
+
| `http(url)` / `http(url, opts)` | opts:`method?` `headers?` `query?` `body?` `timeout?`(默认 8s)。自动组合 `ctx.signal`(停止即中断) | `{ ok, status, headers, text, json }`。`json` 仅当 Content-Type 含 json 且能 parse,否则 `null`。HTTP 4xx/5xx **不 throw**,看 `ok`/`status`。只允许 http/https | Node `fetch` | `http: timeout` / `http: only http/https` / `http: response too large` / `http: …` |
|
|
28
|
+
| `bash(command)` | string | `{ stdout, stderr, exitCode }` | 本地 `bash -c` 120s/8MB → dsh `shell.run`。给本机命令用,**不要** `curl` | `bash unavailable` |
|
|
29
|
+
| `tool(name, args)` | args **普通对象**,禁止 `{input}` | **string** | dsh tools | `tool: ctx.tools not available` |
|
|
30
|
+
| `mcp(name, args?)` | 不要 `mcp_` 前缀 | string | `tool(name)` 再 `tool("mcp__"+name)`。dsh 登记名是 `mcp__<server>__<tool>`,例如 `ctx.mcp("everything__echo", { message: "hi" })` | 第一次错误 |
|
|
31
|
+
| `llm(prompt, opts?)` | 见下方 **ModelCallOptions** | **string** | dsh `llm.stream` | `llm: no dsh model service` / `llm stream empty` |
|
|
32
|
+
| `agent(goal, opts?)` | **ModelCallOptions** + `onEvent?`(见下) | **string** | dsh one-shot agent(与聊天 session 隔离);可用工具循环。不要用多次 `ctx.llm` 假装 agent | `agent: … unbound` / `empty result` / `cancelled` |
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
const r = await ctx.http("https://example.com/api", {
|
|
36
|
+
method: "GET",
|
|
37
|
+
headers: { accept: "application/json" },
|
|
38
|
+
query: { q: "hi" },
|
|
39
|
+
timeout: 8000,
|
|
40
|
+
});
|
|
41
|
+
if (!r.ok) throw new Error("HTTP " + r.status);
|
|
42
|
+
const data = r.json ?? JSON.parse(r.text);
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
POST:`ctx.http(url, { method: "POST", body: { a: 1 } })`(对象会 JSON 编码)。RSS/HTML 用 `r.text`。
|
|
46
|
+
|
|
47
|
+
### ModelCallOptions(`llm` / `agent` 共用最小集合)
|
|
48
|
+
|
|
49
|
+
```ts
|
|
50
|
+
type ModelCallOptions = {
|
|
51
|
+
provider?: string; // 默认跟 dsh 当前模型;可不传
|
|
52
|
+
model?: string;
|
|
53
|
+
system?: string;
|
|
54
|
+
schema?: object; // JSON Schema;要对象时用,再 JSON.parse 返回值
|
|
55
|
+
maxTokens?: number;
|
|
56
|
+
signal?: AbortSignal; // api 调用里通常已有 ctx.signal,可省略
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
// llm
|
|
60
|
+
await ctx.llm(prompt, opts?: ModelCallOptions): Promise<string>
|
|
61
|
+
|
|
62
|
+
// agent = ModelCallOptions + onEvent + maxIterations + cwd
|
|
63
|
+
await ctx.agent(goal, opts?: ModelCallOptions & {
|
|
64
|
+
/** Soft turn cap: host cancels after this many completed turns. */
|
|
65
|
+
maxIterations?: number;
|
|
66
|
+
onEvent?: (ev: AgentEvent) => void;
|
|
67
|
+
/**
|
|
68
|
+
* Working dir mode (default "process").
|
|
69
|
+
* app = 当前小程序目录;process = dsh 启动目录;temp = 临时目录;custom = 配 cwd 绝对路径。
|
|
70
|
+
* 只传 cwd 路径 ⇒ 视为 custom。cwd + 非 custom 的 cwdType ⇒ 报错。
|
|
71
|
+
*/
|
|
72
|
+
cwdType?: "app" | "process" | "temp" | "custom";
|
|
73
|
+
cwd?: string; // 绝对路径;custom 必填,或单独传
|
|
74
|
+
}): Promise<string>
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
路由:`opts.provider/model` → dsh 当前 `agent-default-model` → `deepseek-official` / `deepseek-v4-flash`。不必改 `host.json`。
|
|
78
|
+
|
|
79
|
+
### `opts.schema`(llm + agent)
|
|
80
|
+
|
|
81
|
+
软约束「只回 JSON」+ 剥 markdown;**返回仍是 string**,`JSON.parse`。例子 → [llm-json.md](llm-json.md)。提示宜短,约束交给 schema。
|
|
82
|
+
|
|
83
|
+
### `opts.onEvent`(仅 agent)— 过程事件完整形状
|
|
84
|
+
|
|
85
|
+
返回值仍是最终 string;`onEvent` 只观测过程。UI 用 storage 轮询即可:
|
|
86
|
+
|
|
87
|
+
```ts
|
|
88
|
+
type AgentEvent =
|
|
89
|
+
| { type: "status"; status: "running" | "idle" }
|
|
90
|
+
| { type: "text-delta"; text: string }
|
|
91
|
+
| { type: "tool"; phase: "start" | "end"; name: string; args?: unknown; result?: unknown }
|
|
92
|
+
| { type: "turn"; phase: "start"; turn: number }
|
|
93
|
+
| { type: "turn"; phase: "end"; turn: number; reason?: { kind: string; error?: unknown; reason?: unknown } }
|
|
94
|
+
// reason.kind 常见:completed | blocked | error | aborted | max-tokens
|
|
95
|
+
| { type: "error"; message: string }
|
|
96
|
+
| { type: "done"; text: string };
|
|
97
|
+
|
|
98
|
+
const trace = [];
|
|
99
|
+
const text = await ctx.agent("根据材料给出洞察", {
|
|
100
|
+
schema: { type: "object", properties: { summary: { type: "string" } }, required: ["summary"] },
|
|
101
|
+
onEvent: (ev) => {
|
|
102
|
+
trace.push(ev);
|
|
103
|
+
void ctx.storage.set("agentTrace", trace);
|
|
104
|
+
},
|
|
105
|
+
});
|
|
106
|
+
const insight = JSON.parse(text);
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
`ctx.agent` 与用户聊天 session 隔离(ephemeral,跑完 dispose)。
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
## 列出当前 tool
|
|
113
|
+
|
|
114
|
+
**仅当 main.api.ts 会调用 `ctx.tool` 时**才调聊天工具 `mini_app_list_ctx_tools`。纯 storage / http / bash / llm 的 app 不要调。
|
|
115
|
+
|
|
116
|
+
后端也可用 `ctx.listTools()`。不要假设 read/write/bash 一定存在或参数名固定。
|
|
117
|
+
|
|
118
|
+
## 长耗时任务:必须采样 + 响应取消
|
|
119
|
+
|
|
120
|
+
多源抓取 × LLM 分析这类任务,**不要全量跑**:
|
|
121
|
+
|
|
122
|
+
- **采样走通流程**:10 个 RSS 取 2 个有代表性的源(如主站 + 高热度站);批次只跑 1 批(如最热的 16~24 条)验证全链路;其余用启发式兜底。告诉用户「先跑样例,全量可后续加」。
|
|
123
|
+
- **批次上限**:LLM 分析批次数硬上限(如 `MAX_BATCHES = 2`),避免单次调用跑 10 分钟。
|
|
124
|
+
- **必须响应取消**:循环/批次/sleep 处检查 `ctx.signal`:
|
|
125
|
+
```ts
|
|
126
|
+
async function sleep(ms: number, signal?: AbortSignal) {
|
|
127
|
+
return new Promise((resolve) => {
|
|
128
|
+
if (signal?.aborted) return resolve();
|
|
129
|
+
const t = setTimeout(resolve, ms);
|
|
130
|
+
signal?.addEventListener("abort", () => { clearTimeout(t); resolve(); }, { once: true });
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
// 批次间
|
|
134
|
+
if (ctx.signal?.aborted) throw new Error("cancelled");
|
|
135
|
+
await sleep(400, ctx.signal);
|
|
136
|
+
```
|
|
137
|
+
- **异步进度**:长任务提供 `scanStatus`/`progress` 类方法(写入 storage),UI 轮询;`scan` 本身 fire-and-forget 立即返回「已启动」。
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# Icons
|
|
2
|
+
|
|
3
|
+
`import { Icon } from "@monkey-mini-app/ui"` — 一个 `Icon` 命名空间(来自 lucide)。`Icon.<Name>` 接受**任意 lucide React 组件名**(大驼峰)。下面是**常用推荐子集**,按用途分组、一句话告诉你什么时候用;没列到的按 lucide 命名规则也能用(如 `Icon.IconName`)。
|
|
4
|
+
|
|
5
|
+
```tsx
|
|
6
|
+
import { Icon } from "@monkey-mini-app/ui";
|
|
7
|
+
<Icon.Search size={16} strokeWidth={2} />
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
## 操作
|
|
11
|
+
| 名字 | 何时用 |
|
|
12
|
+
|---|---|
|
|
13
|
+
| `Plus` / `Minus` | 添加 / 减少 |
|
|
14
|
+
| `X` | 关闭、清除 |
|
|
15
|
+
| `Check` / `CheckCircle2` | 完成、成功 |
|
|
16
|
+
| `Trash2` | 删除 |
|
|
17
|
+
| `Pencil` / `PenLine` | 编辑、重命名 |
|
|
18
|
+
| `Copy` / `Clipboard` | 复制 |
|
|
19
|
+
| `Download` / `Upload` | 下载 / 上传 |
|
|
20
|
+
| `RefreshCw` | 刷新、重新拉取 |
|
|
21
|
+
| `Send` | 提交、发送 |
|
|
22
|
+
| `ExternalLink` | 打开新窗口 |
|
|
23
|
+
| `Link` | 复制链接 |
|
|
24
|
+
|
|
25
|
+
## 导航
|
|
26
|
+
| 名字 | 何时用 |
|
|
27
|
+
|---|---|
|
|
28
|
+
| `ChevronRight` / `ChevronLeft` | 进入/展开 或 返回 |
|
|
29
|
+
| `ChevronDown` / `ChevronUp` | 折叠/展开 |
|
|
30
|
+
| `ChevronsUpDown` | 可排序 |
|
|
31
|
+
| `ArrowUpRight` | 外链、跑分增长 |
|
|
32
|
+
| `ArrowLeftRight` / `ArrowUpDown` | 切换、传输 |
|
|
33
|
+
| `MoreHorizontal` | 更多菜单 |
|
|
34
|
+
|
|
35
|
+
## 状态
|
|
36
|
+
| 名字 | 何时用 |
|
|
37
|
+
|---|---|
|
|
38
|
+
| `Bell` / `BellOff` | 通知 / 免打扰 |
|
|
39
|
+
| `Eye` / `EyeOff` | 显示 / 隐藏敏感值 |
|
|
40
|
+
| `Info` | 信息提示 |
|
|
41
|
+
| `AlertCircle` / `TriangleAlert` | 警告 |
|
|
42
|
+
| `Loader2` / `LoaderCircle` | 加载中(配 animate) |
|
|
43
|
+
| `HelpCircle` | 帮助 |
|
|
44
|
+
| `BadgeCheck` | 已验证、通过 |
|
|
45
|
+
| `Star` / `Heart` | 收藏 / 喜欢 |
|
|
46
|
+
|
|
47
|
+
## 内容 & 输入
|
|
48
|
+
| 名字 | 何时用 |
|
|
49
|
+
|---|---|
|
|
50
|
+
| `Search` | 搜索框 |
|
|
51
|
+
| `Filter` | 筛选 |
|
|
52
|
+
| `SlidersHorizontal` | 高级筛选、设置参数 |
|
|
53
|
+
| `CalendarDays` | 日期 |
|
|
54
|
+
| `Clock` / `History` | 时间 / 历史 |
|
|
55
|
+
| `Tag` | 标签、分类 |
|
|
56
|
+
| `File` / `FileText` | 文件 / 文档 |
|
|
57
|
+
| `Folder` / `FolderOpen` | 目录 |
|
|
58
|
+
| `Image` | 图片 |
|
|
59
|
+
| `List` / `ListOrdered` | 列表 / 有序列表 |
|
|
60
|
+
| `Hash` | 编号、话题 |
|
|
61
|
+
| `Code2` / `Terminal` | 代码 / 命令行 |
|
|
62
|
+
|
|
63
|
+
## 系统 & 监控
|
|
64
|
+
| 名字 | 何时用 |
|
|
65
|
+
|---|---|
|
|
66
|
+
| `Activity` / `Zap` | 实时活动、性能 |
|
|
67
|
+
| `Gauge` / `BarChart3` | 指标、大盘 |
|
|
68
|
+
| `Server` / `Database` | 服务、数据存储 |
|
|
69
|
+
| `HardDrive` / `Cpu` / `MemoryStick` | 磁盘 / CPU / 内存 |
|
|
70
|
+
| `Cloud` / `Network` / `Globe` / `Wifi` | 网络、云、外部服务 |
|
|
71
|
+
| `TrendingUp` / `TrendingDown` | 涨 / 跌 |
|
|
72
|
+
| `GitBranch` / `GitMerge` / `GitPullRequest` | git 分支、合并、PR |
|
|
73
|
+
| `Rocket` | 发布、上线 |
|
|
74
|
+
|
|
75
|
+
## 媒体 / 用户 / 设置
|
|
76
|
+
| 名字 | 何时用 |
|
|
77
|
+
|---|---|
|
|
78
|
+
| `Play` / `Pause` | 播放 / 暂停 |
|
|
79
|
+
| `Music2` / `Video` / `Mic` / `Camera` | 音视频 |
|
|
80
|
+
| `Settings` / `Settings2` | 设置 |
|
|
81
|
+
| `Mail` / `MessageSquare` | 邮箱 / 评论 |
|
|
82
|
+
| `Lock` / `Unlock` / `KeyRound` | 权限、密钥 |
|
|
83
|
+
| `Home` | 首页 |
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# 结构化 JSON(`ctx.llm` / `ctx.agent` + `opts.schema`)
|
|
2
|
+
|
|
3
|
+
需要对象/数组时走这条,不要自己试各种「请只输出 JSON」。
|
|
4
|
+
|
|
5
|
+
## 契约(llm 与 agent 对齐)
|
|
6
|
+
|
|
7
|
+
| | 说明 |
|
|
8
|
+
|--|------|
|
|
9
|
+
| 入口 | `ctx.llm(prompt, { schema })` **或** `ctx.agent(goal, { schema })` |
|
|
10
|
+
| 返回 | **始终是 string**;给了 `schema` 时宿主会要求模型只回 JSON,并尽量剥掉 markdown/前言 |
|
|
11
|
+
| App 侧 | `JSON.parse(raw)`;失败就 throw,不要当业务文案展示 |
|
|
12
|
+
| 不是什么 | **不是**默认每次结构化;**不是** provider 原生 JSON mode / schema 校验重试(二期可加强) |
|
|
13
|
+
|
|
14
|
+
`schema` 用普通 JSON Schema 对象(至少 `type` + `properties` / `items`)。提示宜短:任务说清楚 + 把约束交给 `schema`,不必再堆「不要解释」。
|
|
15
|
+
|
|
16
|
+
## `ctx.llm` 例子
|
|
17
|
+
|
|
18
|
+
完整 RSS + `./lib` + schema 见 `templates/insights/`。
|
|
19
|
+
|
|
20
|
+
```ts
|
|
21
|
+
const SCHEMA = {
|
|
22
|
+
type: "object",
|
|
23
|
+
properties: {
|
|
24
|
+
headline: { type: "string" },
|
|
25
|
+
bullets: { type: "array", items: { type: "string" } },
|
|
26
|
+
},
|
|
27
|
+
required: ["headline", "bullets"],
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const raw = await ctx.llm("写一条中文 headline,以及恰好 3 条中文 bullets。不要前言。", {
|
|
31
|
+
schema: SCHEMA,
|
|
32
|
+
});
|
|
33
|
+
const digest = JSON.parse(raw);
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## `ctx.agent` 例子
|
|
37
|
+
|
|
38
|
+
适合「多步工具/推理后再收成结构化结果」。仍返回 string。若还要过程时间线,同一调用加 `onEvent`(形状见 [ctx.md](ctx.md))。
|
|
39
|
+
|
|
40
|
+
```ts
|
|
41
|
+
const INSIGHT_SCHEMA = {
|
|
42
|
+
type: "object",
|
|
43
|
+
properties: {
|
|
44
|
+
summary: { type: "string" },
|
|
45
|
+
risks: { type: "array", items: { type: "string" } },
|
|
46
|
+
nextStep: { type: "string" },
|
|
47
|
+
},
|
|
48
|
+
required: ["summary", "risks", "nextStep"],
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const raw = await ctx.agent(
|
|
52
|
+
"根据下面材料给出对独立开发者的洞察:风险列表 + 下一步建议。\n" + materials,
|
|
53
|
+
{ schema: INSIGHT_SCHEMA },
|
|
54
|
+
);
|
|
55
|
+
const insight = JSON.parse(raw);
|
|
56
|
+
await ctx.storage.set("insight", insight);
|
|
57
|
+
return insight;
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
与 llm 一样:`schema` 可选;自然语言最终句不必传 `schema`。
|
|
61
|
+
|
|
62
|
+
## 宿主实际做了什么(实现提示)
|
|
63
|
+
|
|
64
|
+
1. `withJsonInstruction`:把 schema 写进约束(llm → stream 的 `system`;agent → one-shot followup 文本)
|
|
65
|
+
2. 模型生成
|
|
66
|
+
3. `coerceSchemaJson`:去掉 \`\`\`json 围栏 / 前言,尽量抽出 `{…}` / `[…]`
|
|
67
|
+
4. App `JSON.parse`
|
|
68
|
+
|
|
69
|
+
校验失败时 **不会**自动重试;该 throw 就 throw,让 UI 显示错误。
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Loader
|
|
2
|
+
|
|
3
|
+
Host 在服务端即时编译:**后端**用 sucrase 编译 `main.api.ts` / `lib/*.ts`;**前端 UI** 用 esbuild-wasm 把 `ui.tsx` 连同用到的组件打包成单个 ESM bundle(tree-shake,按 app 裁剪组件库)。
|
|
4
|
+
|
|
5
|
+
## 后端(main.api.ts / lib/*.ts)
|
|
6
|
+
|
|
7
|
+
- `import { defineDashboard } from "@monkeyagent/dashboard"`
|
|
8
|
+
- `import { foo } from "./lib/foo"`(也可 `./components/...`)
|
|
9
|
+
- TypeScript 随意(sucrase:参数类型、`{ title: string }`、`catch (e: any)` 都可以)
|
|
10
|
+
- `export default defineDashboard(...)`
|
|
11
|
+
- `lib/` 里 `export function` / `export const` / `export async function`
|
|
12
|
+
|
|
13
|
+
## 前端(ui.tsx)
|
|
14
|
+
|
|
15
|
+
- `import { Button, DataGrid, ... } from "@monkey-mini-app/ui"` —— 组件库(已内置图标/图表/编辑器依赖,不要额外 import npm 包)
|
|
16
|
+
- `import { useDashboardApi } from "@monkeyagent/host"` —— host 注入的 hook,只返回 `{ call }`
|
|
17
|
+
- `import { useState } from "react"` —— React 19(host 注入)
|
|
18
|
+
- `import { foo } from "./lib/foo"` —— 相对 app 内文件,随 bundle 一起打包
|
|
19
|
+
- 布局用 Tailwind classes(`flex flex-col gap-3` 等)
|
|
20
|
+
|
|
21
|
+
## 禁止(编译即报错,不要绕)
|
|
22
|
+
|
|
23
|
+
- npm 包:`recharts`、`lucide-react`、`rss-parser`、`openai`、`node-fetch`…(组件库已内置)
|
|
24
|
+
- Node 内置:`fs`、`http`、`path`…
|
|
25
|
+
- 逃出 app 目录的 `../` 出界(前端 `./lib` 同理)
|
|
26
|
+
- UI `import main.api.ts`(要数据走 `call`)
|
|
27
|
+
|
|
28
|
+
抓网页用 `ctx.http("https://…", { timeout: 8000 })`,看 `r.ok` / `r.text` / `r.json`;解析写在 `./lib`。本机命令才 `ctx.bash`。
|
|
29
|
+
|
|
30
|
+
改 `ui.tsx` / `main.api.ts` / `lib/*.ts` 会按 mtime 重新编译。RSS + lib 完整例子见 `templates/insights/`。
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Host 冒烟调试(人类用)
|
|
2
|
+
|
|
3
|
+
这是 **Host `:17880` 调试**,不是小程序里的 `ctx.http`。
|
|
4
|
+
|
|
5
|
+
冒烟请用聊天工具 **`mini_app_call({ appId, method, args })`**,不要 bash/curl。
|
|
6
|
+
|
|
7
|
+
Base: `http://127.0.0.1:17880`(插件 apply 时已 listen,打开小程序面板会预热)。仅在人类调试时用 curl。
|
|
8
|
+
|
|
9
|
+
| 方法 | 路径 | Body | 结果 |
|
|
10
|
+
|------|------|------|------|
|
|
11
|
+
| GET | `/api/apps` | | `{ apps: [{ id, name, version }] }` |
|
|
12
|
+
| GET | `/api/ctx-tools` | | `{ count, tools: [{ name, description, schema }] }` |
|
|
13
|
+
| POST | `/api/call` | `{ appId, method, args }` | `{ ok: true, value }` 或 `{ ok: false, error }` |
|
|
14
|
+
| GET | `/app/:id` | | runner HTML |
|
|
15
|
+
| GET | `/api/app/:id/ui/entry.js` | | per-app UI bundle(编译缓存) |
|
|
16
|
+
| GET | `/ui.css` | | @monkey-mini-app/ui 全局样式 |
|
|
17
|
+
| DELETE | `/api/app/:id` | | `{ ok, appId }` |
|
|
18
|
+
| GET/POST | `/api/host-config` | POST `{ hostPort, theme, palette, … }` | Host 设置 |
|
|
19
|
+
| GET/POST | `/api/llm-config` | POST `{ provider, model }` | 写入 `runtime/llm.json` |
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
curl -s http://127.0.0.1:17880/api/apps
|
|
23
|
+
curl -s http://127.0.0.1:17880/api/call \
|
|
24
|
+
-H 'content-type: application/json' \
|
|
25
|
+
-d '{"appId":"com.example.todo","method":"list","args":{"filter":"all"}}'
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
CORS 已开。改 `main.api.ts` 后直接再 curl,不必开浏览器。
|
|
29
|
+
|
|
30
|
+
小程序后端抓外网 API:用 `ctx.http`,见 [ctx.md](ctx.md)。
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# ctx.tool 能调什么
|
|
2
|
+
|
|
3
|
+
**不要把本文件当固定目录。** 工具集随 dsh profile / 插件 / MCP 变化。
|
|
4
|
+
|
|
5
|
+
生成或改 `main.api.ts` **并且确实要用 `ctx.tool`** 时才:
|
|
6
|
+
|
|
7
|
+
1. 调聊天工具 `mini_app_list_ctx_tools`(无参)
|
|
8
|
+
2. 人类调试才 `curl -s http://127.0.0.1:17880/api/ctx-tools`
|
|
9
|
+
|
|
10
|
+
返回 `{ count, tools: [{ name, description, schema }] }`。
|
|
11
|
+
`name` 就是 `ctx.tool(name, args)` 的第一参;`schema` 是参数形状(可能叫 parameters / inputSchema)。
|
|
12
|
+
|
|
13
|
+
`args` 必须是普通 JSON 对象(`{}` 可以)。禁止 `{ input: "..." }`、`Date`、function、`AbortSignal`。无参工具传 `{}`。
|
|
14
|
+
|
|
15
|
+
## 写 app 时的优先级
|
|
16
|
+
|
|
17
|
+
1. `ctx.storage` / `ctx.http` / `ctx.bash` / `ctx.llm` / `ctx.system.metrics`
|
|
18
|
+
2. 只有明确要复用 dsh 已有工具(读工作区文件等)才 `ctx.tool`
|
|
19
|
+
3. MCP 用 `ctx.mcp("server__tool", args)`,不要 `{ input }`
|
|
20
|
+
|
|
21
|
+
`ctx.listTools()` 在后端同样返回这份快照。
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# 排错
|
|
2
|
+
|
|
3
|
+
| 现象 | 先查 |
|
|
4
|
+
|------|------|
|
|
5
|
+
| `/api/apps` 404 | dsh 插件没起来或 port 不是 17880 |
|
|
6
|
+
| `already been declared defineDashboard` | 旧 loader;当前应只从 require dashboard 来 |
|
|
7
|
+
| 对象字面量/正则被编坏 | 旧 `compileAppSource` 乱剥 `: type` |
|
|
8
|
+
| `llm unavailable` + 其实聊天能用 | 应走 `ctx.llm.stream`;或 POST `/api/llm-config` |
|
|
9
|
+
| bash `policy.mode` undefined | 用本地 `bash -c` 路径,不要依赖坏的 sandbox policy |
|
|
10
|
+
| UI 空白 / CDN | esm.sh 被拦 |
|
|
11
|
+
| iframe 一条缝 | 不是 app 的问题,是 host iframe 高度 |
|
|
12
|
+
| MCP 没反应 | args 不要包 `{ input }` |
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Mini-app 模板指引
|
|
2
|
+
|
|
3
|
+
每个模板是不同的**参考场景**:一个「布局原型」× 一条「能力轴」,告诉你**什么时候抄它、它主要教什么**。先看这张表定位,再决定细读哪个模板(避免把 7 个都读一遍)。
|
|
4
|
+
|
|
5
|
+
| 模板 | 一句话 | 什么时候抄它 | 主要教你 |
|
|
6
|
+
|---|---|---|---|
|
|
7
|
+
| [minimal](./minimal/) | 最简可运行的骨架 | 刚起步 / 连通检查 / 只要个能跑的壳 | `defineDashboard` + `useDashboardApi().call` 一次往返 + `AppShell`/`PageHeader` 骨架 |
|
|
8
|
+
| [todo](./todo/) | 本地 CRUD + 筛选 + 派生统计 | 记本地数据、要增删改查+状态过滤 | `ctx.storage` + 一屏固定内滚 + `FilterBar` + `storage.table()` 多表 |
|
|
9
|
+
| [insights](./insights/) | 联网数据 → 模型摘要(长任务) | 外部数据+智能提炼、会慢 | `ctx.http` + `ctx.llm({schema})` + **采样/进度/`ctx.signal` 取消**(`scan`/`scanStatus` 轮询) |
|
|
10
|
+
| [monitor](./monitor/) | 本机指标实时看板 | 监控/大盘/图表/KPI | `ctx.system.metrics()` + `ctx.bash`(只做 host 没有的 ps/df) + 轮询隐藏即停 |
|
|
11
|
+
| [review](./review/) | 代码/文本对比 + 用例表格 | 审阅/diff/用例、要编辑回写 | `DiffViewer`(original/modified) + `CodeEditor` + `DataGrid` 列筛/排序 + 写回 |
|
|
12
|
+
| [agentrun](./agentrun/) | 让模型干多步活并展示过程 | 需要 `ctx.agent`(**唯一**示范)+ 取消/进度 | `ctx.agent` + `onEvent`→storage→UI 轮询 + 模块级 `AbortController` 取消 |
|
|
13
|
+
| [jira](./jira/) | 复杂业务仿真(多视图+状态机+AI 辅助) | 工单/Jira/项目管理类、多视图、要 AI | `Kanban`+`DataGrid` 双视图 + 详情 `Sheet` 编辑 + 状态色板 + `ctx.llm` 生成用户可确认草稿 |
|
|
14
|
+
|
|
15
|
+
## 怎么用
|
|
16
|
+
|
|
17
|
+
1. **只读你需要的模板**,不要全读。按「一句话 / 什么时候抄它」定位。
|
|
18
|
+
2. 模板内带 `// ⭐ 关键:...` 的注释是**教学点** —— 扫注释就能抓到要点(如 `ctx.agent`、`storage.table`、`ctx.signal` 取消、`DiffViewer` 的 original/modified、`StatusBadge` 认小写状态)。
|
|
19
|
+
3. **通用约定**(每个都遵守,不分模板):
|
|
20
|
+
- UI 只 `import`:`react` / `@monkey-mini-app/ui` / `@monkeyagent/host` / `./lib`。禁止其它 npm(app 目录无 node_modules)。
|
|
21
|
+
- 图标:`import { Icon } from "@monkey-mini-app/ui"` → `<Icon.HelpCircle />`(常用子集见 [../references/icons.md](../references/icons.md))。空状态插图:`import { IlluServerStatus } from "@monkey-mini-app/ui"`。
|
|
22
|
+
- 唯一访问后端的入口:`useDashboardApi().call(method, args)`,method 必须是 `defineDashboard({ api })` 的键。
|
|
23
|
+
- 布局 `AppShell`(可选 `sidebar`/`header`)+ `PageHeader`(`title`/`description`/`actions`)。
|
|
24
|
+
- 列表/看板/表格数据用 `key` 字段做增删改定位。
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { defineDashboard } from "@monkeyagent/dashboard";
|
|
2
|
+
|
|
3
|
+
// ⭐ 关键:ctx.agent 是「让模型干一个多步活」的入口,返回最终 string。
|
|
4
|
+
// 过程事件经 onEvent 观测(status/tool/turn/text-delta/done),写进 storage 让 UI 轮询。
|
|
5
|
+
// 取消:用模块级 AbortController(app 模块只加载一次,var 可存);页面隐藏/停止时不空跑。
|
|
6
|
+
type Step = { phase: string; name?: string; turn?: number; text?: string; at: number };
|
|
7
|
+
|
|
8
|
+
let currentAbort: AbortController | null = null;
|
|
9
|
+
|
|
10
|
+
function pushStep(ctx, step: Step) {
|
|
11
|
+
void ctx.storage.set("step", step);
|
|
12
|
+
}
|
|
13
|
+
async function addStep(ctx, step: Step) {
|
|
14
|
+
const run = (await ctx.storage.get("run")) || { goal: "", status: "idle", steps: [], result: "", startedAt: 0 };
|
|
15
|
+
run.steps = [...(run.steps || []), step];
|
|
16
|
+
await ctx.storage.set("run", run);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export default defineDashboard({
|
|
20
|
+
name: "任务执行器",
|
|
21
|
+
description: "让模型干一个多步活,实时展示过程,可取消",
|
|
22
|
+
api: {
|
|
23
|
+
async runStatus(ctx) {
|
|
24
|
+
return (await ctx.storage.get("run")) || { goal: "", status: "idle", steps: [], result: "", startedAt: 0 };
|
|
25
|
+
},
|
|
26
|
+
|
|
27
|
+
// 启动:立即返回,后台跑 agent;progress 靠 storage + UI 轮询
|
|
28
|
+
async start(ctx, args?: { goal?: string }) {
|
|
29
|
+
const goal = String(args?.goal ?? "").trim();
|
|
30
|
+
if (!goal) throw new Error("请输入目标");
|
|
31
|
+
currentAbort?.abort();
|
|
32
|
+
const ac = new AbortController();
|
|
33
|
+
currentAbort = ac;
|
|
34
|
+
const run = { goal, status: "running", steps: [], result: "", startedAt: Date.now() };
|
|
35
|
+
await ctx.storage.set("run", run);
|
|
36
|
+
await ctx.storage.set("step", { phase: "status", text: "running", at: Date.now() });
|
|
37
|
+
|
|
38
|
+
void ctx.agent(goal, {
|
|
39
|
+
signal: ac.signal,
|
|
40
|
+
maxIterations: 12,
|
|
41
|
+
onEvent: (ev) => {
|
|
42
|
+
// ⭐ 关键:onEvent 只是观测过程,返回值仍是最终 string。这里把每个事件落 storage。
|
|
43
|
+
if (ev.type === "tool") void addStep(ctx, { phase: "tool", name: ev.name, at: Date.now() });
|
|
44
|
+
else if (ev.type === "turn") void addStep(ctx, { phase: "turn", turn: ev.turn, at: Date.now() });
|
|
45
|
+
else if (ev.type === "text-delta") setText(ctx, ev.text);
|
|
46
|
+
else if (ev.type === "done") void addStep(ctx, { phase: "done", at: Date.now() });
|
|
47
|
+
else if (ev.type === "error") void addStep(ctx, { phase: "error", text: ev.message, at: Date.now() });
|
|
48
|
+
},
|
|
49
|
+
})
|
|
50
|
+
.then(async (text) => {
|
|
51
|
+
const cur = (await ctx.storage.get("run")) || run;
|
|
52
|
+
await ctx.storage.set("run", { ...cur, status: "done", result: text.slice(-4000), steps: cur.steps || [] });
|
|
53
|
+
if (currentAbort === ac) currentAbort = null;
|
|
54
|
+
})
|
|
55
|
+
.catch(async (cause) => {
|
|
56
|
+
const msg = String((cause as Error)?.message || cause);
|
|
57
|
+
const cur = (await ctx.storage.get("run")) || run;
|
|
58
|
+
await ctx.storage.set("run", { ...cur, status: "error", result: msg, steps: cur.steps || [] });
|
|
59
|
+
if (currentAbort === ac) currentAbort = null;
|
|
60
|
+
});
|
|
61
|
+
return { ok: true, started: true };
|
|
62
|
+
},
|
|
63
|
+
|
|
64
|
+
async cancel(ctx) {
|
|
65
|
+
currentAbort?.abort();
|
|
66
|
+
currentAbort = null;
|
|
67
|
+
const cur = (await ctx.storage.get("run")) || { goal: "", status: "idle", steps: [], result: "", startedAt: 0 };
|
|
68
|
+
await ctx.storage.set("run", { ...cur, status: "cancelled" });
|
|
69
|
+
return { ok: true };
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
async function setText(ctx, delta: string) {
|
|
75
|
+
const cur = (await ctx.storage.get("run")) || { goal: "", status: "running", steps: [], result: "", startedAt: Date.now() };
|
|
76
|
+
cur.result = (cur.result || "") + delta;
|
|
77
|
+
await ctx.storage.set("run", { ...cur, steps: cur.steps || [] });
|
|
78
|
+
}
|