@downcity/plugins 1.0.10 → 1.0.20
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/bin/chat/PROMPT.direct.d.ts +1 -1
- package/bin/chat/PROMPT.direct.js +1 -1
- package/bin/chat/channels/BaseChatChannel.js +1 -1
- package/bin/chat/channels/qq/PROMPT.direct.d.ts +1 -1
- package/bin/chat/channels/qq/PROMPT.direct.js +1 -1
- package/bin/chat/runtime/ChatPluginActionRegistry.js +8 -8
- package/bin/chat/runtime/ChatSendMetadata.d.ts +1 -1
- package/bin/chat/runtime/ChatSendMetadata.js +1 -1
- package/bin/chat/runtime/DirectDispatchParser.d.ts +2 -2
- package/bin/chat/runtime/DirectDispatchParser.js +2 -2
- package/bin/chat/types/DirectDispatch.d.ts +4 -4
- package/bin/chat/types/DirectDispatch.js +1 -1
- package/bin/contact/PROMPT.d.ts +1 -1
- package/bin/contact/PROMPT.js +1 -1
- package/bin/contact/runtime/EndpointNotice.js +2 -2
- package/bin/shell/runtime/ShellRuntimeEnvironment.js +1 -1
- package/bin/skill/Command.d.ts +1 -1
- package/bin/skill/Command.js +2 -2
- package/bin/skill/PROMPT.d.ts +1 -1
- package/bin/skill/PROMPT.js +1 -1
- package/bin/task/Action.js +2 -2
- package/bin/task/PROMPT.d.ts +1 -1
- package/bin/task/PROMPT.js +1 -1
- package/bin/tts/Plugin.js +3 -3
- package/bin/tts/runtime/DependencyInstaller.d.ts +1 -1
- package/bin/tts/runtime/DependencyInstaller.js +1 -1
- package/bin/voice/runtime/DependencyInstaller.d.ts +1 -1
- package/bin/voice/runtime/DependencyInstaller.js +1 -1
- package/bin/voice/runtime/Transcriber.js +2 -2
- package/package.json +17 -17
- package/src/chat/PROMPT.direct.ts +1 -1
- package/src/chat/PROMPT.direct.ts.txt +6 -6
- package/src/chat/channels/BaseChatChannel.ts +1 -1
- package/src/chat/channels/qq/PROMPT.direct.ts +1 -1
- package/src/chat/channels/qq/PROMPT.direct.ts.txt +1 -1
- package/src/chat/runtime/ChatPluginActionRegistry.ts +8 -8
- package/src/chat/runtime/ChatSendMetadata.ts +1 -1
- package/src/chat/runtime/DirectDispatchParser.ts +2 -2
- package/src/chat/types/DirectDispatch.ts +4 -4
- package/src/contact/PROMPT.ts +1 -1
- package/src/contact/PROMPT.ts.txt +11 -11
- package/src/contact/runtime/EndpointNotice.ts +2 -2
- package/src/shell/runtime/ShellRuntimeEnvironment.ts +1 -1
- package/src/skill/Command.ts +2 -2
- package/src/skill/PROMPT.ts +1 -1
- package/src/skill/PROMPT.ts.txt +2 -2
- package/src/task/Action.ts +2 -2
- package/src/task/PROMPT.ts +1 -1
- package/src/task/PROMPT.ts.txt +9 -9
- package/src/tts/Plugin.ts +3 -3
- package/src/tts/runtime/DependencyInstaller.ts +1 -1
- package/src/voice/runtime/DependencyInstaller.ts +1 -1
- package/src/voice/runtime/Transcriber.ts +2 -2
- package/tsconfig.json +1 -0
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
* 自动生成文件,请勿手改。
|
|
3
3
|
* 源文件:由同路径 `*.ts.txt` 生成。
|
|
4
4
|
*/
|
|
5
|
-
declare const TEXT_MODULE_CONTENT = "# Chat Plugin \u4F7F\u7528\u8BF4\u660E\n\n## \u7528\u6237\u53EF\u89C1\u56DE\u590D\u89C4\u5219\n\n- \u5F53\u524D\u6A21\u5F0F\u4E0B\uFF0C\u76F4\u63A5\u8F93\u51FA\uFF0C\u5373\u4F1A\u53D1\u9001\u6D88\u606F\u7ED9\u5230\u7528\u6237\u5BF9\u5E94\u7684channel\n\n## \u8F93\u51FA\u534F\u8BAE\n\n- \u9700\u8981\u666E\u901A\u56DE\u590D\u65F6\uFF0C\u76F4\u63A5\u8F93\u51FA\u6587\u672C\u5373\u53EF\u3002\u6587\u672C\u9876\u90E8\u53EF\u7528 frontmatter metadata (optional)\uFF0C\u5B57\u6BB5\u8BED\u4E49\u4E0E `
|
|
5
|
+
declare const TEXT_MODULE_CONTENT = "# Chat Plugin \u4F7F\u7528\u8BF4\u660E\n\n## \u7528\u6237\u53EF\u89C1\u56DE\u590D\u89C4\u5219\n\n- \u5F53\u524D\u6A21\u5F0F\u4E0B\uFF0C\u76F4\u63A5\u8F93\u51FA\uFF0C\u5373\u4F1A\u53D1\u9001\u6D88\u606F\u7ED9\u5230\u7528\u6237\u5BF9\u5E94\u7684channel\n\n## \u8F93\u51FA\u534F\u8BAE\n\n- \u9700\u8981\u666E\u901A\u56DE\u590D\u65F6\uFF0C\u76F4\u63A5\u8F93\u51FA\u6587\u672C\u5373\u53EF\u3002\u6587\u672C\u9876\u90E8\u53EF\u7528 frontmatter metadata (optional)\uFF0C\u5B57\u6BB5\u8BED\u4E49\u4E0E `town chat send` \u4FDD\u6301\u4E00\u81F4\uFF1A\n\n- `delay` / `delayMs`\uFF1A\u5EF6\u8FDF\u53D1\u9001\u6BEB\u79D2\u6570\u3002\n- `time` / `sendAt` / `sendAtMs`\uFF1A\u5B9A\u65F6\u53D1\u9001\u65F6\u95F4\u3002\n- `reply`\uFF1A\u662F\u5426\u4F7F\u7528 reply \u8BED\u4E49\u53D1\u9001\u3002\n- `messageId`\uFF1A\u76EE\u6807 `message_id`\uFF08\u7FA4\u804A\u63A8\u8350\uFF09\u3002\n- `react`\uFF1A\u53D1\u9001\u8868\u60C5\u53CD\u5E94\u3002\n - \u5355\u4E2A\u5B57\u7B26\u4E32\uFF1A`react: \"\uD83D\uDC4D\"`\n - \u6216\u5BF9\u8C61/\u6570\u7EC4\uFF1A`emoji/big`\n - \u8BBE\u7F6E `messageId` \u65F6\uFF0C`react` \u4F1A\u4F18\u5148\u590D\u7528\u8BE5\u6D88\u606F\u4F5C\u4E3A\u76EE\u6807\u6D88\u606F\u3002\n- \u9644\u4EF6\u4F7F\u7528 `<file type=\"...\">path</file>`\uFF08\u652F\u6301 `document/photo/voice/audio/video`\uFF09\u3002\n- \u9644\u4EF6\u8DEF\u5F84\u5FC5\u987B\u662F\u9879\u76EE\u5185\u53EF\u8BBF\u95EE\u7684\u76F8\u5BF9\u8DEF\u5F84\u3002\u591A\u9644\u4EF6\u53EF\u8F93\u51FA\u591A\u4E2A `<file>` \u6807\u7B7E\u3002\n\n### \u793A\u4F8B\n\n```text\n---\nreply: true\nmessageId: \"128\"\nreact:\n - emoji: \"\u2705\"\n---\n\u8FD9\u662F\u4ECA\u5929\u7684\u62A5\u544A\u3002\n<file type=\"document\">reports/daily.md</file>\n```\n\n### \u534F\u8BAE\u7EA6\u675F\n\n- frontmatter \u5FC5\u987B\u4F4D\u4E8E\u6587\u672C\u6700\u5F00\u5934\uFF08`---` \u5305\u88F9\uFF09\u3002\n- \u9664 `<file>` \u9644\u4EF6\u6807\u7B7E\u5916\uFF0C\u4E0D\u8981\u4F7F\u7528\u5C16\u62EC\u53F7\u683C\u5F0F\u505A\u63A7\u5236\u53C2\u6570\u3002\n\n## \u8DE8\u534F\u8BAE/\u8DE8\u5E73\u53F0\u64CD\u4F5C\n\n- \u5F53\u4EFB\u52A1\u9700\u8981\u8DE8\u4F1A\u8BDD\u3001\u8DE8\u5E73\u53F0\u6216\u590D\u6742\u8DEF\u7531\uFF0C\u5FC5\u987B\u4F7F\u7528 `town chat send` / `town chat react`\u3002\n- metadata \u53EA\u9002\u7528\u4E8E\u5F53\u524D\u4F1A\u8BDD\u5185\u7684 direct \u51FA\u7AD9\uFF0C\u4E0D\u8981\u62FF metadata \u505A\u8DE8 chat \u8DEF\u7531\u3002\n- \u5982\u679C\u9700\u8981\u8DE8 chat \u53D1\u9001\uFF0C\u6216\u8005\u4E0D\u6E05\u695A\u600E\u4E48\u53D1\u9001\uFF0C\u76F4\u63A5\u5148\u8C03\u7528 `town chat --help` \u67E5\u770B\u65B9\u6CD5\u3002\n- \u5982\u4E0D\u786E\u5B9A\u53C2\u6570\u6216\u6B63\u6587\u534F\u8BAE\uFF0C\u5148\u81EA\u884C\u8C03\u7528\uFF1A\n - `town chat --help`\n - `town chat send --help`\n - `town chat react --help`\n\n## \u5165\u7AD9\u6D88\u606F\u7ED3\u6784\uFF08\u4EC5\u4F9B\u5185\u90E8\u7406\u89E3\uFF09\n\n- \u6BCF\u6761\u5165\u961F\u7528\u6237\u6D88\u606F\u5305\u542B `<info>...</info>` \u5143\u4FE1\u606F\u5757 + \u7528\u6237\u6B63\u6587\u3002\n- `<info>` \u4EC5\u4FDD\u7559 user/request \u5143\u4FE1\u606F\uFF0C\u4F8B\u5982 `user_id`\u3001`username`\u3001`message_id`\u3001`permissions`\u3001`received_at`\u3002\n- \u5F53\u524D chat \u8DEF\u7531\u73AF\u5883\uFF08\u4F8B\u5982 `channel`\u3001`session_id`\u3001`chat_key`\u3001`chat_id`\uFF09\u4F1A\u901A\u8FC7 system prompt \u5355\u72EC\u6CE8\u5165\uFF0C\u4E0D\u518D\u6DF7\u5728 `<info>` \u91CC\u3002\n- `<info>` \u4E0D\u8981\u539F\u6837\u56DE\u4F20\u7ED9\u7528\u6237\u3002\n";
|
|
6
6
|
export default TEXT_MODULE_CONTENT;
|
|
7
7
|
//# sourceMappingURL=PROMPT.direct.d.ts.map
|
|
@@ -3,6 +3,6 @@
|
|
|
3
3
|
* 源文件:由同路径 `*.ts.txt` 生成。
|
|
4
4
|
*/
|
|
5
5
|
// Source: src/chat/PROMPT.direct.ts.txt
|
|
6
|
-
const TEXT_MODULE_CONTENT = "# Chat Plugin 使用说明\n\n## 用户可见回复规则\n\n- 当前模式下,直接输出,即会发送消息给到用户对应的channel\n\n## 输出协议\n\n- 需要普通回复时,直接输出文本即可。文本顶部可用 frontmatter metadata (optional),字段语义与 `
|
|
6
|
+
const TEXT_MODULE_CONTENT = "# Chat Plugin 使用说明\n\n## 用户可见回复规则\n\n- 当前模式下,直接输出,即会发送消息给到用户对应的channel\n\n## 输出协议\n\n- 需要普通回复时,直接输出文本即可。文本顶部可用 frontmatter metadata (optional),字段语义与 `town chat send` 保持一致:\n\n- `delay` / `delayMs`:延迟发送毫秒数。\n- `time` / `sendAt` / `sendAtMs`:定时发送时间。\n- `reply`:是否使用 reply 语义发送。\n- `messageId`:目标 `message_id`(群聊推荐)。\n- `react`:发送表情反应。\n - 单个字符串:`react: \"👍\"`\n - 或对象/数组:`emoji/big`\n - 设置 `messageId` 时,`react` 会优先复用该消息作为目标消息。\n- 附件使用 `<file type=\"...\">path</file>`(支持 `document/photo/voice/audio/video`)。\n- 附件路径必须是项目内可访问的相对路径。多附件可输出多个 `<file>` 标签。\n\n### 示例\n\n```text\n---\nreply: true\nmessageId: \"128\"\nreact:\n - emoji: \"✅\"\n---\n这是今天的报告。\n<file type=\"document\">reports/daily.md</file>\n```\n\n### 协议约束\n\n- frontmatter 必须位于文本最开头(`---` 包裹)。\n- 除 `<file>` 附件标签外,不要使用尖括号格式做控制参数。\n\n## 跨协议/跨平台操作\n\n- 当任务需要跨会话、跨平台或复杂路由,必须使用 `town chat send` / `town chat react`。\n- metadata 只适用于当前会话内的 direct 出站,不要拿 metadata 做跨 chat 路由。\n- 如果需要跨 chat 发送,或者不清楚怎么发送,直接先调用 `town chat --help` 查看方法。\n- 如不确定参数或正文协议,先自行调用:\n - `town chat --help`\n - `town chat send --help`\n - `town chat react --help`\n\n## 入站消息结构(仅供内部理解)\n\n- 每条入队用户消息包含 `<info>...</info>` 元信息块 + 用户正文。\n- `<info>` 仅保留 user/request 元信息,例如 `user_id`、`username`、`message_id`、`permissions`、`received_at`。\n- 当前 chat 路由环境(例如 `channel`、`session_id`、`chat_key`、`chat_id`)会通过 system prompt 单独注入,不再混在 `<info>` 里。\n- `<info>` 不要原样回传给用户。\n";
|
|
7
7
|
export default TEXT_MODULE_CONTENT;
|
|
8
8
|
//# sourceMappingURL=PROMPT.direct.js.map
|
|
@@ -103,7 +103,7 @@ export class BaseChatChannel {
|
|
|
103
103
|
"当前会话权限不足,已拒绝处理。请联系管理员调整你的角色。",
|
|
104
104
|
];
|
|
105
105
|
if (userId) {
|
|
106
|
-
lines.push("", "请把下面命令发给管理员:", `
|
|
106
|
+
lines.push("", "请把下面命令发给管理员:", `town chat auth set ${this.channel}:${userId}`);
|
|
107
107
|
}
|
|
108
108
|
if (chatId || chatType) {
|
|
109
109
|
lines.push("", "来源信息:");
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
* 自动生成文件,请勿手改。
|
|
3
3
|
* 源文件:由同路径 `*.ts.txt` 生成。
|
|
4
4
|
*/
|
|
5
|
-
declare const TEXT_MODULE_CONTENT = "# QQ Adapter \u4F7F\u7528\u8BF4\u660E\uFF08direct \u6A21\u5F0F\uFF09\n\n## \u80FD\u529B\u8303\u56F4\n- \u8D1F\u8D23 QQ \u5B98\u65B9\u673A\u5668\u4EBA\u7F51\u5173\uFF08WebSocket\uFF09\u6D88\u606F\u63A5\u5165\u4E0E\u53D1\u9001\u3002\n- \u5165\u7AD9\u6D88\u606F\u4F1A\u7531 chat plugin runtime \u6620\u5C04\u5230\u5185\u90E8 `sessionId`\uFF08\u968F\u673A\u5206\u914D\u5E76\u6301\u4E45\u5316\uFF09\u3002\n\n## \u4F7F\u7528\u7EA6\u675F\n- \u5728 direct \u6A21\u5F0F\u4E0B\uFF0C\u4F60\u8F93\u51FA\u7684 assistant \u6587\u672C\u4F1A\u81EA\u52A8\u53D1\u9001\u5230\u5F53\u524D QQ \u4F1A\u8BDD\u3002\n- QQ \u51FA\u7AD9\u56DE\u590D\u4F9D\u8D56\u5165\u7AD9\u6D88\u606F\u4E0A\u4E0B\u6587\uFF08\u5982 `chatType` \u4E0E `messageId`\uFF09\uFF1B\u8DE8\u4F1A\u8BDD\u53D1\u9001\u8BF7\u4F7F\u7528 `
|
|
5
|
+
declare const TEXT_MODULE_CONTENT = "# QQ Adapter \u4F7F\u7528\u8BF4\u660E\uFF08direct \u6A21\u5F0F\uFF09\n\n## \u80FD\u529B\u8303\u56F4\n- \u8D1F\u8D23 QQ \u5B98\u65B9\u673A\u5668\u4EBA\u7F51\u5173\uFF08WebSocket\uFF09\u6D88\u606F\u63A5\u5165\u4E0E\u53D1\u9001\u3002\n- \u5165\u7AD9\u6D88\u606F\u4F1A\u7531 chat plugin runtime \u6620\u5C04\u5230\u5185\u90E8 `sessionId`\uFF08\u968F\u673A\u5206\u914D\u5E76\u6301\u4E45\u5316\uFF09\u3002\n\n## \u4F7F\u7528\u7EA6\u675F\n- \u5728 direct \u6A21\u5F0F\u4E0B\uFF0C\u4F60\u8F93\u51FA\u7684 assistant \u6587\u672C\u4F1A\u81EA\u52A8\u53D1\u9001\u5230\u5F53\u524D QQ \u4F1A\u8BDD\u3002\n- QQ \u51FA\u7AD9\u56DE\u590D\u4F9D\u8D56\u5165\u7AD9\u6D88\u606F\u4E0A\u4E0B\u6587\uFF08\u5982 `chatType` \u4E0E `messageId`\uFF09\uFF1B\u8DE8\u4F1A\u8BDD\u53D1\u9001\u8BF7\u4F7F\u7528 `town chat send --chat-key ...`\uFF0C\u4E0D\u8981\u5728 direct metadata \u4E2D\u5199 `chatKey`\u3002\n- \u7FA4\u804A\u6D88\u606F\u9ED8\u8BA4\u5168\u91CF\u63A5\u5165\uFF0C\u4E0D\u9700\u8981 `@` \u89E6\u53D1\u3002\n- \u9002\u914D\u5668\u4F1A\u8FC7\u6EE4\u673A\u5668\u4EBA\u81EA\u56DE\u73AF\u6D88\u606F\u5E76\u505A\u5165\u7AD9\u53BB\u91CD\uFF0C\u907F\u514D\u201C\u81EA\u5DF1\u56DE\u590D\u81EA\u5DF1\u201D\u7684\u5FAA\u73AF\u3002\n";
|
|
6
6
|
export default TEXT_MODULE_CONTENT;
|
|
7
7
|
//# sourceMappingURL=PROMPT.direct.d.ts.map
|
|
@@ -3,6 +3,6 @@
|
|
|
3
3
|
* 源文件:由同路径 `*.ts.txt` 生成。
|
|
4
4
|
*/
|
|
5
5
|
// Source: src/chat/channels/qq/PROMPT.direct.ts.txt
|
|
6
|
-
const TEXT_MODULE_CONTENT = "# QQ Adapter 使用说明(direct 模式)\n\n## 能力范围\n- 负责 QQ 官方机器人网关(WebSocket)消息接入与发送。\n- 入站消息会由 chat plugin runtime 映射到内部 `sessionId`(随机分配并持久化)。\n\n## 使用约束\n- 在 direct 模式下,你输出的 assistant 文本会自动发送到当前 QQ 会话。\n- QQ 出站回复依赖入站消息上下文(如 `chatType` 与 `messageId`);跨会话发送请使用 `
|
|
6
|
+
const TEXT_MODULE_CONTENT = "# QQ Adapter 使用说明(direct 模式)\n\n## 能力范围\n- 负责 QQ 官方机器人网关(WebSocket)消息接入与发送。\n- 入站消息会由 chat plugin runtime 映射到内部 `sessionId`(随机分配并持久化)。\n\n## 使用约束\n- 在 direct 模式下,你输出的 assistant 文本会自动发送到当前 QQ 会话。\n- QQ 出站回复依赖入站消息上下文(如 `chatType` 与 `messageId`);跨会话发送请使用 `town chat send --chat-key ...`,不要在 direct metadata 中写 `chatKey`。\n- 群聊消息默认全量接入,不需要 `@` 触发。\n- 适配器会过滤机器人自回环消息并做入站去重,避免“自己回复自己”的循环。\n";
|
|
7
7
|
export default TEXT_MODULE_CONTENT;
|
|
8
8
|
//# sourceMappingURL=PROMPT.direct.js.map
|
|
@@ -12,18 +12,18 @@ import { executeChatCloseAction, executeChatConfigurationAction, executeChatConf
|
|
|
12
12
|
const CHAT_SEND_HELP_TEXT = [
|
|
13
13
|
"",
|
|
14
14
|
"消息协议:",
|
|
15
|
-
" frontmatter metadata 字段语义与 `
|
|
15
|
+
" frontmatter metadata 字段语义与 `town chat send` 参数一致。",
|
|
16
16
|
" 附件使用 `<file type=\"...\">path</file>`,支持 `document/photo/voice/audio/video`。",
|
|
17
17
|
" 正文与 `<file>` 可以交错出现,运行时会按原顺序发送。",
|
|
18
18
|
"",
|
|
19
19
|
"常用示例:",
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
" cat <<'EOF' |
|
|
20
|
+
" town chat send --text 'done'",
|
|
21
|
+
" town chat send --chat-key <chatKey> --text 'done'",
|
|
22
|
+
" cat <<'EOF' | town chat send --stdin --chat-key <chatKey>",
|
|
23
23
|
" 第一行",
|
|
24
24
|
" 第二行",
|
|
25
25
|
" EOF",
|
|
26
|
-
"
|
|
26
|
+
" town chat send --text-file ./result.md --chat-key <chatKey>",
|
|
27
27
|
"",
|
|
28
28
|
"说明:",
|
|
29
29
|
" 当前会话可省略 `--chat-key`;跨 chat 发送时必须显式传 `--chat-key`。",
|
|
@@ -32,9 +32,9 @@ const CHAT_SEND_HELP_TEXT = [
|
|
|
32
32
|
const CHAT_REACT_HELP_TEXT = [
|
|
33
33
|
"",
|
|
34
34
|
"常用示例:",
|
|
35
|
-
"
|
|
36
|
-
"
|
|
37
|
-
"
|
|
35
|
+
" town chat react --emoji '👍'",
|
|
36
|
+
" town chat react --emoji '✅' --message-id <messageId>",
|
|
37
|
+
" town chat react --chat-key <chatKey> --message-id <messageId> --emoji '🔥'",
|
|
38
38
|
"",
|
|
39
39
|
"说明:",
|
|
40
40
|
" 当前会话可省略 `--chat-key`;跨 chat 操作时显式传 `--chat-key`。",
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Chat send frontmatter metadata 解析工具。
|
|
3
3
|
*
|
|
4
4
|
* 关键点(中文)
|
|
5
|
-
* - frontmatter 中的字段语义与 `
|
|
5
|
+
* - frontmatter 中的字段语义与 `town chat send` 参数保持一致。
|
|
6
6
|
* - direct 模式也复用同一解析逻辑,避免 metadata 协议分叉。
|
|
7
7
|
*/
|
|
8
8
|
import type { ChatMessageSendOptions } from "@downcity/agent/internal/executor/messages/ChatMessageMarkupTypes.js";
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* 关键点(中文)
|
|
5
5
|
* - 默认把 assistant 文本原样当作用户可见正文发送。
|
|
6
|
-
* - frontmatter metadata 语义与 `
|
|
6
|
+
* - frontmatter metadata 语义与 `town chat send` 保持一致。
|
|
7
7
|
* - 额外保留 `react` 字段用于 direct 模式贴表情。
|
|
8
8
|
*/
|
|
9
9
|
import type { ResolvedDirectDispatchPlan } from "../../chat/types/DirectDispatch.js";
|
|
@@ -11,7 +11,7 @@ import type { ResolvedDirectDispatchPlan } from "../../chat/types/DirectDispatch
|
|
|
11
11
|
* 从 assistant 文本中解析 direct 出站执行计划。
|
|
12
12
|
*
|
|
13
13
|
* 协议(中文)
|
|
14
|
-
* - frontmatter metadata:与 `
|
|
14
|
+
* - frontmatter metadata:与 `town chat send` 参数保持一致。
|
|
15
15
|
* - 附件统一使用 `<file type=\"document|photo|voice|audio|video\">path</file>`。
|
|
16
16
|
* - `react` 仍仅用于 direct 模式的反应动作。
|
|
17
17
|
*/
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* 关键点(中文)
|
|
5
5
|
* - 默认把 assistant 文本原样当作用户可见正文发送。
|
|
6
|
-
* - frontmatter metadata 语义与 `
|
|
6
|
+
* - frontmatter metadata 语义与 `town chat send` 保持一致。
|
|
7
7
|
* - 额外保留 `react` 字段用于 direct 模式贴表情。
|
|
8
8
|
*/
|
|
9
9
|
import { buildChatMessageText, parseChatMessageMarkup, } from "@downcity/agent/internal/executor/messages/ChatMessageMarkup.js";
|
|
@@ -102,7 +102,7 @@ function resolveReactionPlans(params) {
|
|
|
102
102
|
* 从 assistant 文本中解析 direct 出站执行计划。
|
|
103
103
|
*
|
|
104
104
|
* 协议(中文)
|
|
105
|
-
* - frontmatter metadata:与 `
|
|
105
|
+
* - frontmatter metadata:与 `town chat send` 参数保持一致。
|
|
106
106
|
* - 附件统一使用 `<file type=\"document|photo|voice|audio|video\">path</file>`。
|
|
107
107
|
* - `react` 仍仅用于 direct 模式的反应动作。
|
|
108
108
|
*/
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* 关键点(中文)
|
|
5
5
|
* - 仅用于当前 chat assistant 出站解析。
|
|
6
|
-
* - frontmatter metadata 语义与 `
|
|
6
|
+
* - frontmatter metadata 语义与 `town chat send` 保持一致,再额外支持 `react`。
|
|
7
7
|
*/
|
|
8
8
|
import type { ChatMessageFileTag, ChatMessageFileType } from "@downcity/agent/internal/executor/messages/ChatMessageMarkupTypes.js";
|
|
9
9
|
export type DirectFileType = ChatMessageFileType;
|
|
@@ -43,7 +43,7 @@ export interface ResolvedDirectTextPayload {
|
|
|
43
43
|
* 是否以 reply 语义发送正文。
|
|
44
44
|
*
|
|
45
45
|
* 说明(中文)
|
|
46
|
-
* - 语义与 `
|
|
46
|
+
* - 语义与 `town chat send --reply` 一致。
|
|
47
47
|
* - 当 metadata 提供 `reply: true` 或显式 `messageId` 时自动为 true。
|
|
48
48
|
*/
|
|
49
49
|
replyToMessage: boolean;
|
|
@@ -58,14 +58,14 @@ export interface ResolvedDirectTextPayload {
|
|
|
58
58
|
* 可选延迟发送毫秒数。
|
|
59
59
|
*
|
|
60
60
|
* 说明(中文)
|
|
61
|
-
* - 与 `
|
|
61
|
+
* - 与 `town chat send --delay` 对齐。
|
|
62
62
|
*/
|
|
63
63
|
delayMs?: number;
|
|
64
64
|
/**
|
|
65
65
|
* 可选定时发送毫秒时间戳。
|
|
66
66
|
*
|
|
67
67
|
* 说明(中文)
|
|
68
|
-
* - 与 `
|
|
68
|
+
* - 与 `town chat send --time` 对齐。
|
|
69
69
|
*/
|
|
70
70
|
sendAtMs?: number;
|
|
71
71
|
}
|
package/bin/contact/PROMPT.d.ts
CHANGED
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
* 自动生成文件,请勿手改。
|
|
3
3
|
* 源文件:由同路径 `*.ts.txt` 生成。
|
|
4
4
|
*/
|
|
5
|
-
declare const TEXT_MODULE_CONTENT = "Contact plugin\n\ncontact plugin \u7528\u6765\u7BA1\u7406\u548C\u5176\u4ED6 agent \u7684\u8054\u7CFB\u65B9\u5F0F\u3002\u4E00\u4E2A contact \u4EE3\u8868\u4E00\u4E2A\u5DF2\u5EFA\u7ACB\u8054\u7CFB\u7684\u8FDC\u7AEF agent\uFF0C\u5E76\u56FA\u5B9A\u62E5\u6709\u4E00\u6761\u957F\u671F\u5BF9\u8BDD\u5386\u53F2\u3002contact \u53EF\u4EE5\u662F\u5355\u5411\u7684\uFF1A\u53EA\u8981\u672C agent \u80FD\u8BBF\u95EE\u5BF9\u65B9\uFF0C\u5C31\u53EF\u4EE5 check\u3001chat\u3001share\u3002\n\n\u53EF\u7528\u547D\u4EE4\uFF1A\n- `
|
|
5
|
+
declare const TEXT_MODULE_CONTENT = "Contact plugin\n\ncontact plugin \u7528\u6765\u7BA1\u7406\u548C\u5176\u4ED6 agent \u7684\u8054\u7CFB\u65B9\u5F0F\u3002\u4E00\u4E2A contact \u4EE3\u8868\u4E00\u4E2A\u5DF2\u5EFA\u7ACB\u8054\u7CFB\u7684\u8FDC\u7AEF agent\uFF0C\u5E76\u56FA\u5B9A\u62E5\u6709\u4E00\u6761\u957F\u671F\u5BF9\u8BDD\u5386\u53F2\u3002contact \u53EF\u4EE5\u662F\u5355\u5411\u7684\uFF1A\u53EA\u8981\u672C agent \u80FD\u8BBF\u95EE\u5BF9\u65B9\uFF0C\u5C31\u53EF\u4EE5 check\u3001chat\u3001share\u3002\n\n\u53EF\u7528\u547D\u4EE4\uFF1A\n- `town contact link`\uFF1A\u751F\u6210\u4E00\u6B21\u6027\u8054\u7CFB\u7801\uFF0C\u4EA4\u7ED9\u53E6\u4E00\u4E2A agent\u3002\n- `town contact approve <code>`\uFF1A\u4F7F\u7528\u5BF9\u65B9\u7ED9\u7684\u8054\u7CFB\u7801\u5EFA\u7ACB contact\u3002\n- `town contact list`\uFF1A\u67E5\u770B\u5DF2\u4FDD\u5B58\u7684 agent \u8054\u7CFB\u65B9\u5F0F\u3002\n- `town contact check <contact>` / `town contact check --to <ip:port>`\uFF1A\u68C0\u67E5\u5BF9\u65B9\u662F\u5426\u5728\u7EBF\u53EF\u7528\u3002\n- `town contact chat --to <contact> \"<message>\"`\uFF1A\u548C\u67D0\u4E2A agent \u5BF9\u8BDD\u3002\n- `town contact share --to <contact> --text ... | --link ... | <path...>`\uFF1A\u5206\u4EAB\u6587\u672C\u3001\u94FE\u63A5\u3001\u6587\u4EF6\u6216\u76EE\u5F55\u3002\n- `town contact inbox`\uFF1A\u67E5\u770B\u6536\u5230\u7684\u5206\u4EAB\u3002\n- `town contact receive <share_id>`\uFF1A\u63A5\u6536\u67D0\u6761\u5206\u4EAB\u3002\n\n\u8FB9\u754C\uFF1A\n- chat \u7528\u4E8E\u5BF9\u8BDD\uFF0Cshare \u7528\u4E8E\u8D44\u6599\u4EA4\u63A5\u3002\n- `town contact link` \u8FD4\u56DE\u4E2D\u7684 notes \u4F1A\u8BF4\u660E\u8054\u7CFB\u7801\u9002\u5408\u672C\u673A\u3001\u5C40\u57DF\u7F51\u8FD8\u662F\u516C\u7F51 agent \u4F7F\u7528\uFF1B\u672C\u5730 localhost \u8054\u7CFB\u7801\u4E0D\u80FD\u4EA4\u7ED9 server agent approve\u3002\n- public-looking endpoint \u4ECD\u53EF\u80FD\u88AB\u9632\u706B\u5899/NAT \u963B\u65AD\uFF1B\u4EE5\u8FD4\u56DE\u7684 notes \u4E3A\u51C6\uFF0C\u4E0D\u8981\u627F\u8BFA\u516C\u7F51\u4E00\u5B9A\u53EF\u8FBE\u3002\n- `town start` \u4F1A\u81EA\u52A8\u5199\u5165 `DOWNCITY_PUBLIC_HOST` \u4F9B contact link \u4F7F\u7528\uFF1B\u8FD9\u4E0D\u662F\u8981\u6C42\u7528\u6237\u624B\u52A8\u914D\u7F6E\u7684 token \u6216 endpoint\u3002\n- `town contact approve` \u4F1A\u5148\u5EFA\u7ACB\u5355\u5411\u5173\u7CFB\uFF0C\u518D\u7531\u5BF9\u65B9\u4E3B\u52A8 ping \u56DE\u672C agent\uFF0Cping \u6210\u529F\u624D\u5347\u7EA7\u4E3A bidirectional\u3002\n- local/private agent \u8FDE\u63A5 public agent \u65F6\u901A\u5E38\u53EA\u80FD outbound-only\uFF0C\u4E0D\u8981\u8BF4\u6210\u53CC\u5411\u3002\n- contact token \u7531 link/approve \u81EA\u52A8\u4EA4\u6362\uFF1B\u4E0D\u8981\u8981\u6C42\u7528\u6237\u624B\u52A8\u914D\u7F6E token \u73AF\u5883\u53D8\u91CF\u3002\n- `Contact link not found` \u8868\u793A\u8BF7\u6C42\u6253\u5230\u7684 agent runtime \u6CA1\u6709\u8FD9\u6761 link \u8BB0\u5F55\uFF0C\u4F18\u5148\u68C0\u67E5 endpoint/\u7AEF\u53E3/agent \u662F\u5426\u4E00\u81F4\uFF1B\u8FC7\u671F\u4F1A\u660E\u786E\u8FD4\u56DE `Contact link expired`\u3002\n- receive \u53EA\u63A5\u6536\u5185\u5BB9\uFF0C\u4E0D\u81EA\u52A8\u6267\u884C\u3001\u4E0D\u5B89\u88C5 skill\u3001\u4E0D\u4FEE\u6539\u9879\u76EE\u4E1A\u52A1\u6587\u4EF6\u3002\n- \u4E0D\u81EA\u52A8 approve \u6216 receive\uFF0C\u9664\u975E\u7528\u6237\u660E\u786E\u8981\u6C42\u3002\n";
|
|
6
6
|
export default TEXT_MODULE_CONTENT;
|
|
7
7
|
//# sourceMappingURL=PROMPT.d.ts.map
|
package/bin/contact/PROMPT.js
CHANGED
|
@@ -3,6 +3,6 @@
|
|
|
3
3
|
* 源文件:由同路径 `*.ts.txt` 生成。
|
|
4
4
|
*/
|
|
5
5
|
// Source: src/contact/PROMPT.ts.txt
|
|
6
|
-
const TEXT_MODULE_CONTENT = "Contact plugin\n\ncontact plugin 用来管理和其他 agent 的联系方式。一个 contact 代表一个已建立联系的远端 agent,并固定拥有一条长期对话历史。contact 可以是单向的:只要本 agent 能访问对方,就可以 check、chat、share。\n\n可用命令:\n- `
|
|
6
|
+
const TEXT_MODULE_CONTENT = "Contact plugin\n\ncontact plugin 用来管理和其他 agent 的联系方式。一个 contact 代表一个已建立联系的远端 agent,并固定拥有一条长期对话历史。contact 可以是单向的:只要本 agent 能访问对方,就可以 check、chat、share。\n\n可用命令:\n- `town contact link`:生成一次性联系码,交给另一个 agent。\n- `town contact approve <code>`:使用对方给的联系码建立 contact。\n- `town contact list`:查看已保存的 agent 联系方式。\n- `town contact check <contact>` / `town contact check --to <ip:port>`:检查对方是否在线可用。\n- `town contact chat --to <contact> \"<message>\"`:和某个 agent 对话。\n- `town contact share --to <contact> --text ... | --link ... | <path...>`:分享文本、链接、文件或目录。\n- `town contact inbox`:查看收到的分享。\n- `town contact receive <share_id>`:接收某条分享。\n\n边界:\n- chat 用于对话,share 用于资料交接。\n- `town contact link` 返回中的 notes 会说明联系码适合本机、局域网还是公网 agent 使用;本地 localhost 联系码不能交给 server agent approve。\n- public-looking endpoint 仍可能被防火墙/NAT 阻断;以返回的 notes 为准,不要承诺公网一定可达。\n- `town start` 会自动写入 `DOWNCITY_PUBLIC_HOST` 供 contact link 使用;这不是要求用户手动配置的 token 或 endpoint。\n- `town contact approve` 会先建立单向关系,再由对方主动 ping 回本 agent,ping 成功才升级为 bidirectional。\n- local/private agent 连接 public agent 时通常只能 outbound-only,不要说成双向。\n- contact token 由 link/approve 自动交换;不要要求用户手动配置 token 环境变量。\n- `Contact link not found` 表示请求打到的 agent runtime 没有这条 link 记录,优先检查 endpoint/端口/agent 是否一致;过期会明确返回 `Contact link expired`。\n- receive 只接收内容,不自动执行、不安装 skill、不修改项目业务文件。\n- 不自动 approve 或 receive,除非用户明确要求。\n";
|
|
7
7
|
export default TEXT_MODULE_CONTENT;
|
|
8
8
|
//# sourceMappingURL=PROMPT.js.map
|
|
@@ -54,7 +54,7 @@ export function buildContactLinkNotes(params) {
|
|
|
54
54
|
if (reachability === "loopback") {
|
|
55
55
|
return [
|
|
56
56
|
"This link endpoint is local-only. Only an agent on the same machine can approve it; a server agent cannot approve a link generated by this local agent.",
|
|
57
|
-
"Start city from a reachable environment before generating a new link;
|
|
57
|
+
"Start city from a reachable environment before generating a new link; town start automatically writes the public host used by contact links when it can detect one.",
|
|
58
58
|
];
|
|
59
59
|
}
|
|
60
60
|
if (reachability === "private") {
|
|
@@ -91,7 +91,7 @@ export function buildContactApproveNotes(params) {
|
|
|
91
91
|
notes.push("This contact is outbound-only for now: this agent sent a callback candidate, but the peer has not confirmed it can ping this agent back.");
|
|
92
92
|
}
|
|
93
93
|
else {
|
|
94
|
-
notes.push("This contact is outbound-only from this side: this agent can call the peer, but the peer cannot call back unless this agent was started with a reachable address that
|
|
94
|
+
notes.push("This contact is outbound-only from this side: this agent can call the peer, but the peer cannot call back unless this agent was started with a reachable address that town start can provide to contact.");
|
|
95
95
|
}
|
|
96
96
|
return notes;
|
|
97
97
|
}
|
|
@@ -29,7 +29,7 @@ export function buildShellEnv(context) {
|
|
|
29
29
|
const configuredAgentId = String(context.config?.id || "").trim();
|
|
30
30
|
const agentId = configuredAgentId || (agentPath ? path.basename(agentPath) : "");
|
|
31
31
|
// 关键点(中文)
|
|
32
|
-
// - agent 自己在 shell 里执行 `
|
|
32
|
+
// - agent 自己在 shell 里执行 `town <service> ...` 时,也需要显式知道“当前 agent 是谁”。
|
|
33
33
|
// - 否则 service CLI 会退回到当前终端 cwd / registry 猜测,在多 agent 或外部工作目录下
|
|
34
34
|
// 很容易把请求发到错误项目,最终误报 “Agent server 没启动”。
|
|
35
35
|
if (agentPath)
|
package/bin/skill/Command.d.ts
CHANGED
package/bin/skill/Command.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `
|
|
2
|
+
* `town skill` 命令 helper。
|
|
3
3
|
*
|
|
4
4
|
* 设计目标(中文)
|
|
5
5
|
* - 尽量不自建 registry:直接复用社区的 `npx skills` 生态(find/install)。
|
|
@@ -53,7 +53,7 @@ export async function skillListCommand(cwd = ".") {
|
|
|
53
53
|
const projectRoot = path.resolve(String(cwd || "."));
|
|
54
54
|
const shipJson = path.join(projectRoot, "downcity.json");
|
|
55
55
|
if (!fs.existsSync(shipJson)) {
|
|
56
|
-
throw new Error(`downcity.json not found at ${shipJson}. Run "
|
|
56
|
+
throw new Error(`downcity.json not found at ${shipJson}. Run "town agent create" first or pass the correct path.`);
|
|
57
57
|
}
|
|
58
58
|
const config = loadDowncityConfig(projectRoot);
|
|
59
59
|
const roots = getClaudeSkillSearchRoots(projectRoot, config);
|
package/bin/skill/PROMPT.d.ts
CHANGED
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
* 自动生成文件,请勿手改。
|
|
3
3
|
* 源文件:由同路径 `*.ts.txt` 生成。
|
|
4
4
|
*/
|
|
5
|
-
declare const TEXT_MODULE_CONTENT = "# Skill Plugin\n\nskill \u662F\u4F60\u62E5\u6709\u7684\u6280\u80FD\u3002\u7528\u6237\u7684\u63D0\u51FA\u7684\u9700\u6C42\u548C\u4EFB\u52A1\uFF0C\u4F60\u90FD\u9700\u8981\u5148\u8003\u8651\u5229\u7528\u76F8\u5173\u7684skill\u6765\u9AD8\u8D28\u91CF\u7684\u5B8C\u6210\u3002\n\n\n## \u4F7F\u7528\n\n\u4F7F\u7528\u6280\u80FD\u65F6\u9700\u8981\u9996\u5148\u901A\u8FC7 `
|
|
5
|
+
declare const TEXT_MODULE_CONTENT = "# Skill Plugin\n\nskill \u662F\u4F60\u62E5\u6709\u7684\u6280\u80FD\u3002\u7528\u6237\u7684\u63D0\u51FA\u7684\u9700\u6C42\u548C\u4EFB\u52A1\uFF0C\u4F60\u90FD\u9700\u8981\u5148\u8003\u8651\u5229\u7528\u76F8\u5173\u7684skill\u6765\u9AD8\u8D28\u91CF\u7684\u5B8C\u6210\u3002\n\n\n## \u4F7F\u7528\n\n\u4F7F\u7528\u6280\u80FD\u65F6\u9700\u8981\u9996\u5148\u901A\u8FC7 `town skill lookup <name>` \u547D\u4EE4\u8F7D\u5165\u5BF9\u5E94\u7684\u6280\u80FD\u5185\u5BB9\u3002\n\n\u4F60\u4E5F\u53EF\u4EE5\u4F7F\u7528 `town skill --help` \u547D\u4EE4\u5BF9skill\u8FDB\u884C\u5176\u4ED6\u64CD\u4F5C\u3002\u6BD4\u5982 `list`, `find`, `install`\u7B49\u7B49\u3002\n";
|
|
6
6
|
export default TEXT_MODULE_CONTENT;
|
|
7
7
|
//# sourceMappingURL=PROMPT.d.ts.map
|
package/bin/skill/PROMPT.js
CHANGED
|
@@ -3,6 +3,6 @@
|
|
|
3
3
|
* 源文件:由同路径 `*.ts.txt` 生成。
|
|
4
4
|
*/
|
|
5
5
|
// Source: src/skill/PROMPT.ts.txt
|
|
6
|
-
const TEXT_MODULE_CONTENT = "# Skill Plugin\n\nskill 是你拥有的技能。用户的提出的需求和任务,你都需要先考虑利用相关的skill来高质量的完成。\n\n\n## 使用\n\n使用技能时需要首先通过 `
|
|
6
|
+
const TEXT_MODULE_CONTENT = "# Skill Plugin\n\nskill 是你拥有的技能。用户的提出的需求和任务,你都需要先考虑利用相关的skill来高质量的完成。\n\n\n## 使用\n\n使用技能时需要首先通过 `town skill lookup <name>` 命令载入对应的技能内容。\n\n你也可以使用 `town skill --help` 命令对skill进行其他操作。比如 `list`, `find`, `install`等等。\n";
|
|
7
7
|
export default TEXT_MODULE_CONTENT;
|
|
8
8
|
//# sourceMappingURL=PROMPT.js.map
|
package/bin/task/Action.js
CHANGED
|
@@ -41,7 +41,7 @@ function buildDefaultTaskBody() {
|
|
|
41
41
|
"",
|
|
42
42
|
"- 最终输出直接写结果本身,不要包多余寒暄,不要粘贴冗长日志。",
|
|
43
43
|
"- 需要结构时,优先使用短标题、要点列表、表格或 JSON 等稳定格式。",
|
|
44
|
-
"- 默认不要在正文里重复调用 `
|
|
44
|
+
"- 默认不要在正文里重复调用 `town chat send`;系统会自动发送最终结果。",
|
|
45
45
|
"",
|
|
46
46
|
"# 触发与状态建议",
|
|
47
47
|
"",
|
|
@@ -53,7 +53,7 @@ function buildDefaultTaskBody() {
|
|
|
53
53
|
"",
|
|
54
54
|
"- 当前是独立 task 上下文,不要假设仍处在原始聊天回合里。",
|
|
55
55
|
"- 尽量使用可审计的方式:关键中间产物写入 `./.downcity/task/<title>/<timestamp>/` 下的 markdown 文件。",
|
|
56
|
-
"- 如果任务明确要求跨会话、跨平台或发送额外通知,再显式调用 `
|
|
56
|
+
"- 如果任务明确要求跨会话、跨平台或发送额外通知,再显式调用 `town chat send`。",
|
|
57
57
|
"",
|
|
58
58
|
].join("\n");
|
|
59
59
|
}
|
package/bin/task/PROMPT.d.ts
CHANGED
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
* 自动生成文件,请勿手改。
|
|
3
3
|
* 源文件:由同路径 `*.ts.txt` 生成。
|
|
4
4
|
*/
|
|
5
|
-
declare const TEXT_MODULE_CONTENT = "# Task Plugin\n\n\u4F60\u53EF\u4EE5\u901A\u8FC7 `task` plugin \u7BA1\u7406\u4EFB\u52A1\u5B9A\u4E49\u3001\u6267\u884C\u3001\u8C03\u5EA6\u4E0E\u72B6\u6001\u63A7\u5236\u3002\n\n## \u4EFB\u52A1\u6A21\u578B\n\n\u6BCF\u4E2A\u4EFB\u52A1\u5B9A\u4E49\u5728 `./.downcity/task/<title>/task.md`\uFF0C\u5305\u542B\uFF1A\n- frontmatter\uFF08\u7ED3\u6784\u5316\u5B57\u6BB5\uFF09\n- body\uFF08\u4EFB\u52A1\u6B63\u6587\uFF09\n\nfrontmatter \u6838\u5FC3\u5B57\u6BB5\uFF1A\n- `title`\uFF1A\u4EFB\u52A1\u552F\u4E00\u6807\u8BC6\uFF08\u552F\u4E00\uFF09\n- `description`\uFF1A\u4EFB\u52A1\u63CF\u8FF0\n- `when`\uFF1A\u89E6\u53D1\u6761\u4EF6\uFF0C\u652F\u6301\uFF1A`@manual` / cron / `time:<ISO8601-with-timezone>`\n- `sessionId`\uFF1A\u4EFB\u52A1\u6267\u884C\u4F1A\u8BDD\n- `status`\uFF1A`enabled|paused|disabled`\n- `kind`\uFF1A`agent|script`\uFF08\u9ED8\u8BA4 `agent`\uFF09\n\n\u6267\u884C\u65F6\u4F1A\u4EA7\u751F run \u76EE\u5F55\uFF1A\n- `./.downcity/task/<title>/<timestamp>/`\n\n\u5E38\u89C1\u4EA7\u7269\uFF1A\n- `input.md`\n- `output.md`\uFF08\u672C\u6B21\u4EFB\u52A1\u7684\u6700\u7EC8\u8F93\u51FA\u6B63\u6587\uFF09\n- `result.md`\uFF08\u6267\u884C\u6458\u8981\uFF09\n- `run.json`\n- `run-progress.json`\n- `dialogue.md` / `dialogue.json`\uFF08agent \u591A\u8F6E\uFF09\n- `error.md`\uFF08\u5931\u8D25\u65F6\uFF09\n\n## \u6267\u884C\u7C7B\u578B\uFF08kind\uFF09\n\n1. `kind=agent`\n- \u5C06\u6B63\u6587\u4EA4\u7ED9 agent \u6267\u884C\n- \u9ED8\u8BA4\u5355\u8F6E\u5B8C\u6210\uFF1B\u4EC5\u5F53 frontmatter \u663E\u5F0F\u8BBE\u7F6E `review: true` \u65F6\u542F\u7528\u6A21\u62DF\u7528\u6237\u591A\u8F6E\u590D\u6838\n- \u9002\u5408\u7814\u7A76\u3001\u5206\u6790\u3001\u62A5\u544A\u751F\u6210\n\n2. `kind=script`\n- \u5C06\u6B63\u6587\u5F53\u4F5C shell \u811A\u672C\u6267\u884C\n- \u6B63\u6587\u4E0D\u80FD\u4E3A\u7A7A\uFF0C\u5FC5\u987B\u662F\u53EF\u6267\u884C\u811A\u672C\n\n## \u53EF\u7528 action\n\n- `list`\n- `create`\n- `run`\n- `delete`\n- `update`\n- `status`\n- `enable`\n- `disable`\n\n## CLI \u793A\u4F8B\n\n- `city task list [--status enabled|paused|disabled]`\n- `city task create --title '...' --description '...' --session-id <sessionId> [--when '@manual'] [--kind agent|script] [--status ...|--activate]`\n- `city task run <title> [--reason '...']`\n- `city task update <title> [--title ...] [--description ...] [--when ...] [--status ...|--activate] [--session-id ...]`\n- `city task delete <title>`\n\n## \u5173\u952E\u7EA6\u675F\n\n- `title` \u552F\u4E00\uFF1Bcreate \u53BB\u91CD\u4EC5\u6309 `title` \u7CBE\u786E\u5339\u914D\u3002\n- `when=time:...` \u89E6\u53D1\u540E\u4F1A\u81EA\u52A8\u7F6E\u4E3A `paused`\uFF0C\u5E76\u56DE\u9000\u4E3A `when=@manual`\u3002\n- `run` \u4E3A\u5F02\u6B65\u53D7\u7406\uFF1A\u7ACB\u5373\u8FD4\u56DE `accepted=true`\u3001`message`\u3001`executionId`\uFF1B\u8C03\u7528\u65B9\u5E94\u628A\u5B83\u89C6\u4E3A\u201C\u4EFB\u52A1\u5DF2\u8FDB\u5165\u540E\u53F0\u6267\u884C\uFF0C\u7ED3\u679C\u4F1A\u81EA\u52A8\u901A\u8FC7 chat plugin runtime \u53D1\u9001\uFF0C\u5F53\u524D\u6D41\u7A0B\u65E0\u9700\u963B\u585E\u7B49\u5F85\u201D\u3002\n- \u5982\u679C `run` \u8FD4\u56DE `accepted=true`\uFF1A\n - \u4E0D\u8981\u624B\u52A8\u628A task \u4EA7\u51FA\u518D\u8F6C\u53D1\u7ED9\u7528\u6237\u3002\n - \u4E0D\u8981\u4E3B\u52A8\u8BFB\u53D6 run \u76EE\u5F55\u3001`run-progress.json`\u3001`output.md` \u505A\u8F6E\u8BE2\u3002\n - \u53EA\u6709\u5F53\u7528\u6237\u660E\u786E\u8981\u6C42\u6392\u67E5\u3001\u67E5\u770B\u4EA7\u7269\u6216\u786E\u8BA4\u6267\u884C\u7EC6\u8282\u65F6\uFF0C\u624D\u8FDB\u5165 run \u76EE\u5F55\u68C0\u67E5\u3002\n- agent \u4EFB\u52A1\u9ED8\u8BA4\u53EA\u8981\u6C42\u4EA7\u751F\u6709\u6548\u8F93\u51FA\uFF1B\u4EC5\u5F53\u4EFB\u52A1\u6B63\u6587\u660E\u786E\u8981\u6C42\u5916\u53D1\u65F6\uFF0C\u624D\u5E94\u53D1\u9001\u5230\u5916\u90E8 channel\u3002\n\n## \u5982\u4F55\u8BBE\u8BA1 task \u6B63\u6587\n\n### agent task \u63A8\u8350\u7ED3\u6784\n\n\u5EFA\u8BAE\u6B63\u6587\u81F3\u5C11\u5305\u542B\u8FD9\u4E9B\u6807\u9898\uFF1A\n\n```md\n# \u4EFB\u52A1\u76EE\u6807\n\n- \u8FD9\u6B21\u4EFB\u52A1\u8981\u4EA4\u4ED8\u4EC0\u4E48\u6700\u7EC8\u7ED3\u679C\n\n# \u80CC\u666F\u4E0E\u8F93\u5165\n\n- \u6570\u636E\u6765\u6E90\u3001\u8303\u56F4\u3001\u7EA6\u675F\u3001\u53C2\u8003\u6750\u6599\n\n# \u6267\u884C\u6B65\u9AA4\n\n1. \u5148\u505A\u4EC0\u4E48\n2. \u518D\u505A\u4EC0\u4E48\n3. \u5173\u952E\u4E2D\u95F4\u4EA7\u7269\u843D\u5728\u54EA\u91CC\n\n# \u8F93\u51FA\u8981\u6C42\n\n- \u6700\u7EC8\u7ED3\u679C\u7528\u4EC0\u4E48\u683C\u5F0F\u8FD4\u56DE\n- \u662F\u5426\u9700\u8981\u8868\u683C / JSON / Markdown\n- \u4E0D\u8981\u5305\u542B\u4EC0\u4E48\u5185\u5BB9\n\n# \u89E6\u53D1\u4E0E\u72B6\u6001\u5EFA\u8BAE\n\n- \u8FD9\u4E2A\u4EFB\u52A1\u4E3A\u4EC0\u4E48\u9002\u5408 `@manual` / cron / `time:...`\n- \u5F53\u524D\u5E94\u8BE5\u662F `paused` \u8FD8\u662F `enabled`\n\n# \u6CE8\u610F\u4E8B\u9879\n\n- \u98CE\u9669\u3001\u8FB9\u754C\u3001\u4E0D\u8981\u505A\u4EC0\u4E48\n```\n\n### agent task \u6B63\u6587\u7F16\u5199\u7EA6\u675F\n\n- task \u6B63\u6587\u5FC5\u987B\u50CF\u4E00\u4EFD\u201C\u4EA4\u4ED8\u5408\u540C\u201D\uFF0C\u8BA9\u53E6\u4E00\u4E2A\u6267\u884C\u5668\u62FF\u5230\u540E\u53EF\u4EE5\u76F4\u63A5\u6267\u884C\uFF0C\u4E0D\u4F9D\u8D56\u5F53\u524D\u804A\u5929\u8BED\u5883\u8865\u5168\u542B\u4E49\u3002\n- `# \u4EFB\u52A1\u76EE\u6807` \u5FC5\u987B\u5199\u6E05\u695A\u6700\u7EC8\u8981\u4EA4\u4ED8\u4EC0\u4E48\uFF0C\u4E0D\u8981\u53EA\u5199\u201C\u770B\u4E00\u4E0B\u201D\u201C\u7814\u7A76\u4E00\u4E0B\u201D\u201C\u5904\u7406\u4E00\u4E0B\u201D\u8FD9\u7C7B\u6A21\u7CCA\u76EE\u6807\u3002\n- `# \u80CC\u666F\u4E0E\u8F93\u5165` \u5FC5\u987B\u5199\u6E05\u6765\u6E90\u3001\u8303\u56F4\u3001\u5BF9\u8C61\u3001\u65F6\u95F4\u3001\u9650\u5236\u6761\u4EF6\uFF1B\u4E0D\u8981\u5047\u8BBE\u6267\u884C\u5668\u8FD8\u80FD\u770B\u5230\u539F\u59CB\u804A\u5929\u4E0A\u4E0B\u6587\u3002\n- `# \u6267\u884C\u6B65\u9AA4` \u5E94\u63CF\u8FF0\u4EFB\u52A1\u6D41\u7A0B\uFF0C\u4E0D\u5E94\u63CF\u8FF0 task \u7BA1\u7406\u52A8\u4F5C\uFF1B\u4E0D\u8981\u5199\u201C\u5148\u68C0\u67E5\u6709\u6CA1\u6709\u540C\u540D\u4EFB\u52A1\u201D\u201C\u518D\u521B\u5EFA\u4EFB\u52A1\u201D\u201C\u7136\u540E\u89E6\u53D1\u4EFB\u52A1\u201D\u3002\n- `# \u8F93\u51FA\u8981\u6C42` \u5FC5\u987B\u6E05\u695A\u58F0\u660E\u6700\u7EC8\u6210\u54C1\u7684\u683C\u5F0F\u3001\u7ED3\u6784\u3001\u8BED\u6C14\u3001\u957F\u5EA6\uFF0C\u4EE5\u53CA\u201C\u4E0D\u8981\u8F93\u51FA\u4EC0\u4E48\u201D\u3002\n- \u8981\u660E\u786E\u5199\u51FA\uFF1A**\u6700\u540E\u4E00\u6761 assistant \u8FD4\u56DE\u4F1A\u88AB\u76F4\u63A5\u5199\u5165 `output.md` \u5E76\u53D1\u9001\u7ED9\u7528\u6237**\uFF1B\u56E0\u6B64\u6700\u7EC8\u56DE\u7B54\u5FC5\u987B\u76F4\u63A5\u7B49\u4E8E\u6210\u54C1\u5185\u5BB9\u3002\n- \u5185\u5BB9\u751F\u6210\u7C7B\u4EFB\u52A1\uFF08\u5982\u65E5\u62A5\u3001\u63D0\u9192\u3001\u6668\u8BFB\u3001\u6458\u8981\u3001\u62A5\u544A\uFF09\u5FC5\u987B\u660E\u786E\u8981\u6C42\u201C\u6700\u7EC8\u8F93\u51FA\u76F4\u63A5\u662F\u6210\u54C1\u6B63\u6587\u201D\uFF0C\u4E0D\u8981\u8BA9\u6267\u884C\u5668\u8F93\u51FA\u8FC7\u7A0B\u8BF4\u660E\u3002\n- \u5982\u679C\u4EFB\u52A1\u8981\u628A\u7ED3\u679C\u53D1\u7ED9\u7528\u6237\uFF0C\u6B63\u6587\u5E94\u8981\u6C42\u201C\u8F93\u51FA\u53EF\u76F4\u63A5\u53D1\u9001\u7684\u6B63\u6587\u5185\u5BB9\u201D\uFF0C\u800C\u4E0D\u662F\u8981\u6C42\u6267\u884C\u5668\u89E3\u91CA\u81EA\u5DF1\u5DF2\u7ECF\u53D1\u9001\u4E86\u4EC0\u4E48\u3002\n- \u9664\u975E\u786E\u6709\u9700\u8981\uFF0C\u4E0D\u8981\u5728\u6B63\u6587\u4E2D\u8981\u6C42\u6267\u884C\u5668\u590D\u8FF0 task title\u3001sessionId\u3001\u6267\u884C\u65F6\u95F4\u3001\u72B6\u6001\u7B49\u5143\u4FE1\u606F\u3002\n- \u6B63\u6587\u4E2D\u7684\u7EA6\u675F\u8981\u53EF\u6267\u884C\u3001\u53EF\u5224\u65AD\uFF0C\u5C3D\u91CF\u907F\u514D\u201C\u9002\u5F53\u201D\u201C\u5C3D\u91CF\u201D\u201C\u770B\u60C5\u51B5\u201D\u8FD9\u7C7B\u5F31\u7EA6\u675F\u8BCD\u3002\n- \u4E0D\u8981\u628A\u521B\u5EFA task\u3001\u66F4\u65B0 task\u3001\u67E5\u770B task \u72B6\u6001\u3001\u786E\u8BA4 task \u662F\u5426\u5B58\u5728\u7B49\u7BA1\u7406\u52A8\u4F5C\u5199\u8FDB\u6B63\u6587\uFF1B\u8FD9\u4E9B\u5C5E\u4E8E task plugin \u7684\u804C\u8D23\uFF0C\u4E0D\u5C5E\u4E8E task \u6B63\u6587\u4EA4\u4ED8\u7269\u3002\n\n### agent task \u6B63\u6587\u7981\u6B62\u5199\u6CD5\n\n- \u4E0D\u8981\u628A\u6B63\u6587\u5199\u6210\u804A\u5929\u56DE\u590D\u53E3\u543B\uFF0C\u4F8B\u5982\uFF1A\n - \u201C\u6211\u6765\u4E3A\u4F60\u2026\u2026\u201D\n - \u201C\u9996\u5148\u8BA9\u6211\u2026\u2026\u201D\n - \u201C\u6211\u5148\u68C0\u67E5\u4E00\u4E0B\u2026\u2026\u201D\n - \u201C\u6211\u770B\u5230\u5DF2\u7ECF\u6709\u4E00\u4E2A\u540C\u540D\u4EFB\u52A1\u2026\u2026\u201D\n- \u4E0D\u8981\u628A\u6B63\u6587\u5199\u6210\u4EFB\u52A1\u7BA1\u7406\u8BF4\u660E\uFF0C\u4F8B\u5982\uFF1A\n - \u201C\u5982\u679C\u4EFB\u52A1\u5DF2\u5B58\u5728\u5219\u66F4\u65B0\uFF0C\u5426\u5219\u521B\u5EFA\u201D\n - \u201C\u5148 list \u518D run\u201D\n - \u201C\u5B8C\u6210\u540E\u544A\u8BC9\u7528\u6237\u4EFB\u52A1\u5DF2\u542F\u52A8\u201D\n- \u4E0D\u8981\u628A\u6B63\u6587\u5199\u6210\u72B6\u6001\u6C47\u62A5\u6A21\u677F\uFF0C\u4F8B\u5982\uFF1A\n - \u201C\u4EFB\u52A1\u72B6\u6001\u603B\u7ED3\u201D\n - \u201C\u5DF2\u53D1\u9001 / \u5DF2\u5B8C\u6210 / \u5DF2\u66F4\u65B0\u201D\n - \u201C\u5F53\u524D\u4EFB\u52A1\u914D\u7F6E\u5982\u4E0B\u201D\n- \u4E0D\u8981\u53EA\u63CF\u8FF0\u52A8\u4F5C\uFF0C\u4E0D\u63CF\u8FF0\u6210\u54C1\uFF0C\u4F8B\u5982\uFF1A\n - \u201C\u53BB\u641C\u96C6\u4E00\u4E9B\u8D44\u6599\u201D\n - \u201C\u751F\u6210\u4E00\u4E2A\u5185\u5BB9\u770B\u770B\u201D\n - \u201C\u505A\u5B8C\u540E\u53CD\u9988\u7ED3\u679C\u201D\n- \u4E0D\u8981\u628A\u6B63\u6587\u5199\u6210\u4F9D\u8D56\u5F53\u524D\u4E0A\u4E0B\u6587\u7684\u6307\u4EE3\uFF0C\u4F8B\u5982\uFF1A\n - \u201C\u6309\u4E0A\u9762\u8BF4\u7684\u505A\u201D\n - \u201C\u7EE7\u7EED\u521A\u624D\u90A3\u4E2A\u201D\n - \u201C\u628A\u8FD9\u4E2A\u53D1\u51FA\u53BB\u201D\n\n### \u5982\u4F55\u5224\u65AD\u6B63\u6587\u5199\u5F97\u5BF9\u4E0D\u5BF9\n\n- \u5982\u679C\u628A task \u6B63\u6587\u5355\u72EC\u590D\u5236\u51FA\u6765\u7ED9\u53E6\u4E00\u4E2A agent\uFF0C\u5B83\u4ECD\u7136\u80FD\u7406\u89E3\u4EFB\u52A1\u76EE\u6807\u3001\u8F93\u5165\u3001\u6B65\u9AA4\u548C\u4EA4\u4ED8\u7269\uFF0C\u8BF4\u660E\u6B63\u6587\u5408\u683C\u3002\n- \u5982\u679C\u6700\u7EC8\u8F93\u51FA\u7AE0\u8282\u5220\u6389\u540E\uFF0C\u6B63\u6587\u53EA\u5269\u201C\u53BB\u505A\u4E00\u4E0B\u201D\u5F0F\u63CF\u8FF0\uFF0C\u8BF4\u660E\u6B63\u6587\u4E0D\u5408\u683C\u3002\n- \u5982\u679C\u6B63\u6587\u66F4\u50CF\u201C\u521B\u5EFA/\u66F4\u65B0\u4EFB\u52A1\u7684\u64CD\u4F5C\u8BF4\u660E\u201D\uFF0C\u800C\u4E0D\u662F\u201C\u4EFB\u52A1\u6267\u884C\u8BF4\u660E\u201D\uFF0C\u8BF4\u660E\u5206\u5C42\u9519\u4E86\uFF0C\u5FC5\u987B\u91CD\u5199\u3002\n- \u5982\u679C\u6B63\u6587\u5929\u7136\u4F1A\u8BF1\u5BFC\u6267\u884C\u5668\u8F93\u51FA\u8FC7\u7A0B\u6C47\u62A5\uFF0C\u800C\u4E0D\u662F\u6700\u7EC8\u6210\u54C1\uFF0C\u8BF4\u660E `# \u8F93\u51FA\u8981\u6C42` \u5199\u5F97\u4E0D\u591F\u5F3A\uFF0C\u5FC5\u987B\u8865\u5145\u7981\u6B62\u9879\u3002\n\n### script task \u63A8\u8350\u7ED3\u6784\n\n- \u6B63\u6587\u5FC5\u987B\u662F\u7EAF shell \u811A\u672C\uFF0C\u4E0D\u8981\u6DF7\u5165\u89E3\u91CA\u6027\u81EA\u7136\u8BED\u8A00\u3002\n- \u5F00\u5934\u5C3D\u91CF\u5199\u6CE8\u91CA\u8BF4\u660E\u811A\u672C\u76EE\u7684\u3001\u8F93\u5165\u4F9D\u8D56\u3001\u5931\u8D25\u6761\u4EF6\u3002\n- \u8F93\u51FA\u4FDD\u6301\u7A33\u5B9A\uFF0C\u4FBF\u4E8E\u76F4\u63A5\u4F5C\u4E3A\u6700\u7EC8\u7ED3\u679C\u53D1\u9001\u7ED9\u7528\u6237\u3002\n- \u5982\u9700\u751F\u6210\u6587\u4EF6\uFF0C\u5199\u5230 run \u76EE\u5F55\u6216\u660E\u786E\u7684\u9879\u76EE\u8DEF\u5F84\u3002\n\n### \u8F93\u51FA\u8BBE\u8BA1\u539F\u5219\n\n- task \u5B8C\u6210\u540E\uFF0C\u7CFB\u7EDF\u4F1A\u81EA\u52A8\u628A**\u6700\u7EC8\u7ED3\u679C\u6B63\u6587**\u901A\u8FC7 chat plugin runtime \u7684 `send` \u53D1\u56DE `sessionId` \u7ED1\u5B9A\u7684 chat\u3002\n- \u5F53\u524D\u5B9E\u73B0\u91C7\u7528\u6700\u7B80\u89C4\u5219\uFF1A**\u6700\u540E\u4E00\u6761 assistant \u8FD4\u56DE**\u4F1A\u88AB\u76F4\u63A5\u89C6\u4E3A\u6700\u7EC8\u7ED3\u679C\u6B63\u6587\uFF0C\u5E76\u5199\u5165 `output.md`\u3002\n- \u56E0\u6B64\u6B63\u6587\u91CC\u7684\u201C\u8F93\u51FA\u8981\u6C42\u201D\u8981\u9762\u5411\u6700\u7EC8\u7528\u6237\u9605\u8BFB\uFF0C\u4E0D\u8981\u53EA\u5199\u7ED9\u5F00\u53D1\u8005\u770B\u3002\n- \u5BF9\u4E8E\u9762\u5411\u7528\u6237\u7684 agent task\uFF0C\u6B63\u6587\u5E94\u8981\u6C42\u201C\u6700\u540E\u4E00\u6761 assistant \u8FD4\u56DE\u76F4\u63A5\u8F93\u51FA\u6700\u7EC8\u4EA4\u4ED8\u7269\u672C\u8EAB\u201D\uFF0C\u4E0D\u8981\u8BA9\u6267\u884C\u5668\u5728\u6700\u540E\u56DE\u7B54\u91CC\u8F93\u51FA\u81EA\u5DF1\u5982\u4F55\u521B\u5EFA\u3001\u68C0\u67E5\u3001\u66F4\u65B0\u3001\u89E6\u53D1\u6216\u53D1\u9001\u4EFB\u52A1\u3002\n- \u5982\u679C\u4EFB\u52A1\u662F\u5185\u5BB9\u751F\u6210\u7C7B\uFF08\u4F8B\u5982\u65E5\u62A5\u3001\u63D0\u9192\u3001\u6668\u8BFB\u3001\u6458\u8981\uFF09\uFF0C\u6700\u540E\u8F93\u51FA\u5E94\u76F4\u63A5\u662F\u90A3\u6BB5\u5185\u5BB9\u672C\u8EAB\uFF0C\u4E0D\u8981\u9644\u5E26\u201C\u6211\u6765\u4E3A\u4F60\u5904\u7406\u201D\u201C\u4EFB\u52A1\u5DF2\u53D1\u9001\u201D\u201C\u4EFB\u52A1\u72B6\u6001\u603B\u7ED3\u201D\u7B49\u8FC7\u7A0B\u6C47\u62A5\u3002\n- \u9ED8\u8BA4\u4E0D\u8981\u5728\u6B63\u6587\u91CC\u518D\u6B21\u8981\u6C42\u6267\u884C\u5668\u8C03\u7528 `city chat send`\u3002\n- \u53EA\u6709\u5728\u201C\u8DE8\u4F1A\u8BDD\u53D1\u9001\u201D\u201C\u989D\u5916\u6284\u9001\u201D\u201C\u591A\u6E20\u9053\u901A\u77E5\u201D\u8FD9\u7C7B\u573A\u666F\u4E0B\uFF0C\u624D\u663E\u5F0F\u8981\u6C42 `city chat send`\u3002\n\n### `when` / `status` \u600E\u4E48\u9009\n\n- task \u521B\u5EFA\u9ED8\u8BA4\u5C31\u662F `status=enabled`\uFF1B\u5982\u679C\u8FD8\u5728\u8BD5\u4EFB\u52A1\u3001\u5BB9\u6613\u5931\u8D25\u3001\u9700\u8981\u4EBA\u5DE5\u786E\u8BA4\uFF0C\u518D\u663E\u5F0F\u5207\u5230 `paused`\u3002\n- \u5DF2\u7ECF\u9A8C\u8BC1\u7A33\u5B9A\u3001\u9700\u8981\u81EA\u52A8\u8FD0\u884C\uFF1A\u76F4\u63A5\u4F7F\u7528 cron + `status=enabled`\u3002\n- \u660E\u786E\u53EA\u6267\u884C\u4E00\u6B21\uFF1A\u4F7F\u7528 `time:<\u5E26\u65F6\u533A ISO \u65F6\u95F4>`\uFF1B\u6267\u884C\u540E\u7CFB\u7EDF\u4F1A\u81EA\u52A8\u56DE\u9000\u5230 `@manual` + `paused`\u3002\n- \u5982\u679C\u7528\u6237\u53EA\u662F\u201C\u5148\u5B58\u8D77\u6765\u4EE5\u540E\u518D\u8DD1\u201D\uFF0C\u4E0D\u8981\u76F4\u63A5\u542F\u7528\u8C03\u5EA6\u3002\n\n## \u6B63\u6587\u6A21\u677F\n\n### agent \u6A21\u677F\n\n```md\n# \u4EFB\u52A1\u76EE\u6807\n\n- \u4EA7\u51FA\u4E00\u4EFD\u53EF\u76F4\u63A5\u53D1\u7ED9\u7528\u6237\u7684\u6700\u7EC8\u7ED3\u679C\u3002\n\n# \u80CC\u666F\u4E0E\u8F93\u5165\n\n- \u5728\u8FD9\u91CC\u8865\u5145\u4E0A\u4E0B\u6587\u3001\u6587\u4EF6\u3001\u94FE\u63A5\u3001\u8303\u56F4\u548C\u5047\u8BBE\u3002\n\n# \u6267\u884C\u6B65\u9AA4\n\n1. \u7406\u89E3\u4EFB\u52A1\u76EE\u6807\u4E0E\u5B8C\u6210\u6807\u51C6\u3002\n2. \u6536\u96C6\u5FC5\u8981\u4FE1\u606F\u5E76\u6267\u884C\u4EFB\u52A1\u3002\n3. \u628A\u5173\u952E\u4E2D\u95F4\u4EA7\u7269\u5199\u5165 run \u76EE\u5F55\u3002\n4. \u8F93\u51FA\u6700\u7EC8\u7ED3\u679C\u6B63\u6587\u3002\n\n# \u8F93\u51FA\u8981\u6C42\n\n- \u6700\u540E\u4E00\u6761 assistant \u8FD4\u56DE\u76F4\u63A5\u4F5C\u4E3A\u6700\u7EC8\u7ED3\u679C\uFF0C\u4E0D\u8981\u9644\u5E26\u5197\u957F\u65E5\u5FD7\u3002\n- \u6700\u540E\u4E00\u6761 assistant \u8FD4\u56DE\u76F4\u63A5\u8F93\u51FA\u4EA4\u4ED8\u7269\u672C\u8EAB\uFF0C\u4E0D\u8981\u8F93\u51FA\u4EFB\u52A1\u7BA1\u7406\u8FC7\u7A0B\u3001\u53D1\u9001\u8FC7\u7A0B\u6216\u72B6\u6001\u6C47\u62A5\u3002\n- \u4E0D\u8981\u4F7F\u7528\u201C\u6211\u6765\u4E3A\u4F60\u2026\u2026 / \u9996\u5148\u8BA9\u6211\u2026\u2026 / \u5DF2\u53D1\u9001\u2026\u2026\u201D\u8FD9\u7C7B\u5143\u8BDD\u672F\u3002\n- \u9ED8\u8BA4\u4E0D\u8981\u518D\u6B21\u8C03\u7528 `city chat send`\u3002\n\n# \u89E6\u53D1\u4E0E\u72B6\u6001\u5EFA\u8BAE\n\n- \u9ED8\u8BA4\u521B\u5EFA\u540E\u7ACB\u5373\u542F\u7528\uFF1B\u5982\u679C\u53EA\u662F\u5148\u4FDD\u5B58\u8349\u7A3F\u6216\u7B49\u5F85\u4EBA\u5DE5\u786E\u8BA4\uFF0C\u518D\u6539\u6210 `paused`\u3002\n\n# \u6CE8\u610F\u4E8B\u9879\n\n- \u4EC5\u5728\u660E\u786E\u9700\u8981\u8DE8\u4F1A\u8BDD\u6216\u989D\u5916\u901A\u77E5\u65F6\uFF0C\u624D\u8C03\u7528 `city chat send`\u3002\n```\n\n### script \u6A21\u677F\n\n```bash\n# \u4EFB\u52A1\u76EE\u6807\uFF1A\u4E00\u53E5\u8BDD\u8BF4\u660E\u811A\u672C\u8981\u505A\u4EC0\u4E48\n# \u8F93\u5165\u4F9D\u8D56\uFF1A\u5217\u51FA\u73AF\u5883\u53D8\u91CF\u3001\u6587\u4EF6\u3001\u547D\u4EE4\u4F9D\u8D56\n# \u5931\u8D25\u6761\u4EF6\uFF1A\u5217\u51FA\u5E94\u8BE5 exit 1 \u7684\u60C5\u51B5\n\nset -euo pipefail\n\n# 1. \u51C6\u5907\u8F93\u5165\n\n# 2. \u6267\u884C\u4E3B\u903B\u8F91\n\n# 3. \u8F93\u51FA\u6700\u7EC8\u7ED3\u679C\uFF08\u8FD9\u6BB5\u8F93\u51FA\u4F1A\u88AB\u76F4\u63A5\u53D1\u9001\u7ED9\u7528\u6237\uFF09\n```\n\n## \u5EFA\u8BAE\n\n- \u5148 `list`\uFF0C\u518D `create`/`update`\u3002\n- \u7B80\u5355\u5185\u5BB9\u751F\u6210\u4EFB\u52A1\u4F18\u5148\u4FDD\u6301\u9ED8\u8BA4\u5355\u8F6E\uFF1B\u53EA\u6709\u786E\u5B9E\u9700\u8981\u201C\u5148\u751F\u6210\u3001\u518D\u590D\u6838\u3001\u518D\u4FEE\u8BA2\u201D\u65F6\u518D\u8BBE\u7F6E `review: true`\u3002\n- script \u4EFB\u52A1\u6B63\u6587\u4FDD\u6301\u7EAF\u811A\u672C\uFF0C\u4E0D\u8981\u6DF7\u5165\u5197\u4F59\u81EA\u7136\u8BED\u8A00\u3002\n- \u5982\u679C\u7528\u6237\u53EA\u662F\u5148\u5B58\u8D77\u6765\u4EE5\u540E\u518D\u8DD1\uFF0C\u521B\u5EFA\u540E\u663E\u5F0F\u8BBE\u6210 `paused`\uFF1B\u5426\u5219\u4FDD\u6301\u9ED8\u8BA4\u542F\u7528\u3002\n- task \u6B63\u6587\u8981\u5199\u201C\u6700\u7EC8\u7ED3\u679C\u957F\u4EC0\u4E48\u6837\u201D\uFF0C\u4E0D\u8981\u53EA\u5199\u201C\u53BB\u505A\u4E00\u4E0B\u770B\u770B\u201D\u3002\n- \u5BF9\u5185\u5BB9\u751F\u6210\u4EFB\u52A1\uFF0C\u8981\u660E\u786E\u5199\u201C\u6700\u540E\u4E00\u6761 assistant \u8FD4\u56DE\u53EA\u80FD\u662F\u6210\u54C1\u6B63\u6587\u201D\uFF0C\u907F\u514D\u6267\u884C\u5668\u628A\u8FC7\u7A0B\u8BF4\u660E\u8BEF\u5F53\u6210\u6700\u7EC8\u7ED3\u679C\u3002\n";
|
|
5
|
+
declare const TEXT_MODULE_CONTENT = "# Task Plugin\n\n\u4F60\u53EF\u4EE5\u901A\u8FC7 `task` plugin \u7BA1\u7406\u4EFB\u52A1\u5B9A\u4E49\u3001\u6267\u884C\u3001\u8C03\u5EA6\u4E0E\u72B6\u6001\u63A7\u5236\u3002\n\n## \u4EFB\u52A1\u6A21\u578B\n\n\u6BCF\u4E2A\u4EFB\u52A1\u5B9A\u4E49\u5728 `./.downcity/task/<title>/task.md`\uFF0C\u5305\u542B\uFF1A\n- frontmatter\uFF08\u7ED3\u6784\u5316\u5B57\u6BB5\uFF09\n- body\uFF08\u4EFB\u52A1\u6B63\u6587\uFF09\n\nfrontmatter \u6838\u5FC3\u5B57\u6BB5\uFF1A\n- `title`\uFF1A\u4EFB\u52A1\u552F\u4E00\u6807\u8BC6\uFF08\u552F\u4E00\uFF09\n- `description`\uFF1A\u4EFB\u52A1\u63CF\u8FF0\n- `when`\uFF1A\u89E6\u53D1\u6761\u4EF6\uFF0C\u652F\u6301\uFF1A`@manual` / cron / `time:<ISO8601-with-timezone>`\n- `sessionId`\uFF1A\u4EFB\u52A1\u6267\u884C\u4F1A\u8BDD\n- `status`\uFF1A`enabled|paused|disabled`\n- `kind`\uFF1A`agent|script`\uFF08\u9ED8\u8BA4 `agent`\uFF09\n\n\u6267\u884C\u65F6\u4F1A\u4EA7\u751F run \u76EE\u5F55\uFF1A\n- `./.downcity/task/<title>/<timestamp>/`\n\n\u5E38\u89C1\u4EA7\u7269\uFF1A\n- `input.md`\n- `output.md`\uFF08\u672C\u6B21\u4EFB\u52A1\u7684\u6700\u7EC8\u8F93\u51FA\u6B63\u6587\uFF09\n- `result.md`\uFF08\u6267\u884C\u6458\u8981\uFF09\n- `run.json`\n- `run-progress.json`\n- `dialogue.md` / `dialogue.json`\uFF08agent \u591A\u8F6E\uFF09\n- `error.md`\uFF08\u5931\u8D25\u65F6\uFF09\n\n## \u6267\u884C\u7C7B\u578B\uFF08kind\uFF09\n\n1. `kind=agent`\n- \u5C06\u6B63\u6587\u4EA4\u7ED9 agent \u6267\u884C\n- \u9ED8\u8BA4\u5355\u8F6E\u5B8C\u6210\uFF1B\u4EC5\u5F53 frontmatter \u663E\u5F0F\u8BBE\u7F6E `review: true` \u65F6\u542F\u7528\u6A21\u62DF\u7528\u6237\u591A\u8F6E\u590D\u6838\n- \u9002\u5408\u7814\u7A76\u3001\u5206\u6790\u3001\u62A5\u544A\u751F\u6210\n\n2. `kind=script`\n- \u5C06\u6B63\u6587\u5F53\u4F5C shell \u811A\u672C\u6267\u884C\n- \u6B63\u6587\u4E0D\u80FD\u4E3A\u7A7A\uFF0C\u5FC5\u987B\u662F\u53EF\u6267\u884C\u811A\u672C\n\n## \u53EF\u7528 action\n\n- `list`\n- `create`\n- `run`\n- `delete`\n- `update`\n- `status`\n- `enable`\n- `disable`\n\n## CLI \u793A\u4F8B\n\n- `town task list [--status enabled|paused|disabled]`\n- `town task create --title '...' --description '...' --session-id <sessionId> [--when '@manual'] [--kind agent|script] [--status ...|--activate]`\n- `town task run <title> [--reason '...']`\n- `town task update <title> [--title ...] [--description ...] [--when ...] [--status ...|--activate] [--session-id ...]`\n- `town task delete <title>`\n\n## \u5173\u952E\u7EA6\u675F\n\n- `title` \u552F\u4E00\uFF1Bcreate \u53BB\u91CD\u4EC5\u6309 `title` \u7CBE\u786E\u5339\u914D\u3002\n- `when=time:...` \u89E6\u53D1\u540E\u4F1A\u81EA\u52A8\u7F6E\u4E3A `paused`\uFF0C\u5E76\u56DE\u9000\u4E3A `when=@manual`\u3002\n- `run` \u4E3A\u5F02\u6B65\u53D7\u7406\uFF1A\u7ACB\u5373\u8FD4\u56DE `accepted=true`\u3001`message`\u3001`executionId`\uFF1B\u8C03\u7528\u65B9\u5E94\u628A\u5B83\u89C6\u4E3A\u201C\u4EFB\u52A1\u5DF2\u8FDB\u5165\u540E\u53F0\u6267\u884C\uFF0C\u7ED3\u679C\u4F1A\u81EA\u52A8\u901A\u8FC7 chat plugin runtime \u53D1\u9001\uFF0C\u5F53\u524D\u6D41\u7A0B\u65E0\u9700\u963B\u585E\u7B49\u5F85\u201D\u3002\n- \u5982\u679C `run` \u8FD4\u56DE `accepted=true`\uFF1A\n - \u4E0D\u8981\u624B\u52A8\u628A task \u4EA7\u51FA\u518D\u8F6C\u53D1\u7ED9\u7528\u6237\u3002\n - \u4E0D\u8981\u4E3B\u52A8\u8BFB\u53D6 run \u76EE\u5F55\u3001`run-progress.json`\u3001`output.md` \u505A\u8F6E\u8BE2\u3002\n - \u53EA\u6709\u5F53\u7528\u6237\u660E\u786E\u8981\u6C42\u6392\u67E5\u3001\u67E5\u770B\u4EA7\u7269\u6216\u786E\u8BA4\u6267\u884C\u7EC6\u8282\u65F6\uFF0C\u624D\u8FDB\u5165 run \u76EE\u5F55\u68C0\u67E5\u3002\n- agent \u4EFB\u52A1\u9ED8\u8BA4\u53EA\u8981\u6C42\u4EA7\u751F\u6709\u6548\u8F93\u51FA\uFF1B\u4EC5\u5F53\u4EFB\u52A1\u6B63\u6587\u660E\u786E\u8981\u6C42\u5916\u53D1\u65F6\uFF0C\u624D\u5E94\u53D1\u9001\u5230\u5916\u90E8 channel\u3002\n\n## \u5982\u4F55\u8BBE\u8BA1 task \u6B63\u6587\n\n### agent task \u63A8\u8350\u7ED3\u6784\n\n\u5EFA\u8BAE\u6B63\u6587\u81F3\u5C11\u5305\u542B\u8FD9\u4E9B\u6807\u9898\uFF1A\n\n```md\n# \u4EFB\u52A1\u76EE\u6807\n\n- \u8FD9\u6B21\u4EFB\u52A1\u8981\u4EA4\u4ED8\u4EC0\u4E48\u6700\u7EC8\u7ED3\u679C\n\n# \u80CC\u666F\u4E0E\u8F93\u5165\n\n- \u6570\u636E\u6765\u6E90\u3001\u8303\u56F4\u3001\u7EA6\u675F\u3001\u53C2\u8003\u6750\u6599\n\n# \u6267\u884C\u6B65\u9AA4\n\n1. \u5148\u505A\u4EC0\u4E48\n2. \u518D\u505A\u4EC0\u4E48\n3. \u5173\u952E\u4E2D\u95F4\u4EA7\u7269\u843D\u5728\u54EA\u91CC\n\n# \u8F93\u51FA\u8981\u6C42\n\n- \u6700\u7EC8\u7ED3\u679C\u7528\u4EC0\u4E48\u683C\u5F0F\u8FD4\u56DE\n- \u662F\u5426\u9700\u8981\u8868\u683C / JSON / Markdown\n- \u4E0D\u8981\u5305\u542B\u4EC0\u4E48\u5185\u5BB9\n\n# \u89E6\u53D1\u4E0E\u72B6\u6001\u5EFA\u8BAE\n\n- \u8FD9\u4E2A\u4EFB\u52A1\u4E3A\u4EC0\u4E48\u9002\u5408 `@manual` / cron / `time:...`\n- \u5F53\u524D\u5E94\u8BE5\u662F `paused` \u8FD8\u662F `enabled`\n\n# \u6CE8\u610F\u4E8B\u9879\n\n- \u98CE\u9669\u3001\u8FB9\u754C\u3001\u4E0D\u8981\u505A\u4EC0\u4E48\n```\n\n### agent task \u6B63\u6587\u7F16\u5199\u7EA6\u675F\n\n- task \u6B63\u6587\u5FC5\u987B\u50CF\u4E00\u4EFD\u201C\u4EA4\u4ED8\u5408\u540C\u201D\uFF0C\u8BA9\u53E6\u4E00\u4E2A\u6267\u884C\u5668\u62FF\u5230\u540E\u53EF\u4EE5\u76F4\u63A5\u6267\u884C\uFF0C\u4E0D\u4F9D\u8D56\u5F53\u524D\u804A\u5929\u8BED\u5883\u8865\u5168\u542B\u4E49\u3002\n- `# \u4EFB\u52A1\u76EE\u6807` \u5FC5\u987B\u5199\u6E05\u695A\u6700\u7EC8\u8981\u4EA4\u4ED8\u4EC0\u4E48\uFF0C\u4E0D\u8981\u53EA\u5199\u201C\u770B\u4E00\u4E0B\u201D\u201C\u7814\u7A76\u4E00\u4E0B\u201D\u201C\u5904\u7406\u4E00\u4E0B\u201D\u8FD9\u7C7B\u6A21\u7CCA\u76EE\u6807\u3002\n- `# \u80CC\u666F\u4E0E\u8F93\u5165` \u5FC5\u987B\u5199\u6E05\u6765\u6E90\u3001\u8303\u56F4\u3001\u5BF9\u8C61\u3001\u65F6\u95F4\u3001\u9650\u5236\u6761\u4EF6\uFF1B\u4E0D\u8981\u5047\u8BBE\u6267\u884C\u5668\u8FD8\u80FD\u770B\u5230\u539F\u59CB\u804A\u5929\u4E0A\u4E0B\u6587\u3002\n- `# \u6267\u884C\u6B65\u9AA4` \u5E94\u63CF\u8FF0\u4EFB\u52A1\u6D41\u7A0B\uFF0C\u4E0D\u5E94\u63CF\u8FF0 task \u7BA1\u7406\u52A8\u4F5C\uFF1B\u4E0D\u8981\u5199\u201C\u5148\u68C0\u67E5\u6709\u6CA1\u6709\u540C\u540D\u4EFB\u52A1\u201D\u201C\u518D\u521B\u5EFA\u4EFB\u52A1\u201D\u201C\u7136\u540E\u89E6\u53D1\u4EFB\u52A1\u201D\u3002\n- `# \u8F93\u51FA\u8981\u6C42` \u5FC5\u987B\u6E05\u695A\u58F0\u660E\u6700\u7EC8\u6210\u54C1\u7684\u683C\u5F0F\u3001\u7ED3\u6784\u3001\u8BED\u6C14\u3001\u957F\u5EA6\uFF0C\u4EE5\u53CA\u201C\u4E0D\u8981\u8F93\u51FA\u4EC0\u4E48\u201D\u3002\n- \u8981\u660E\u786E\u5199\u51FA\uFF1A**\u6700\u540E\u4E00\u6761 assistant \u8FD4\u56DE\u4F1A\u88AB\u76F4\u63A5\u5199\u5165 `output.md` \u5E76\u53D1\u9001\u7ED9\u7528\u6237**\uFF1B\u56E0\u6B64\u6700\u7EC8\u56DE\u7B54\u5FC5\u987B\u76F4\u63A5\u7B49\u4E8E\u6210\u54C1\u5185\u5BB9\u3002\n- \u5185\u5BB9\u751F\u6210\u7C7B\u4EFB\u52A1\uFF08\u5982\u65E5\u62A5\u3001\u63D0\u9192\u3001\u6668\u8BFB\u3001\u6458\u8981\u3001\u62A5\u544A\uFF09\u5FC5\u987B\u660E\u786E\u8981\u6C42\u201C\u6700\u7EC8\u8F93\u51FA\u76F4\u63A5\u662F\u6210\u54C1\u6B63\u6587\u201D\uFF0C\u4E0D\u8981\u8BA9\u6267\u884C\u5668\u8F93\u51FA\u8FC7\u7A0B\u8BF4\u660E\u3002\n- \u5982\u679C\u4EFB\u52A1\u8981\u628A\u7ED3\u679C\u53D1\u7ED9\u7528\u6237\uFF0C\u6B63\u6587\u5E94\u8981\u6C42\u201C\u8F93\u51FA\u53EF\u76F4\u63A5\u53D1\u9001\u7684\u6B63\u6587\u5185\u5BB9\u201D\uFF0C\u800C\u4E0D\u662F\u8981\u6C42\u6267\u884C\u5668\u89E3\u91CA\u81EA\u5DF1\u5DF2\u7ECF\u53D1\u9001\u4E86\u4EC0\u4E48\u3002\n- \u9664\u975E\u786E\u6709\u9700\u8981\uFF0C\u4E0D\u8981\u5728\u6B63\u6587\u4E2D\u8981\u6C42\u6267\u884C\u5668\u590D\u8FF0 task title\u3001sessionId\u3001\u6267\u884C\u65F6\u95F4\u3001\u72B6\u6001\u7B49\u5143\u4FE1\u606F\u3002\n- \u6B63\u6587\u4E2D\u7684\u7EA6\u675F\u8981\u53EF\u6267\u884C\u3001\u53EF\u5224\u65AD\uFF0C\u5C3D\u91CF\u907F\u514D\u201C\u9002\u5F53\u201D\u201C\u5C3D\u91CF\u201D\u201C\u770B\u60C5\u51B5\u201D\u8FD9\u7C7B\u5F31\u7EA6\u675F\u8BCD\u3002\n- \u4E0D\u8981\u628A\u521B\u5EFA task\u3001\u66F4\u65B0 task\u3001\u67E5\u770B task \u72B6\u6001\u3001\u786E\u8BA4 task \u662F\u5426\u5B58\u5728\u7B49\u7BA1\u7406\u52A8\u4F5C\u5199\u8FDB\u6B63\u6587\uFF1B\u8FD9\u4E9B\u5C5E\u4E8E task plugin \u7684\u804C\u8D23\uFF0C\u4E0D\u5C5E\u4E8E task \u6B63\u6587\u4EA4\u4ED8\u7269\u3002\n\n### agent task \u6B63\u6587\u7981\u6B62\u5199\u6CD5\n\n- \u4E0D\u8981\u628A\u6B63\u6587\u5199\u6210\u804A\u5929\u56DE\u590D\u53E3\u543B\uFF0C\u4F8B\u5982\uFF1A\n - \u201C\u6211\u6765\u4E3A\u4F60\u2026\u2026\u201D\n - \u201C\u9996\u5148\u8BA9\u6211\u2026\u2026\u201D\n - \u201C\u6211\u5148\u68C0\u67E5\u4E00\u4E0B\u2026\u2026\u201D\n - \u201C\u6211\u770B\u5230\u5DF2\u7ECF\u6709\u4E00\u4E2A\u540C\u540D\u4EFB\u52A1\u2026\u2026\u201D\n- \u4E0D\u8981\u628A\u6B63\u6587\u5199\u6210\u4EFB\u52A1\u7BA1\u7406\u8BF4\u660E\uFF0C\u4F8B\u5982\uFF1A\n - \u201C\u5982\u679C\u4EFB\u52A1\u5DF2\u5B58\u5728\u5219\u66F4\u65B0\uFF0C\u5426\u5219\u521B\u5EFA\u201D\n - \u201C\u5148 list \u518D run\u201D\n - \u201C\u5B8C\u6210\u540E\u544A\u8BC9\u7528\u6237\u4EFB\u52A1\u5DF2\u542F\u52A8\u201D\n- \u4E0D\u8981\u628A\u6B63\u6587\u5199\u6210\u72B6\u6001\u6C47\u62A5\u6A21\u677F\uFF0C\u4F8B\u5982\uFF1A\n - \u201C\u4EFB\u52A1\u72B6\u6001\u603B\u7ED3\u201D\n - \u201C\u5DF2\u53D1\u9001 / \u5DF2\u5B8C\u6210 / \u5DF2\u66F4\u65B0\u201D\n - \u201C\u5F53\u524D\u4EFB\u52A1\u914D\u7F6E\u5982\u4E0B\u201D\n- \u4E0D\u8981\u53EA\u63CF\u8FF0\u52A8\u4F5C\uFF0C\u4E0D\u63CF\u8FF0\u6210\u54C1\uFF0C\u4F8B\u5982\uFF1A\n - \u201C\u53BB\u641C\u96C6\u4E00\u4E9B\u8D44\u6599\u201D\n - \u201C\u751F\u6210\u4E00\u4E2A\u5185\u5BB9\u770B\u770B\u201D\n - \u201C\u505A\u5B8C\u540E\u53CD\u9988\u7ED3\u679C\u201D\n- \u4E0D\u8981\u628A\u6B63\u6587\u5199\u6210\u4F9D\u8D56\u5F53\u524D\u4E0A\u4E0B\u6587\u7684\u6307\u4EE3\uFF0C\u4F8B\u5982\uFF1A\n - \u201C\u6309\u4E0A\u9762\u8BF4\u7684\u505A\u201D\n - \u201C\u7EE7\u7EED\u521A\u624D\u90A3\u4E2A\u201D\n - \u201C\u628A\u8FD9\u4E2A\u53D1\u51FA\u53BB\u201D\n\n### \u5982\u4F55\u5224\u65AD\u6B63\u6587\u5199\u5F97\u5BF9\u4E0D\u5BF9\n\n- \u5982\u679C\u628A task \u6B63\u6587\u5355\u72EC\u590D\u5236\u51FA\u6765\u7ED9\u53E6\u4E00\u4E2A agent\uFF0C\u5B83\u4ECD\u7136\u80FD\u7406\u89E3\u4EFB\u52A1\u76EE\u6807\u3001\u8F93\u5165\u3001\u6B65\u9AA4\u548C\u4EA4\u4ED8\u7269\uFF0C\u8BF4\u660E\u6B63\u6587\u5408\u683C\u3002\n- \u5982\u679C\u6700\u7EC8\u8F93\u51FA\u7AE0\u8282\u5220\u6389\u540E\uFF0C\u6B63\u6587\u53EA\u5269\u201C\u53BB\u505A\u4E00\u4E0B\u201D\u5F0F\u63CF\u8FF0\uFF0C\u8BF4\u660E\u6B63\u6587\u4E0D\u5408\u683C\u3002\n- \u5982\u679C\u6B63\u6587\u66F4\u50CF\u201C\u521B\u5EFA/\u66F4\u65B0\u4EFB\u52A1\u7684\u64CD\u4F5C\u8BF4\u660E\u201D\uFF0C\u800C\u4E0D\u662F\u201C\u4EFB\u52A1\u6267\u884C\u8BF4\u660E\u201D\uFF0C\u8BF4\u660E\u5206\u5C42\u9519\u4E86\uFF0C\u5FC5\u987B\u91CD\u5199\u3002\n- \u5982\u679C\u6B63\u6587\u5929\u7136\u4F1A\u8BF1\u5BFC\u6267\u884C\u5668\u8F93\u51FA\u8FC7\u7A0B\u6C47\u62A5\uFF0C\u800C\u4E0D\u662F\u6700\u7EC8\u6210\u54C1\uFF0C\u8BF4\u660E `# \u8F93\u51FA\u8981\u6C42` \u5199\u5F97\u4E0D\u591F\u5F3A\uFF0C\u5FC5\u987B\u8865\u5145\u7981\u6B62\u9879\u3002\n\n### script task \u63A8\u8350\u7ED3\u6784\n\n- \u6B63\u6587\u5FC5\u987B\u662F\u7EAF shell \u811A\u672C\uFF0C\u4E0D\u8981\u6DF7\u5165\u89E3\u91CA\u6027\u81EA\u7136\u8BED\u8A00\u3002\n- \u5F00\u5934\u5C3D\u91CF\u5199\u6CE8\u91CA\u8BF4\u660E\u811A\u672C\u76EE\u7684\u3001\u8F93\u5165\u4F9D\u8D56\u3001\u5931\u8D25\u6761\u4EF6\u3002\n- \u8F93\u51FA\u4FDD\u6301\u7A33\u5B9A\uFF0C\u4FBF\u4E8E\u76F4\u63A5\u4F5C\u4E3A\u6700\u7EC8\u7ED3\u679C\u53D1\u9001\u7ED9\u7528\u6237\u3002\n- \u5982\u9700\u751F\u6210\u6587\u4EF6\uFF0C\u5199\u5230 run \u76EE\u5F55\u6216\u660E\u786E\u7684\u9879\u76EE\u8DEF\u5F84\u3002\n\n### \u8F93\u51FA\u8BBE\u8BA1\u539F\u5219\n\n- task \u5B8C\u6210\u540E\uFF0C\u7CFB\u7EDF\u4F1A\u81EA\u52A8\u628A**\u6700\u7EC8\u7ED3\u679C\u6B63\u6587**\u901A\u8FC7 chat plugin runtime \u7684 `send` \u53D1\u56DE `sessionId` \u7ED1\u5B9A\u7684 chat\u3002\n- \u5F53\u524D\u5B9E\u73B0\u91C7\u7528\u6700\u7B80\u89C4\u5219\uFF1A**\u6700\u540E\u4E00\u6761 assistant \u8FD4\u56DE**\u4F1A\u88AB\u76F4\u63A5\u89C6\u4E3A\u6700\u7EC8\u7ED3\u679C\u6B63\u6587\uFF0C\u5E76\u5199\u5165 `output.md`\u3002\n- \u56E0\u6B64\u6B63\u6587\u91CC\u7684\u201C\u8F93\u51FA\u8981\u6C42\u201D\u8981\u9762\u5411\u6700\u7EC8\u7528\u6237\u9605\u8BFB\uFF0C\u4E0D\u8981\u53EA\u5199\u7ED9\u5F00\u53D1\u8005\u770B\u3002\n- \u5BF9\u4E8E\u9762\u5411\u7528\u6237\u7684 agent task\uFF0C\u6B63\u6587\u5E94\u8981\u6C42\u201C\u6700\u540E\u4E00\u6761 assistant \u8FD4\u56DE\u76F4\u63A5\u8F93\u51FA\u6700\u7EC8\u4EA4\u4ED8\u7269\u672C\u8EAB\u201D\uFF0C\u4E0D\u8981\u8BA9\u6267\u884C\u5668\u5728\u6700\u540E\u56DE\u7B54\u91CC\u8F93\u51FA\u81EA\u5DF1\u5982\u4F55\u521B\u5EFA\u3001\u68C0\u67E5\u3001\u66F4\u65B0\u3001\u89E6\u53D1\u6216\u53D1\u9001\u4EFB\u52A1\u3002\n- \u5982\u679C\u4EFB\u52A1\u662F\u5185\u5BB9\u751F\u6210\u7C7B\uFF08\u4F8B\u5982\u65E5\u62A5\u3001\u63D0\u9192\u3001\u6668\u8BFB\u3001\u6458\u8981\uFF09\uFF0C\u6700\u540E\u8F93\u51FA\u5E94\u76F4\u63A5\u662F\u90A3\u6BB5\u5185\u5BB9\u672C\u8EAB\uFF0C\u4E0D\u8981\u9644\u5E26\u201C\u6211\u6765\u4E3A\u4F60\u5904\u7406\u201D\u201C\u4EFB\u52A1\u5DF2\u53D1\u9001\u201D\u201C\u4EFB\u52A1\u72B6\u6001\u603B\u7ED3\u201D\u7B49\u8FC7\u7A0B\u6C47\u62A5\u3002\n- \u9ED8\u8BA4\u4E0D\u8981\u5728\u6B63\u6587\u91CC\u518D\u6B21\u8981\u6C42\u6267\u884C\u5668\u8C03\u7528 `town chat send`\u3002\n- \u53EA\u6709\u5728\u201C\u8DE8\u4F1A\u8BDD\u53D1\u9001\u201D\u201C\u989D\u5916\u6284\u9001\u201D\u201C\u591A\u6E20\u9053\u901A\u77E5\u201D\u8FD9\u7C7B\u573A\u666F\u4E0B\uFF0C\u624D\u663E\u5F0F\u8981\u6C42 `town chat send`\u3002\n\n### `when` / `status` \u600E\u4E48\u9009\n\n- task \u521B\u5EFA\u9ED8\u8BA4\u5C31\u662F `status=enabled`\uFF1B\u5982\u679C\u8FD8\u5728\u8BD5\u4EFB\u52A1\u3001\u5BB9\u6613\u5931\u8D25\u3001\u9700\u8981\u4EBA\u5DE5\u786E\u8BA4\uFF0C\u518D\u663E\u5F0F\u5207\u5230 `paused`\u3002\n- \u5DF2\u7ECF\u9A8C\u8BC1\u7A33\u5B9A\u3001\u9700\u8981\u81EA\u52A8\u8FD0\u884C\uFF1A\u76F4\u63A5\u4F7F\u7528 cron + `status=enabled`\u3002\n- \u660E\u786E\u53EA\u6267\u884C\u4E00\u6B21\uFF1A\u4F7F\u7528 `time:<\u5E26\u65F6\u533A ISO \u65F6\u95F4>`\uFF1B\u6267\u884C\u540E\u7CFB\u7EDF\u4F1A\u81EA\u52A8\u56DE\u9000\u5230 `@manual` + `paused`\u3002\n- \u5982\u679C\u7528\u6237\u53EA\u662F\u201C\u5148\u5B58\u8D77\u6765\u4EE5\u540E\u518D\u8DD1\u201D\uFF0C\u4E0D\u8981\u76F4\u63A5\u542F\u7528\u8C03\u5EA6\u3002\n\n## \u6B63\u6587\u6A21\u677F\n\n### agent \u6A21\u677F\n\n```md\n# \u4EFB\u52A1\u76EE\u6807\n\n- \u4EA7\u51FA\u4E00\u4EFD\u53EF\u76F4\u63A5\u53D1\u7ED9\u7528\u6237\u7684\u6700\u7EC8\u7ED3\u679C\u3002\n\n# \u80CC\u666F\u4E0E\u8F93\u5165\n\n- \u5728\u8FD9\u91CC\u8865\u5145\u4E0A\u4E0B\u6587\u3001\u6587\u4EF6\u3001\u94FE\u63A5\u3001\u8303\u56F4\u548C\u5047\u8BBE\u3002\n\n# \u6267\u884C\u6B65\u9AA4\n\n1. \u7406\u89E3\u4EFB\u52A1\u76EE\u6807\u4E0E\u5B8C\u6210\u6807\u51C6\u3002\n2. \u6536\u96C6\u5FC5\u8981\u4FE1\u606F\u5E76\u6267\u884C\u4EFB\u52A1\u3002\n3. \u628A\u5173\u952E\u4E2D\u95F4\u4EA7\u7269\u5199\u5165 run \u76EE\u5F55\u3002\n4. \u8F93\u51FA\u6700\u7EC8\u7ED3\u679C\u6B63\u6587\u3002\n\n# \u8F93\u51FA\u8981\u6C42\n\n- \u6700\u540E\u4E00\u6761 assistant \u8FD4\u56DE\u76F4\u63A5\u4F5C\u4E3A\u6700\u7EC8\u7ED3\u679C\uFF0C\u4E0D\u8981\u9644\u5E26\u5197\u957F\u65E5\u5FD7\u3002\n- \u6700\u540E\u4E00\u6761 assistant \u8FD4\u56DE\u76F4\u63A5\u8F93\u51FA\u4EA4\u4ED8\u7269\u672C\u8EAB\uFF0C\u4E0D\u8981\u8F93\u51FA\u4EFB\u52A1\u7BA1\u7406\u8FC7\u7A0B\u3001\u53D1\u9001\u8FC7\u7A0B\u6216\u72B6\u6001\u6C47\u62A5\u3002\n- \u4E0D\u8981\u4F7F\u7528\u201C\u6211\u6765\u4E3A\u4F60\u2026\u2026 / \u9996\u5148\u8BA9\u6211\u2026\u2026 / \u5DF2\u53D1\u9001\u2026\u2026\u201D\u8FD9\u7C7B\u5143\u8BDD\u672F\u3002\n- \u9ED8\u8BA4\u4E0D\u8981\u518D\u6B21\u8C03\u7528 `town chat send`\u3002\n\n# \u89E6\u53D1\u4E0E\u72B6\u6001\u5EFA\u8BAE\n\n- \u9ED8\u8BA4\u521B\u5EFA\u540E\u7ACB\u5373\u542F\u7528\uFF1B\u5982\u679C\u53EA\u662F\u5148\u4FDD\u5B58\u8349\u7A3F\u6216\u7B49\u5F85\u4EBA\u5DE5\u786E\u8BA4\uFF0C\u518D\u6539\u6210 `paused`\u3002\n\n# \u6CE8\u610F\u4E8B\u9879\n\n- \u4EC5\u5728\u660E\u786E\u9700\u8981\u8DE8\u4F1A\u8BDD\u6216\u989D\u5916\u901A\u77E5\u65F6\uFF0C\u624D\u8C03\u7528 `town chat send`\u3002\n```\n\n### script \u6A21\u677F\n\n```bash\n# \u4EFB\u52A1\u76EE\u6807\uFF1A\u4E00\u53E5\u8BDD\u8BF4\u660E\u811A\u672C\u8981\u505A\u4EC0\u4E48\n# \u8F93\u5165\u4F9D\u8D56\uFF1A\u5217\u51FA\u73AF\u5883\u53D8\u91CF\u3001\u6587\u4EF6\u3001\u547D\u4EE4\u4F9D\u8D56\n# \u5931\u8D25\u6761\u4EF6\uFF1A\u5217\u51FA\u5E94\u8BE5 exit 1 \u7684\u60C5\u51B5\n\nset -euo pipefail\n\n# 1. \u51C6\u5907\u8F93\u5165\n\n# 2. \u6267\u884C\u4E3B\u903B\u8F91\n\n# 3. \u8F93\u51FA\u6700\u7EC8\u7ED3\u679C\uFF08\u8FD9\u6BB5\u8F93\u51FA\u4F1A\u88AB\u76F4\u63A5\u53D1\u9001\u7ED9\u7528\u6237\uFF09\n```\n\n## \u5EFA\u8BAE\n\n- \u5148 `list`\uFF0C\u518D `create`/`update`\u3002\n- \u7B80\u5355\u5185\u5BB9\u751F\u6210\u4EFB\u52A1\u4F18\u5148\u4FDD\u6301\u9ED8\u8BA4\u5355\u8F6E\uFF1B\u53EA\u6709\u786E\u5B9E\u9700\u8981\u201C\u5148\u751F\u6210\u3001\u518D\u590D\u6838\u3001\u518D\u4FEE\u8BA2\u201D\u65F6\u518D\u8BBE\u7F6E `review: true`\u3002\n- script \u4EFB\u52A1\u6B63\u6587\u4FDD\u6301\u7EAF\u811A\u672C\uFF0C\u4E0D\u8981\u6DF7\u5165\u5197\u4F59\u81EA\u7136\u8BED\u8A00\u3002\n- \u5982\u679C\u7528\u6237\u53EA\u662F\u5148\u5B58\u8D77\u6765\u4EE5\u540E\u518D\u8DD1\uFF0C\u521B\u5EFA\u540E\u663E\u5F0F\u8BBE\u6210 `paused`\uFF1B\u5426\u5219\u4FDD\u6301\u9ED8\u8BA4\u542F\u7528\u3002\n- task \u6B63\u6587\u8981\u5199\u201C\u6700\u7EC8\u7ED3\u679C\u957F\u4EC0\u4E48\u6837\u201D\uFF0C\u4E0D\u8981\u53EA\u5199\u201C\u53BB\u505A\u4E00\u4E0B\u770B\u770B\u201D\u3002\n- \u5BF9\u5185\u5BB9\u751F\u6210\u4EFB\u52A1\uFF0C\u8981\u660E\u786E\u5199\u201C\u6700\u540E\u4E00\u6761 assistant \u8FD4\u56DE\u53EA\u80FD\u662F\u6210\u54C1\u6B63\u6587\u201D\uFF0C\u907F\u514D\u6267\u884C\u5668\u628A\u8FC7\u7A0B\u8BF4\u660E\u8BEF\u5F53\u6210\u6700\u7EC8\u7ED3\u679C\u3002\n";
|
|
6
6
|
export default TEXT_MODULE_CONTENT;
|
|
7
7
|
//# sourceMappingURL=PROMPT.d.ts.map
|
package/bin/task/PROMPT.js
CHANGED
|
@@ -3,6 +3,6 @@
|
|
|
3
3
|
* 源文件:由同路径 `*.ts.txt` 生成。
|
|
4
4
|
*/
|
|
5
5
|
// Source: src/task/PROMPT.ts.txt
|
|
6
|
-
const TEXT_MODULE_CONTENT = "# Task Plugin\n\n你可以通过 `task` plugin 管理任务定义、执行、调度与状态控制。\n\n## 任务模型\n\n每个任务定义在 `./.downcity/task/<title>/task.md`,包含:\n- frontmatter(结构化字段)\n- body(任务正文)\n\nfrontmatter 核心字段:\n- `title`:任务唯一标识(唯一)\n- `description`:任务描述\n- `when`:触发条件,支持:`@manual` / cron / `time:<ISO8601-with-timezone>`\n- `sessionId`:任务执行会话\n- `status`:`enabled|paused|disabled`\n- `kind`:`agent|script`(默认 `agent`)\n\n执行时会产生 run 目录:\n- `./.downcity/task/<title>/<timestamp>/`\n\n常见产物:\n- `input.md`\n- `output.md`(本次任务的最终输出正文)\n- `result.md`(执行摘要)\n- `run.json`\n- `run-progress.json`\n- `dialogue.md` / `dialogue.json`(agent 多轮)\n- `error.md`(失败时)\n\n## 执行类型(kind)\n\n1. `kind=agent`\n- 将正文交给 agent 执行\n- 默认单轮完成;仅当 frontmatter 显式设置 `review: true` 时启用模拟用户多轮复核\n- 适合研究、分析、报告生成\n\n2. `kind=script`\n- 将正文当作 shell 脚本执行\n- 正文不能为空,必须是可执行脚本\n\n## 可用 action\n\n- `list`\n- `create`\n- `run`\n- `delete`\n- `update`\n- `status`\n- `enable`\n- `disable`\n\n## CLI 示例\n\n- `
|
|
6
|
+
const TEXT_MODULE_CONTENT = "# Task Plugin\n\n你可以通过 `task` plugin 管理任务定义、执行、调度与状态控制。\n\n## 任务模型\n\n每个任务定义在 `./.downcity/task/<title>/task.md`,包含:\n- frontmatter(结构化字段)\n- body(任务正文)\n\nfrontmatter 核心字段:\n- `title`:任务唯一标识(唯一)\n- `description`:任务描述\n- `when`:触发条件,支持:`@manual` / cron / `time:<ISO8601-with-timezone>`\n- `sessionId`:任务执行会话\n- `status`:`enabled|paused|disabled`\n- `kind`:`agent|script`(默认 `agent`)\n\n执行时会产生 run 目录:\n- `./.downcity/task/<title>/<timestamp>/`\n\n常见产物:\n- `input.md`\n- `output.md`(本次任务的最终输出正文)\n- `result.md`(执行摘要)\n- `run.json`\n- `run-progress.json`\n- `dialogue.md` / `dialogue.json`(agent 多轮)\n- `error.md`(失败时)\n\n## 执行类型(kind)\n\n1. `kind=agent`\n- 将正文交给 agent 执行\n- 默认单轮完成;仅当 frontmatter 显式设置 `review: true` 时启用模拟用户多轮复核\n- 适合研究、分析、报告生成\n\n2. `kind=script`\n- 将正文当作 shell 脚本执行\n- 正文不能为空,必须是可执行脚本\n\n## 可用 action\n\n- `list`\n- `create`\n- `run`\n- `delete`\n- `update`\n- `status`\n- `enable`\n- `disable`\n\n## CLI 示例\n\n- `town task list [--status enabled|paused|disabled]`\n- `town task create --title '...' --description '...' --session-id <sessionId> [--when '@manual'] [--kind agent|script] [--status ...|--activate]`\n- `town task run <title> [--reason '...']`\n- `town task update <title> [--title ...] [--description ...] [--when ...] [--status ...|--activate] [--session-id ...]`\n- `town task delete <title>`\n\n## 关键约束\n\n- `title` 唯一;create 去重仅按 `title` 精确匹配。\n- `when=time:...` 触发后会自动置为 `paused`,并回退为 `when=@manual`。\n- `run` 为异步受理:立即返回 `accepted=true`、`message`、`executionId`;调用方应把它视为“任务已进入后台执行,结果会自动通过 chat plugin runtime 发送,当前流程无需阻塞等待”。\n- 如果 `run` 返回 `accepted=true`:\n - 不要手动把 task 产出再转发给用户。\n - 不要主动读取 run 目录、`run-progress.json`、`output.md` 做轮询。\n - 只有当用户明确要求排查、查看产物或确认执行细节时,才进入 run 目录检查。\n- agent 任务默认只要求产生有效输出;仅当任务正文明确要求外发时,才应发送到外部 channel。\n\n## 如何设计 task 正文\n\n### agent task 推荐结构\n\n建议正文至少包含这些标题:\n\n```md\n# 任务目标\n\n- 这次任务要交付什么最终结果\n\n# 背景与输入\n\n- 数据来源、范围、约束、参考材料\n\n# 执行步骤\n\n1. 先做什么\n2. 再做什么\n3. 关键中间产物落在哪里\n\n# 输出要求\n\n- 最终结果用什么格式返回\n- 是否需要表格 / JSON / Markdown\n- 不要包含什么内容\n\n# 触发与状态建议\n\n- 这个任务为什么适合 `@manual` / cron / `time:...`\n- 当前应该是 `paused` 还是 `enabled`\n\n# 注意事项\n\n- 风险、边界、不要做什么\n```\n\n### agent task 正文编写约束\n\n- task 正文必须像一份“交付合同”,让另一个执行器拿到后可以直接执行,不依赖当前聊天语境补全含义。\n- `# 任务目标` 必须写清楚最终要交付什么,不要只写“看一下”“研究一下”“处理一下”这类模糊目标。\n- `# 背景与输入` 必须写清来源、范围、对象、时间、限制条件;不要假设执行器还能看到原始聊天上下文。\n- `# 执行步骤` 应描述任务流程,不应描述 task 管理动作;不要写“先检查有没有同名任务”“再创建任务”“然后触发任务”。\n- `# 输出要求` 必须清楚声明最终成品的格式、结构、语气、长度,以及“不要输出什么”。\n- 要明确写出:**最后一条 assistant 返回会被直接写入 `output.md` 并发送给用户**;因此最终回答必须直接等于成品内容。\n- 内容生成类任务(如日报、提醒、晨读、摘要、报告)必须明确要求“最终输出直接是成品正文”,不要让执行器输出过程说明。\n- 如果任务要把结果发给用户,正文应要求“输出可直接发送的正文内容”,而不是要求执行器解释自己已经发送了什么。\n- 除非确有需要,不要在正文中要求执行器复述 task title、sessionId、执行时间、状态等元信息。\n- 正文中的约束要可执行、可判断,尽量避免“适当”“尽量”“看情况”这类弱约束词。\n- 不要把创建 task、更新 task、查看 task 状态、确认 task 是否存在等管理动作写进正文;这些属于 task plugin 的职责,不属于 task 正文交付物。\n\n### agent task 正文禁止写法\n\n- 不要把正文写成聊天回复口吻,例如:\n - “我来为你……”\n - “首先让我……”\n - “我先检查一下……”\n - “我看到已经有一个同名任务……”\n- 不要把正文写成任务管理说明,例如:\n - “如果任务已存在则更新,否则创建”\n - “先 list 再 run”\n - “完成后告诉用户任务已启动”\n- 不要把正文写成状态汇报模板,例如:\n - “任务状态总结”\n - “已发送 / 已完成 / 已更新”\n - “当前任务配置如下”\n- 不要只描述动作,不描述成品,例如:\n - “去搜集一些资料”\n - “生成一个内容看看”\n - “做完后反馈结果”\n- 不要把正文写成依赖当前上下文的指代,例如:\n - “按上面说的做”\n - “继续刚才那个”\n - “把这个发出去”\n\n### 如何判断正文写得对不对\n\n- 如果把 task 正文单独复制出来给另一个 agent,它仍然能理解任务目标、输入、步骤和交付物,说明正文合格。\n- 如果最终输出章节删掉后,正文只剩“去做一下”式描述,说明正文不合格。\n- 如果正文更像“创建/更新任务的操作说明”,而不是“任务执行说明”,说明分层错了,必须重写。\n- 如果正文天然会诱导执行器输出过程汇报,而不是最终成品,说明 `# 输出要求` 写得不够强,必须补充禁止项。\n\n### script task 推荐结构\n\n- 正文必须是纯 shell 脚本,不要混入解释性自然语言。\n- 开头尽量写注释说明脚本目的、输入依赖、失败条件。\n- 输出保持稳定,便于直接作为最终结果发送给用户。\n- 如需生成文件,写到 run 目录或明确的项目路径。\n\n### 输出设计原则\n\n- task 完成后,系统会自动把**最终结果正文**通过 chat plugin runtime 的 `send` 发回 `sessionId` 绑定的 chat。\n- 当前实现采用最简规则:**最后一条 assistant 返回**会被直接视为最终结果正文,并写入 `output.md`。\n- 因此正文里的“输出要求”要面向最终用户阅读,不要只写给开发者看。\n- 对于面向用户的 agent task,正文应要求“最后一条 assistant 返回直接输出最终交付物本身”,不要让执行器在最后回答里输出自己如何创建、检查、更新、触发或发送任务。\n- 如果任务是内容生成类(例如日报、提醒、晨读、摘要),最后输出应直接是那段内容本身,不要附带“我来为你处理”“任务已发送”“任务状态总结”等过程汇报。\n- 默认不要在正文里再次要求执行器调用 `town chat send`。\n- 只有在“跨会话发送”“额外抄送”“多渠道通知”这类场景下,才显式要求 `town chat send`。\n\n### `when` / `status` 怎么选\n\n- task 创建默认就是 `status=enabled`;如果还在试任务、容易失败、需要人工确认,再显式切到 `paused`。\n- 已经验证稳定、需要自动运行:直接使用 cron + `status=enabled`。\n- 明确只执行一次:使用 `time:<带时区 ISO 时间>`;执行后系统会自动回退到 `@manual` + `paused`。\n- 如果用户只是“先存起来以后再跑”,不要直接启用调度。\n\n## 正文模板\n\n### agent 模板\n\n```md\n# 任务目标\n\n- 产出一份可直接发给用户的最终结果。\n\n# 背景与输入\n\n- 在这里补充上下文、文件、链接、范围和假设。\n\n# 执行步骤\n\n1. 理解任务目标与完成标准。\n2. 收集必要信息并执行任务。\n3. 把关键中间产物写入 run 目录。\n4. 输出最终结果正文。\n\n# 输出要求\n\n- 最后一条 assistant 返回直接作为最终结果,不要附带冗长日志。\n- 最后一条 assistant 返回直接输出交付物本身,不要输出任务管理过程、发送过程或状态汇报。\n- 不要使用“我来为你…… / 首先让我…… / 已发送……”这类元话术。\n- 默认不要再次调用 `town chat send`。\n\n# 触发与状态建议\n\n- 默认创建后立即启用;如果只是先保存草稿或等待人工确认,再改成 `paused`。\n\n# 注意事项\n\n- 仅在明确需要跨会话或额外通知时,才调用 `town chat send`。\n```\n\n### script 模板\n\n```bash\n# 任务目标:一句话说明脚本要做什么\n# 输入依赖:列出环境变量、文件、命令依赖\n# 失败条件:列出应该 exit 1 的情况\n\nset -euo pipefail\n\n# 1. 准备输入\n\n# 2. 执行主逻辑\n\n# 3. 输出最终结果(这段输出会被直接发送给用户)\n```\n\n## 建议\n\n- 先 `list`,再 `create`/`update`。\n- 简单内容生成任务优先保持默认单轮;只有确实需要“先生成、再复核、再修订”时再设置 `review: true`。\n- script 任务正文保持纯脚本,不要混入冗余自然语言。\n- 如果用户只是先存起来以后再跑,创建后显式设成 `paused`;否则保持默认启用。\n- task 正文要写“最终结果长什么样”,不要只写“去做一下看看”。\n- 对内容生成任务,要明确写“最后一条 assistant 返回只能是成品正文”,避免执行器把过程说明误当成最终结果。\n";
|
|
7
7
|
export default TEXT_MODULE_CONTENT;
|
|
8
8
|
//# sourceMappingURL=PROMPT.js.map
|
package/bin/tts/Plugin.js
CHANGED
|
@@ -467,13 +467,13 @@ function createTtsPluginDefinition(plugin) {
|
|
|
467
467
|
"# TTS Plugin",
|
|
468
468
|
"The agent can call the tts plugin to synthesize speech audio from plain text.",
|
|
469
469
|
"Typical usage flow:",
|
|
470
|
-
"1. Check availability with `
|
|
471
|
-
"2. Generate audio with `
|
|
470
|
+
"1. Check availability with `town tts status` when you need to confirm whether the plugin and model are ready.",
|
|
471
|
+
"2. Generate audio with `town tts synthesize <text>`.",
|
|
472
472
|
"3. Optionally override synthesis parameters with `--voice`, `--language`, `--format`, `--speed`, and `--output`.",
|
|
473
473
|
"Use the `tts.synthesize` action when the user asks to generate spoken audio or a reusable audio file tag.",
|
|
474
474
|
"A successful synthesis returns a local output path and a reusable `<file type=\"audio\">...</file>` tag for downstream sending.",
|
|
475
475
|
"If the Python runner prints non-fatal stderr, the command still succeeds and returns that stderr summary as extra context.",
|
|
476
|
-
"Example: `
|
|
476
|
+
"Example: `town tts synthesize \"你好,欢迎来到 Downcity\" --format wav`",
|
|
477
477
|
].join("\n");
|
|
478
478
|
},
|
|
479
479
|
};
|
|
@@ -186,7 +186,7 @@ async function resolveVoiceConfig(input) {
|
|
|
186
186
|
: null;
|
|
187
187
|
const enabled = pluginConfig && pluginConfig.enabled === true;
|
|
188
188
|
if (!enabled) {
|
|
189
|
-
throw new Error("ASR plugin is disabled. Run `
|
|
189
|
+
throw new Error("ASR plugin is disabled. Run `town asr on` first.");
|
|
190
190
|
}
|
|
191
191
|
const provider = String(pluginConfig?.provider || "local");
|
|
192
192
|
if (!["local", "command"].includes(provider)) {
|
|
@@ -194,7 +194,7 @@ async function resolveVoiceConfig(input) {
|
|
|
194
194
|
}
|
|
195
195
|
const modelId = String(pluginConfig?.modelId || "SenseVoiceSmall").trim() || "SenseVoiceSmall";
|
|
196
196
|
if (!modelId && provider === "local") {
|
|
197
|
-
throw new Error("ASR active model is not configured. Run `
|
|
197
|
+
throw new Error("ASR active model is not configured. Run `town asr use <modelId>`.");
|
|
198
198
|
}
|
|
199
199
|
const modelsRootDir = resolveVoiceModelsRootDir({
|
|
200
200
|
projectRoot: input.context.rootPath,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@downcity/plugins",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.20",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Downcity 内建 plugin 集合包",
|
|
6
6
|
"main": "./bin/index.js",
|
|
@@ -12,27 +12,27 @@
|
|
|
12
12
|
}
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@larksuiteoapi/node-sdk": "^1.
|
|
16
|
-
"ai": "^6.0.
|
|
17
|
-
"better-sqlite3": "^
|
|
18
|
-
"commander": "^
|
|
19
|
-
"execa": "^9.
|
|
20
|
-
"fs-extra": "^11.
|
|
21
|
-
"js-yaml": "^4.1.
|
|
22
|
-
"node-cron": "^
|
|
23
|
-
"ws": "^8.
|
|
24
|
-
"zod": "^
|
|
25
|
-
"@downcity/agent": "^1.1.
|
|
15
|
+
"@larksuiteoapi/node-sdk": "^1.66.0",
|
|
16
|
+
"ai": "^6.0.193",
|
|
17
|
+
"better-sqlite3": "^12.10.0",
|
|
18
|
+
"commander": "^15.0.0",
|
|
19
|
+
"execa": "^9.6.1",
|
|
20
|
+
"fs-extra": "^11.3.5",
|
|
21
|
+
"js-yaml": "^4.1.1",
|
|
22
|
+
"node-cron": "^4.2.1",
|
|
23
|
+
"ws": "^8.21.0",
|
|
24
|
+
"zod": "^4.4.3",
|
|
25
|
+
"@downcity/agent": "^1.1.62"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
28
|
"@types/better-sqlite3": "^7.6.13",
|
|
29
29
|
"@types/fs-extra": "^11.0.4",
|
|
30
|
-
"@types/js-yaml": "^4.0.
|
|
31
|
-
"@types/node": "^
|
|
32
|
-
"@types/node-cron": "^3.0.
|
|
30
|
+
"@types/js-yaml": "^4.0.9",
|
|
31
|
+
"@types/node": "^25.9.1",
|
|
32
|
+
"@types/node-cron": "^3.0.11",
|
|
33
33
|
"@types/ws": "^8.18.1",
|
|
34
|
-
"tsc-alias": "^1.8.
|
|
35
|
-
"typescript": "^
|
|
34
|
+
"tsc-alias": "^1.8.17",
|
|
35
|
+
"typescript": "^6.0.3"
|
|
36
36
|
},
|
|
37
37
|
"scripts": {
|
|
38
38
|
"build": "rm -rf bin tsconfig.tsbuildinfo && tsc && tsc-alias -f",
|
|
@@ -4,6 +4,6 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
// Source: src/chat/PROMPT.direct.ts.txt
|
|
7
|
-
const TEXT_MODULE_CONTENT = "# Chat Plugin 使用说明\n\n## 用户可见回复规则\n\n- 当前模式下,直接输出,即会发送消息给到用户对应的channel\n\n## 输出协议\n\n- 需要普通回复时,直接输出文本即可。文本顶部可用 frontmatter metadata (optional),字段语义与 `
|
|
7
|
+
const TEXT_MODULE_CONTENT = "# Chat Plugin 使用说明\n\n## 用户可见回复规则\n\n- 当前模式下,直接输出,即会发送消息给到用户对应的channel\n\n## 输出协议\n\n- 需要普通回复时,直接输出文本即可。文本顶部可用 frontmatter metadata (optional),字段语义与 `town chat send` 保持一致:\n\n- `delay` / `delayMs`:延迟发送毫秒数。\n- `time` / `sendAt` / `sendAtMs`:定时发送时间。\n- `reply`:是否使用 reply 语义发送。\n- `messageId`:目标 `message_id`(群聊推荐)。\n- `react`:发送表情反应。\n - 单个字符串:`react: \"👍\"`\n - 或对象/数组:`emoji/big`\n - 设置 `messageId` 时,`react` 会优先复用该消息作为目标消息。\n- 附件使用 `<file type=\"...\">path</file>`(支持 `document/photo/voice/audio/video`)。\n- 附件路径必须是项目内可访问的相对路径。多附件可输出多个 `<file>` 标签。\n\n### 示例\n\n```text\n---\nreply: true\nmessageId: \"128\"\nreact:\n - emoji: \"✅\"\n---\n这是今天的报告。\n<file type=\"document\">reports/daily.md</file>\n```\n\n### 协议约束\n\n- frontmatter 必须位于文本最开头(`---` 包裹)。\n- 除 `<file>` 附件标签外,不要使用尖括号格式做控制参数。\n\n## 跨协议/跨平台操作\n\n- 当任务需要跨会话、跨平台或复杂路由,必须使用 `town chat send` / `town chat react`。\n- metadata 只适用于当前会话内的 direct 出站,不要拿 metadata 做跨 chat 路由。\n- 如果需要跨 chat 发送,或者不清楚怎么发送,直接先调用 `town chat --help` 查看方法。\n- 如不确定参数或正文协议,先自行调用:\n - `town chat --help`\n - `town chat send --help`\n - `town chat react --help`\n\n## 入站消息结构(仅供内部理解)\n\n- 每条入队用户消息包含 `<info>...</info>` 元信息块 + 用户正文。\n- `<info>` 仅保留 user/request 元信息,例如 `user_id`、`username`、`message_id`、`permissions`、`received_at`。\n- 当前 chat 路由环境(例如 `channel`、`session_id`、`chat_key`、`chat_id`)会通过 system prompt 单独注入,不再混在 `<info>` 里。\n- `<info>` 不要原样回传给用户。\n";
|
|
8
8
|
|
|
9
9
|
export default TEXT_MODULE_CONTENT;
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
## 输出协议
|
|
8
8
|
|
|
9
|
-
- 需要普通回复时,直接输出文本即可。文本顶部可用 frontmatter metadata (optional),字段语义与 `
|
|
9
|
+
- 需要普通回复时,直接输出文本即可。文本顶部可用 frontmatter metadata (optional),字段语义与 `town chat send` 保持一致:
|
|
10
10
|
|
|
11
11
|
- `delay` / `delayMs`:延迟发送毫秒数。
|
|
12
12
|
- `time` / `sendAt` / `sendAtMs`:定时发送时间。
|
|
@@ -39,13 +39,13 @@ react:
|
|
|
39
39
|
|
|
40
40
|
## 跨协议/跨平台操作
|
|
41
41
|
|
|
42
|
-
- 当任务需要跨会话、跨平台或复杂路由,必须使用 `
|
|
42
|
+
- 当任务需要跨会话、跨平台或复杂路由,必须使用 `town chat send` / `town chat react`。
|
|
43
43
|
- metadata 只适用于当前会话内的 direct 出站,不要拿 metadata 做跨 chat 路由。
|
|
44
|
-
- 如果需要跨 chat 发送,或者不清楚怎么发送,直接先调用 `
|
|
44
|
+
- 如果需要跨 chat 发送,或者不清楚怎么发送,直接先调用 `town chat --help` 查看方法。
|
|
45
45
|
- 如不确定参数或正文协议,先自行调用:
|
|
46
|
-
- `
|
|
47
|
-
- `
|
|
48
|
-
- `
|
|
46
|
+
- `town chat --help`
|
|
47
|
+
- `town chat send --help`
|
|
48
|
+
- `town chat react --help`
|
|
49
49
|
|
|
50
50
|
## 入站消息结构(仅供内部理解)
|
|
51
51
|
|
|
@@ -4,6 +4,6 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
// Source: src/chat/channels/qq/PROMPT.direct.ts.txt
|
|
7
|
-
const TEXT_MODULE_CONTENT = "# QQ Adapter 使用说明(direct 模式)\n\n## 能力范围\n- 负责 QQ 官方机器人网关(WebSocket)消息接入与发送。\n- 入站消息会由 chat plugin runtime 映射到内部 `sessionId`(随机分配并持久化)。\n\n## 使用约束\n- 在 direct 模式下,你输出的 assistant 文本会自动发送到当前 QQ 会话。\n- QQ 出站回复依赖入站消息上下文(如 `chatType` 与 `messageId`);跨会话发送请使用 `
|
|
7
|
+
const TEXT_MODULE_CONTENT = "# QQ Adapter 使用说明(direct 模式)\n\n## 能力范围\n- 负责 QQ 官方机器人网关(WebSocket)消息接入与发送。\n- 入站消息会由 chat plugin runtime 映射到内部 `sessionId`(随机分配并持久化)。\n\n## 使用约束\n- 在 direct 模式下,你输出的 assistant 文本会自动发送到当前 QQ 会话。\n- QQ 出站回复依赖入站消息上下文(如 `chatType` 与 `messageId`);跨会话发送请使用 `town chat send --chat-key ...`,不要在 direct metadata 中写 `chatKey`。\n- 群聊消息默认全量接入,不需要 `@` 触发。\n- 适配器会过滤机器人自回环消息并做入站去重,避免“自己回复自己”的循环。\n";
|
|
8
8
|
|
|
9
9
|
export default TEXT_MODULE_CONTENT;
|
|
@@ -6,6 +6,6 @@
|
|
|
6
6
|
|
|
7
7
|
## 使用约束
|
|
8
8
|
- 在 direct 模式下,你输出的 assistant 文本会自动发送到当前 QQ 会话。
|
|
9
|
-
- QQ 出站回复依赖入站消息上下文(如 `chatType` 与 `messageId`);跨会话发送请使用 `
|
|
9
|
+
- QQ 出站回复依赖入站消息上下文(如 `chatType` 与 `messageId`);跨会话发送请使用 `town chat send --chat-key ...`,不要在 direct metadata 中写 `chatKey`。
|
|
10
10
|
- 群聊消息默认全量接入,不需要 `@` 触发。
|
|
11
11
|
- 适配器会过滤机器人自回环消息并做入站去重,避免“自己回复自己”的循环。
|
|
@@ -58,18 +58,18 @@ import {
|
|
|
58
58
|
const CHAT_SEND_HELP_TEXT = [
|
|
59
59
|
"",
|
|
60
60
|
"消息协议:",
|
|
61
|
-
" frontmatter metadata 字段语义与 `
|
|
61
|
+
" frontmatter metadata 字段语义与 `town chat send` 参数一致。",
|
|
62
62
|
" 附件使用 `<file type=\"...\">path</file>`,支持 `document/photo/voice/audio/video`。",
|
|
63
63
|
" 正文与 `<file>` 可以交错出现,运行时会按原顺序发送。",
|
|
64
64
|
"",
|
|
65
65
|
"常用示例:",
|
|
66
|
-
"
|
|
67
|
-
"
|
|
68
|
-
" cat <<'EOF' |
|
|
66
|
+
" town chat send --text 'done'",
|
|
67
|
+
" town chat send --chat-key <chatKey> --text 'done'",
|
|
68
|
+
" cat <<'EOF' | town chat send --stdin --chat-key <chatKey>",
|
|
69
69
|
" 第一行",
|
|
70
70
|
" 第二行",
|
|
71
71
|
" EOF",
|
|
72
|
-
"
|
|
72
|
+
" town chat send --text-file ./result.md --chat-key <chatKey>",
|
|
73
73
|
"",
|
|
74
74
|
"说明:",
|
|
75
75
|
" 当前会话可省略 `--chat-key`;跨 chat 发送时必须显式传 `--chat-key`。",
|
|
@@ -79,9 +79,9 @@ const CHAT_SEND_HELP_TEXT = [
|
|
|
79
79
|
const CHAT_REACT_HELP_TEXT = [
|
|
80
80
|
"",
|
|
81
81
|
"常用示例:",
|
|
82
|
-
"
|
|
83
|
-
"
|
|
84
|
-
"
|
|
82
|
+
" town chat react --emoji '👍'",
|
|
83
|
+
" town chat react --emoji '✅' --message-id <messageId>",
|
|
84
|
+
" town chat react --chat-key <chatKey> --message-id <messageId> --emoji '🔥'",
|
|
85
85
|
"",
|
|
86
86
|
"说明:",
|
|
87
87
|
" 当前会话可省略 `--chat-key`;跨 chat 操作时显式传 `--chat-key`。",
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* 关键点(中文)
|
|
5
5
|
* - 默认把 assistant 文本原样当作用户可见正文发送。
|
|
6
|
-
* - frontmatter metadata 语义与 `
|
|
6
|
+
* - frontmatter metadata 语义与 `town chat send` 保持一致。
|
|
7
7
|
* - 额外保留 `react` 字段用于 direct 模式贴表情。
|
|
8
8
|
*/
|
|
9
9
|
|
|
@@ -125,7 +125,7 @@ function resolveReactionPlans(params: {
|
|
|
125
125
|
* 从 assistant 文本中解析 direct 出站执行计划。
|
|
126
126
|
*
|
|
127
127
|
* 协议(中文)
|
|
128
|
-
* - frontmatter metadata:与 `
|
|
128
|
+
* - frontmatter metadata:与 `town chat send` 参数保持一致。
|
|
129
129
|
* - 附件统一使用 `<file type=\"document|photo|voice|audio|video\">path</file>`。
|
|
130
130
|
* - `react` 仍仅用于 direct 模式的反应动作。
|
|
131
131
|
*/
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* 关键点(中文)
|
|
5
5
|
* - 仅用于当前 chat assistant 出站解析。
|
|
6
|
-
* - frontmatter metadata 语义与 `
|
|
6
|
+
* - frontmatter metadata 语义与 `town chat send` 保持一致,再额外支持 `react`。
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import type {
|
|
@@ -53,7 +53,7 @@ export interface ResolvedDirectTextPayload {
|
|
|
53
53
|
* 是否以 reply 语义发送正文。
|
|
54
54
|
*
|
|
55
55
|
* 说明(中文)
|
|
56
|
-
* - 语义与 `
|
|
56
|
+
* - 语义与 `town chat send --reply` 一致。
|
|
57
57
|
* - 当 metadata 提供 `reply: true` 或显式 `messageId` 时自动为 true。
|
|
58
58
|
*/
|
|
59
59
|
replyToMessage: boolean;
|
|
@@ -70,7 +70,7 @@ export interface ResolvedDirectTextPayload {
|
|
|
70
70
|
* 可选延迟发送毫秒数。
|
|
71
71
|
*
|
|
72
72
|
* 说明(中文)
|
|
73
|
-
* - 与 `
|
|
73
|
+
* - 与 `town chat send --delay` 对齐。
|
|
74
74
|
*/
|
|
75
75
|
delayMs?: number;
|
|
76
76
|
|
|
@@ -78,7 +78,7 @@ export interface ResolvedDirectTextPayload {
|
|
|
78
78
|
* 可选定时发送毫秒时间戳。
|
|
79
79
|
*
|
|
80
80
|
* 说明(中文)
|
|
81
|
-
* - 与 `
|
|
81
|
+
* - 与 `town chat send --time` 对齐。
|
|
82
82
|
*/
|
|
83
83
|
sendAtMs?: number;
|
|
84
84
|
}
|
package/src/contact/PROMPT.ts
CHANGED
|
@@ -4,6 +4,6 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
// Source: src/contact/PROMPT.ts.txt
|
|
7
|
-
const TEXT_MODULE_CONTENT = "Contact plugin\n\ncontact plugin 用来管理和其他 agent 的联系方式。一个 contact 代表一个已建立联系的远端 agent,并固定拥有一条长期对话历史。contact 可以是单向的:只要本 agent 能访问对方,就可以 check、chat、share。\n\n可用命令:\n- `
|
|
7
|
+
const TEXT_MODULE_CONTENT = "Contact plugin\n\ncontact plugin 用来管理和其他 agent 的联系方式。一个 contact 代表一个已建立联系的远端 agent,并固定拥有一条长期对话历史。contact 可以是单向的:只要本 agent 能访问对方,就可以 check、chat、share。\n\n可用命令:\n- `town contact link`:生成一次性联系码,交给另一个 agent。\n- `town contact approve <code>`:使用对方给的联系码建立 contact。\n- `town contact list`:查看已保存的 agent 联系方式。\n- `town contact check <contact>` / `town contact check --to <ip:port>`:检查对方是否在线可用。\n- `town contact chat --to <contact> \"<message>\"`:和某个 agent 对话。\n- `town contact share --to <contact> --text ... | --link ... | <path...>`:分享文本、链接、文件或目录。\n- `town contact inbox`:查看收到的分享。\n- `town contact receive <share_id>`:接收某条分享。\n\n边界:\n- chat 用于对话,share 用于资料交接。\n- `town contact link` 返回中的 notes 会说明联系码适合本机、局域网还是公网 agent 使用;本地 localhost 联系码不能交给 server agent approve。\n- public-looking endpoint 仍可能被防火墙/NAT 阻断;以返回的 notes 为准,不要承诺公网一定可达。\n- `town start` 会自动写入 `DOWNCITY_PUBLIC_HOST` 供 contact link 使用;这不是要求用户手动配置的 token 或 endpoint。\n- `town contact approve` 会先建立单向关系,再由对方主动 ping 回本 agent,ping 成功才升级为 bidirectional。\n- local/private agent 连接 public agent 时通常只能 outbound-only,不要说成双向。\n- contact token 由 link/approve 自动交换;不要要求用户手动配置 token 环境变量。\n- `Contact link not found` 表示请求打到的 agent runtime 没有这条 link 记录,优先检查 endpoint/端口/agent 是否一致;过期会明确返回 `Contact link expired`。\n- receive 只接收内容,不自动执行、不安装 skill、不修改项目业务文件。\n- 不自动 approve 或 receive,除非用户明确要求。\n";
|
|
8
8
|
|
|
9
9
|
export default TEXT_MODULE_CONTENT;
|
|
@@ -3,21 +3,21 @@ Contact plugin
|
|
|
3
3
|
contact plugin 用来管理和其他 agent 的联系方式。一个 contact 代表一个已建立联系的远端 agent,并固定拥有一条长期对话历史。contact 可以是单向的:只要本 agent 能访问对方,就可以 check、chat、share。
|
|
4
4
|
|
|
5
5
|
可用命令:
|
|
6
|
-
- `
|
|
7
|
-
- `
|
|
8
|
-
- `
|
|
9
|
-
- `
|
|
10
|
-
- `
|
|
11
|
-
- `
|
|
12
|
-
- `
|
|
13
|
-
- `
|
|
6
|
+
- `town contact link`:生成一次性联系码,交给另一个 agent。
|
|
7
|
+
- `town contact approve <code>`:使用对方给的联系码建立 contact。
|
|
8
|
+
- `town contact list`:查看已保存的 agent 联系方式。
|
|
9
|
+
- `town contact check <contact>` / `town contact check --to <ip:port>`:检查对方是否在线可用。
|
|
10
|
+
- `town contact chat --to <contact> "<message>"`:和某个 agent 对话。
|
|
11
|
+
- `town contact share --to <contact> --text ... | --link ... | <path...>`:分享文本、链接、文件或目录。
|
|
12
|
+
- `town contact inbox`:查看收到的分享。
|
|
13
|
+
- `town contact receive <share_id>`:接收某条分享。
|
|
14
14
|
|
|
15
15
|
边界:
|
|
16
16
|
- chat 用于对话,share 用于资料交接。
|
|
17
|
-
- `
|
|
17
|
+
- `town contact link` 返回中的 notes 会说明联系码适合本机、局域网还是公网 agent 使用;本地 localhost 联系码不能交给 server agent approve。
|
|
18
18
|
- public-looking endpoint 仍可能被防火墙/NAT 阻断;以返回的 notes 为准,不要承诺公网一定可达。
|
|
19
|
-
- `
|
|
20
|
-
- `
|
|
19
|
+
- `town start` 会自动写入 `DOWNCITY_PUBLIC_HOST` 供 contact link 使用;这不是要求用户手动配置的 token 或 endpoint。
|
|
20
|
+
- `town contact approve` 会先建立单向关系,再由对方主动 ping 回本 agent,ping 成功才升级为 bidirectional。
|
|
21
21
|
- local/private agent 连接 public agent 时通常只能 outbound-only,不要说成双向。
|
|
22
22
|
- contact token 由 link/approve 自动交换;不要要求用户手动配置 token 环境变量。
|
|
23
23
|
- `Contact link not found` 表示请求打到的 agent runtime 没有这条 link 记录,优先检查 endpoint/端口/agent 是否一致;过期会明确返回 `Contact link expired`。
|
|
@@ -60,7 +60,7 @@ export function buildContactLinkNotes(params: {
|
|
|
60
60
|
if (reachability === "loopback") {
|
|
61
61
|
return [
|
|
62
62
|
"This link endpoint is local-only. Only an agent on the same machine can approve it; a server agent cannot approve a link generated by this local agent.",
|
|
63
|
-
"Start city from a reachable environment before generating a new link;
|
|
63
|
+
"Start city from a reachable environment before generating a new link; town start automatically writes the public host used by contact links when it can detect one.",
|
|
64
64
|
];
|
|
65
65
|
}
|
|
66
66
|
if (reachability === "private") {
|
|
@@ -118,7 +118,7 @@ export function buildContactApproveNotes(params: {
|
|
|
118
118
|
);
|
|
119
119
|
} else {
|
|
120
120
|
notes.push(
|
|
121
|
-
"This contact is outbound-only from this side: this agent can call the peer, but the peer cannot call back unless this agent was started with a reachable address that
|
|
121
|
+
"This contact is outbound-only from this side: this agent can call the peer, but the peer cannot call back unless this agent was started with a reachable address that town start can provide to contact.",
|
|
122
122
|
);
|
|
123
123
|
}
|
|
124
124
|
return notes;
|
|
@@ -34,7 +34,7 @@ export function buildShellEnv(context: AgentContext): NodeJS.ProcessEnv {
|
|
|
34
34
|
const agentId = configuredAgentId || (agentPath ? path.basename(agentPath) : "");
|
|
35
35
|
|
|
36
36
|
// 关键点(中文)
|
|
37
|
-
// - agent 自己在 shell 里执行 `
|
|
37
|
+
// - agent 自己在 shell 里执行 `town <service> ...` 时,也需要显式知道“当前 agent 是谁”。
|
|
38
38
|
// - 否则 service CLI 会退回到当前终端 cwd / registry 猜测,在多 agent 或外部工作目录下
|
|
39
39
|
// 很容易把请求发到错误项目,最终误报 “Agent server 没启动”。
|
|
40
40
|
if (agentPath) env.DC_AGENT_PATH = agentPath;
|
package/src/skill/Command.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `
|
|
2
|
+
* `town skill` 命令 helper。
|
|
3
3
|
*
|
|
4
4
|
* 设计目标(中文)
|
|
5
5
|
* - 尽量不自建 registry:直接复用社区的 `npx skills` 生态(find/install)。
|
|
@@ -79,7 +79,7 @@ export async function skillListCommand(cwd: string = "."): Promise<void> {
|
|
|
79
79
|
const shipJson = path.join(projectRoot, "downcity.json");
|
|
80
80
|
if (!fs.existsSync(shipJson)) {
|
|
81
81
|
throw new Error(
|
|
82
|
-
`downcity.json not found at ${shipJson}. Run "
|
|
82
|
+
`downcity.json not found at ${shipJson}. Run "town agent create" first or pass the correct path.`,
|
|
83
83
|
);
|
|
84
84
|
}
|
|
85
85
|
|
package/src/skill/PROMPT.ts
CHANGED
|
@@ -4,6 +4,6 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
// Source: src/skill/PROMPT.ts.txt
|
|
7
|
-
const TEXT_MODULE_CONTENT = "# Skill Plugin\n\nskill 是你拥有的技能。用户的提出的需求和任务,你都需要先考虑利用相关的skill来高质量的完成。\n\n\n## 使用\n\n使用技能时需要首先通过 `
|
|
7
|
+
const TEXT_MODULE_CONTENT = "# Skill Plugin\n\nskill 是你拥有的技能。用户的提出的需求和任务,你都需要先考虑利用相关的skill来高质量的完成。\n\n\n## 使用\n\n使用技能时需要首先通过 `town skill lookup <name>` 命令载入对应的技能内容。\n\n你也可以使用 `town skill --help` 命令对skill进行其他操作。比如 `list`, `find`, `install`等等。\n";
|
|
8
8
|
|
|
9
9
|
export default TEXT_MODULE_CONTENT;
|
package/src/skill/PROMPT.ts.txt
CHANGED
|
@@ -5,6 +5,6 @@ skill 是你拥有的技能。用户的提出的需求和任务,你都需要
|
|
|
5
5
|
|
|
6
6
|
## 使用
|
|
7
7
|
|
|
8
|
-
使用技能时需要首先通过 `
|
|
8
|
+
使用技能时需要首先通过 `town skill lookup <name>` 命令载入对应的技能内容。
|
|
9
9
|
|
|
10
|
-
你也可以使用 `
|
|
10
|
+
你也可以使用 `town skill --help` 命令对skill进行其他操作。比如 `list`, `find`, `install`等等。
|
package/src/task/Action.ts
CHANGED
|
@@ -75,7 +75,7 @@ function buildDefaultTaskBody(): string {
|
|
|
75
75
|
"",
|
|
76
76
|
"- 最终输出直接写结果本身,不要包多余寒暄,不要粘贴冗长日志。",
|
|
77
77
|
"- 需要结构时,优先使用短标题、要点列表、表格或 JSON 等稳定格式。",
|
|
78
|
-
"- 默认不要在正文里重复调用 `
|
|
78
|
+
"- 默认不要在正文里重复调用 `town chat send`;系统会自动发送最终结果。",
|
|
79
79
|
"",
|
|
80
80
|
"# 触发与状态建议",
|
|
81
81
|
"",
|
|
@@ -87,7 +87,7 @@ function buildDefaultTaskBody(): string {
|
|
|
87
87
|
"",
|
|
88
88
|
"- 当前是独立 task 上下文,不要假设仍处在原始聊天回合里。",
|
|
89
89
|
"- 尽量使用可审计的方式:关键中间产物写入 `./.downcity/task/<title>/<timestamp>/` 下的 markdown 文件。",
|
|
90
|
-
"- 如果任务明确要求跨会话、跨平台或发送额外通知,再显式调用 `
|
|
90
|
+
"- 如果任务明确要求跨会话、跨平台或发送额外通知,再显式调用 `town chat send`。",
|
|
91
91
|
"",
|
|
92
92
|
].join("\n");
|
|
93
93
|
}
|
package/src/task/PROMPT.ts
CHANGED
|
@@ -4,6 +4,6 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
// Source: src/task/PROMPT.ts.txt
|
|
7
|
-
const TEXT_MODULE_CONTENT = "# Task Plugin\n\n你可以通过 `task` plugin 管理任务定义、执行、调度与状态控制。\n\n## 任务模型\n\n每个任务定义在 `./.downcity/task/<title>/task.md`,包含:\n- frontmatter(结构化字段)\n- body(任务正文)\n\nfrontmatter 核心字段:\n- `title`:任务唯一标识(唯一)\n- `description`:任务描述\n- `when`:触发条件,支持:`@manual` / cron / `time:<ISO8601-with-timezone>`\n- `sessionId`:任务执行会话\n- `status`:`enabled|paused|disabled`\n- `kind`:`agent|script`(默认 `agent`)\n\n执行时会产生 run 目录:\n- `./.downcity/task/<title>/<timestamp>/`\n\n常见产物:\n- `input.md`\n- `output.md`(本次任务的最终输出正文)\n- `result.md`(执行摘要)\n- `run.json`\n- `run-progress.json`\n- `dialogue.md` / `dialogue.json`(agent 多轮)\n- `error.md`(失败时)\n\n## 执行类型(kind)\n\n1. `kind=agent`\n- 将正文交给 agent 执行\n- 默认单轮完成;仅当 frontmatter 显式设置 `review: true` 时启用模拟用户多轮复核\n- 适合研究、分析、报告生成\n\n2. `kind=script`\n- 将正文当作 shell 脚本执行\n- 正文不能为空,必须是可执行脚本\n\n## 可用 action\n\n- `list`\n- `create`\n- `run`\n- `delete`\n- `update`\n- `status`\n- `enable`\n- `disable`\n\n## CLI 示例\n\n- `
|
|
7
|
+
const TEXT_MODULE_CONTENT = "# Task Plugin\n\n你可以通过 `task` plugin 管理任务定义、执行、调度与状态控制。\n\n## 任务模型\n\n每个任务定义在 `./.downcity/task/<title>/task.md`,包含:\n- frontmatter(结构化字段)\n- body(任务正文)\n\nfrontmatter 核心字段:\n- `title`:任务唯一标识(唯一)\n- `description`:任务描述\n- `when`:触发条件,支持:`@manual` / cron / `time:<ISO8601-with-timezone>`\n- `sessionId`:任务执行会话\n- `status`:`enabled|paused|disabled`\n- `kind`:`agent|script`(默认 `agent`)\n\n执行时会产生 run 目录:\n- `./.downcity/task/<title>/<timestamp>/`\n\n常见产物:\n- `input.md`\n- `output.md`(本次任务的最终输出正文)\n- `result.md`(执行摘要)\n- `run.json`\n- `run-progress.json`\n- `dialogue.md` / `dialogue.json`(agent 多轮)\n- `error.md`(失败时)\n\n## 执行类型(kind)\n\n1. `kind=agent`\n- 将正文交给 agent 执行\n- 默认单轮完成;仅当 frontmatter 显式设置 `review: true` 时启用模拟用户多轮复核\n- 适合研究、分析、报告生成\n\n2. `kind=script`\n- 将正文当作 shell 脚本执行\n- 正文不能为空,必须是可执行脚本\n\n## 可用 action\n\n- `list`\n- `create`\n- `run`\n- `delete`\n- `update`\n- `status`\n- `enable`\n- `disable`\n\n## CLI 示例\n\n- `town task list [--status enabled|paused|disabled]`\n- `town task create --title '...' --description '...' --session-id <sessionId> [--when '@manual'] [--kind agent|script] [--status ...|--activate]`\n- `town task run <title> [--reason '...']`\n- `town task update <title> [--title ...] [--description ...] [--when ...] [--status ...|--activate] [--session-id ...]`\n- `town task delete <title>`\n\n## 关键约束\n\n- `title` 唯一;create 去重仅按 `title` 精确匹配。\n- `when=time:...` 触发后会自动置为 `paused`,并回退为 `when=@manual`。\n- `run` 为异步受理:立即返回 `accepted=true`、`message`、`executionId`;调用方应把它视为“任务已进入后台执行,结果会自动通过 chat plugin runtime 发送,当前流程无需阻塞等待”。\n- 如果 `run` 返回 `accepted=true`:\n - 不要手动把 task 产出再转发给用户。\n - 不要主动读取 run 目录、`run-progress.json`、`output.md` 做轮询。\n - 只有当用户明确要求排查、查看产物或确认执行细节时,才进入 run 目录检查。\n- agent 任务默认只要求产生有效输出;仅当任务正文明确要求外发时,才应发送到外部 channel。\n\n## 如何设计 task 正文\n\n### agent task 推荐结构\n\n建议正文至少包含这些标题:\n\n```md\n# 任务目标\n\n- 这次任务要交付什么最终结果\n\n# 背景与输入\n\n- 数据来源、范围、约束、参考材料\n\n# 执行步骤\n\n1. 先做什么\n2. 再做什么\n3. 关键中间产物落在哪里\n\n# 输出要求\n\n- 最终结果用什么格式返回\n- 是否需要表格 / JSON / Markdown\n- 不要包含什么内容\n\n# 触发与状态建议\n\n- 这个任务为什么适合 `@manual` / cron / `time:...`\n- 当前应该是 `paused` 还是 `enabled`\n\n# 注意事项\n\n- 风险、边界、不要做什么\n```\n\n### agent task 正文编写约束\n\n- task 正文必须像一份“交付合同”,让另一个执行器拿到后可以直接执行,不依赖当前聊天语境补全含义。\n- `# 任务目标` 必须写清楚最终要交付什么,不要只写“看一下”“研究一下”“处理一下”这类模糊目标。\n- `# 背景与输入` 必须写清来源、范围、对象、时间、限制条件;不要假设执行器还能看到原始聊天上下文。\n- `# 执行步骤` 应描述任务流程,不应描述 task 管理动作;不要写“先检查有没有同名任务”“再创建任务”“然后触发任务”。\n- `# 输出要求` 必须清楚声明最终成品的格式、结构、语气、长度,以及“不要输出什么”。\n- 要明确写出:**最后一条 assistant 返回会被直接写入 `output.md` 并发送给用户**;因此最终回答必须直接等于成品内容。\n- 内容生成类任务(如日报、提醒、晨读、摘要、报告)必须明确要求“最终输出直接是成品正文”,不要让执行器输出过程说明。\n- 如果任务要把结果发给用户,正文应要求“输出可直接发送的正文内容”,而不是要求执行器解释自己已经发送了什么。\n- 除非确有需要,不要在正文中要求执行器复述 task title、sessionId、执行时间、状态等元信息。\n- 正文中的约束要可执行、可判断,尽量避免“适当”“尽量”“看情况”这类弱约束词。\n- 不要把创建 task、更新 task、查看 task 状态、确认 task 是否存在等管理动作写进正文;这些属于 task plugin 的职责,不属于 task 正文交付物。\n\n### agent task 正文禁止写法\n\n- 不要把正文写成聊天回复口吻,例如:\n - “我来为你……”\n - “首先让我……”\n - “我先检查一下……”\n - “我看到已经有一个同名任务……”\n- 不要把正文写成任务管理说明,例如:\n - “如果任务已存在则更新,否则创建”\n - “先 list 再 run”\n - “完成后告诉用户任务已启动”\n- 不要把正文写成状态汇报模板,例如:\n - “任务状态总结”\n - “已发送 / 已完成 / 已更新”\n - “当前任务配置如下”\n- 不要只描述动作,不描述成品,例如:\n - “去搜集一些资料”\n - “生成一个内容看看”\n - “做完后反馈结果”\n- 不要把正文写成依赖当前上下文的指代,例如:\n - “按上面说的做”\n - “继续刚才那个”\n - “把这个发出去”\n\n### 如何判断正文写得对不对\n\n- 如果把 task 正文单独复制出来给另一个 agent,它仍然能理解任务目标、输入、步骤和交付物,说明正文合格。\n- 如果最终输出章节删掉后,正文只剩“去做一下”式描述,说明正文不合格。\n- 如果正文更像“创建/更新任务的操作说明”,而不是“任务执行说明”,说明分层错了,必须重写。\n- 如果正文天然会诱导执行器输出过程汇报,而不是最终成品,说明 `# 输出要求` 写得不够强,必须补充禁止项。\n\n### script task 推荐结构\n\n- 正文必须是纯 shell 脚本,不要混入解释性自然语言。\n- 开头尽量写注释说明脚本目的、输入依赖、失败条件。\n- 输出保持稳定,便于直接作为最终结果发送给用户。\n- 如需生成文件,写到 run 目录或明确的项目路径。\n\n### 输出设计原则\n\n- task 完成后,系统会自动把**最终结果正文**通过 chat plugin runtime 的 `send` 发回 `sessionId` 绑定的 chat。\n- 当前实现采用最简规则:**最后一条 assistant 返回**会被直接视为最终结果正文,并写入 `output.md`。\n- 因此正文里的“输出要求”要面向最终用户阅读,不要只写给开发者看。\n- 对于面向用户的 agent task,正文应要求“最后一条 assistant 返回直接输出最终交付物本身”,不要让执行器在最后回答里输出自己如何创建、检查、更新、触发或发送任务。\n- 如果任务是内容生成类(例如日报、提醒、晨读、摘要),最后输出应直接是那段内容本身,不要附带“我来为你处理”“任务已发送”“任务状态总结”等过程汇报。\n- 默认不要在正文里再次要求执行器调用 `town chat send`。\n- 只有在“跨会话发送”“额外抄送”“多渠道通知”这类场景下,才显式要求 `town chat send`。\n\n### `when` / `status` 怎么选\n\n- task 创建默认就是 `status=enabled`;如果还在试任务、容易失败、需要人工确认,再显式切到 `paused`。\n- 已经验证稳定、需要自动运行:直接使用 cron + `status=enabled`。\n- 明确只执行一次:使用 `time:<带时区 ISO 时间>`;执行后系统会自动回退到 `@manual` + `paused`。\n- 如果用户只是“先存起来以后再跑”,不要直接启用调度。\n\n## 正文模板\n\n### agent 模板\n\n```md\n# 任务目标\n\n- 产出一份可直接发给用户的最终结果。\n\n# 背景与输入\n\n- 在这里补充上下文、文件、链接、范围和假设。\n\n# 执行步骤\n\n1. 理解任务目标与完成标准。\n2. 收集必要信息并执行任务。\n3. 把关键中间产物写入 run 目录。\n4. 输出最终结果正文。\n\n# 输出要求\n\n- 最后一条 assistant 返回直接作为最终结果,不要附带冗长日志。\n- 最后一条 assistant 返回直接输出交付物本身,不要输出任务管理过程、发送过程或状态汇报。\n- 不要使用“我来为你…… / 首先让我…… / 已发送……”这类元话术。\n- 默认不要再次调用 `town chat send`。\n\n# 触发与状态建议\n\n- 默认创建后立即启用;如果只是先保存草稿或等待人工确认,再改成 `paused`。\n\n# 注意事项\n\n- 仅在明确需要跨会话或额外通知时,才调用 `town chat send`。\n```\n\n### script 模板\n\n```bash\n# 任务目标:一句话说明脚本要做什么\n# 输入依赖:列出环境变量、文件、命令依赖\n# 失败条件:列出应该 exit 1 的情况\n\nset -euo pipefail\n\n# 1. 准备输入\n\n# 2. 执行主逻辑\n\n# 3. 输出最终结果(这段输出会被直接发送给用户)\n```\n\n## 建议\n\n- 先 `list`,再 `create`/`update`。\n- 简单内容生成任务优先保持默认单轮;只有确实需要“先生成、再复核、再修订”时再设置 `review: true`。\n- script 任务正文保持纯脚本,不要混入冗余自然语言。\n- 如果用户只是先存起来以后再跑,创建后显式设成 `paused`;否则保持默认启用。\n- task 正文要写“最终结果长什么样”,不要只写“去做一下看看”。\n- 对内容生成任务,要明确写“最后一条 assistant 返回只能是成品正文”,避免执行器把过程说明误当成最终结果。\n";
|
|
8
8
|
|
|
9
9
|
export default TEXT_MODULE_CONTENT;
|
package/src/task/PROMPT.ts.txt
CHANGED
|
@@ -52,11 +52,11 @@ frontmatter 核心字段:
|
|
|
52
52
|
|
|
53
53
|
## CLI 示例
|
|
54
54
|
|
|
55
|
-
- `
|
|
56
|
-
- `
|
|
57
|
-
- `
|
|
58
|
-
- `
|
|
59
|
-
- `
|
|
55
|
+
- `town task list [--status enabled|paused|disabled]`
|
|
56
|
+
- `town task create --title '...' --description '...' --session-id <sessionId> [--when '@manual'] [--kind agent|script] [--status ...|--activate]`
|
|
57
|
+
- `town task run <title> [--reason '...']`
|
|
58
|
+
- `town task update <title> [--title ...] [--description ...] [--when ...] [--status ...|--activate] [--session-id ...]`
|
|
59
|
+
- `town task delete <title>`
|
|
60
60
|
|
|
61
61
|
## 关键约束
|
|
62
62
|
|
|
@@ -165,8 +165,8 @@ frontmatter 核心字段:
|
|
|
165
165
|
- 因此正文里的“输出要求”要面向最终用户阅读,不要只写给开发者看。
|
|
166
166
|
- 对于面向用户的 agent task,正文应要求“最后一条 assistant 返回直接输出最终交付物本身”,不要让执行器在最后回答里输出自己如何创建、检查、更新、触发或发送任务。
|
|
167
167
|
- 如果任务是内容生成类(例如日报、提醒、晨读、摘要),最后输出应直接是那段内容本身,不要附带“我来为你处理”“任务已发送”“任务状态总结”等过程汇报。
|
|
168
|
-
- 默认不要在正文里再次要求执行器调用 `
|
|
169
|
-
- 只有在“跨会话发送”“额外抄送”“多渠道通知”这类场景下,才显式要求 `
|
|
168
|
+
- 默认不要在正文里再次要求执行器调用 `town chat send`。
|
|
169
|
+
- 只有在“跨会话发送”“额外抄送”“多渠道通知”这类场景下,才显式要求 `town chat send`。
|
|
170
170
|
|
|
171
171
|
### `when` / `status` 怎么选
|
|
172
172
|
|
|
@@ -200,7 +200,7 @@ frontmatter 核心字段:
|
|
|
200
200
|
- 最后一条 assistant 返回直接作为最终结果,不要附带冗长日志。
|
|
201
201
|
- 最后一条 assistant 返回直接输出交付物本身,不要输出任务管理过程、发送过程或状态汇报。
|
|
202
202
|
- 不要使用“我来为你…… / 首先让我…… / 已发送……”这类元话术。
|
|
203
|
-
- 默认不要再次调用 `
|
|
203
|
+
- 默认不要再次调用 `town chat send`。
|
|
204
204
|
|
|
205
205
|
# 触发与状态建议
|
|
206
206
|
|
|
@@ -208,7 +208,7 @@ frontmatter 核心字段:
|
|
|
208
208
|
|
|
209
209
|
# 注意事项
|
|
210
210
|
|
|
211
|
-
- 仅在明确需要跨会话或额外通知时,才调用 `
|
|
211
|
+
- 仅在明确需要跨会话或额外通知时,才调用 `town chat send`。
|
|
212
212
|
```
|
|
213
213
|
|
|
214
214
|
### script 模板
|
package/src/tts/Plugin.ts
CHANGED
|
@@ -493,13 +493,13 @@ function createTtsPluginDefinition(plugin: Plugin): Plugin {
|
|
|
493
493
|
"# TTS Plugin",
|
|
494
494
|
"The agent can call the tts plugin to synthesize speech audio from plain text.",
|
|
495
495
|
"Typical usage flow:",
|
|
496
|
-
"1. Check availability with `
|
|
497
|
-
"2. Generate audio with `
|
|
496
|
+
"1. Check availability with `town tts status` when you need to confirm whether the plugin and model are ready.",
|
|
497
|
+
"2. Generate audio with `town tts synthesize <text>`.",
|
|
498
498
|
"3. Optionally override synthesis parameters with `--voice`, `--language`, `--format`, `--speed`, and `--output`.",
|
|
499
499
|
"Use the `tts.synthesize` action when the user asks to generate spoken audio or a reusable audio file tag.",
|
|
500
500
|
"A successful synthesis returns a local output path and a reusable `<file type=\"audio\">...</file>` tag for downstream sending.",
|
|
501
501
|
"If the Python runner prints non-fatal stderr, the command still succeeds and returns that stderr summary as extra context.",
|
|
502
|
-
"Example: `
|
|
502
|
+
"Example: `town tts synthesize \"你好,欢迎来到 Downcity\" --format wav`",
|
|
503
503
|
].join("\n");
|
|
504
504
|
},
|
|
505
505
|
};
|
|
@@ -292,7 +292,7 @@ async function resolveVoiceConfig(input: VoiceTranscribeInput): Promise<VoiceCon
|
|
|
292
292
|
const enabled =
|
|
293
293
|
pluginConfig && (pluginConfig as { enabled?: unknown }).enabled === true;
|
|
294
294
|
if (!enabled) {
|
|
295
|
-
throw new Error("ASR plugin is disabled. Run `
|
|
295
|
+
throw new Error("ASR plugin is disabled. Run `town asr on` first.");
|
|
296
296
|
}
|
|
297
297
|
|
|
298
298
|
const provider = String(
|
|
@@ -307,7 +307,7 @@ async function resolveVoiceConfig(input: VoiceTranscribeInput): Promise<VoiceCon
|
|
|
307
307
|
(pluginConfig as { modelId?: unknown } | null)?.modelId || "SenseVoiceSmall",
|
|
308
308
|
).trim() || "SenseVoiceSmall";
|
|
309
309
|
if (!modelId && provider === "local") {
|
|
310
|
-
throw new Error("ASR active model is not configured. Run `
|
|
310
|
+
throw new Error("ASR active model is not configured. Run `town asr use <modelId>`.");
|
|
311
311
|
}
|
|
312
312
|
|
|
313
313
|
const modelsRootDir = resolveVoiceModelsRootDir({
|