chatccc 0.2.190 → 0.2.191
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/agent-prompts/claude_specific.md +45 -45
- package/agent-prompts/codex_specific.md +2 -2
- package/agent-prompts/cursor_specific.md +13 -13
- package/config.sample.json +14 -14
- package/im-skills/feishu-skill/receive-send-file.md +63 -63
- package/im-skills/feishu-skill/receive-send-image.md +24 -24
- package/im-skills/feishu-skill/skill.md +3 -3
- package/im-skills/wechat-file-skill/receive-send-file.md +38 -38
- package/im-skills/wechat-file-skill/send-file.mjs +83 -83
- package/im-skills/wechat-file-skill/skill.md +10 -10
- package/im-skills/wechat-image-skill/skill.md +10 -10
- package/im-skills/wechat-video-skill/receive-send-video.md +38 -38
- package/im-skills/wechat-video-skill/send-video.mjs +79 -79
- package/im-skills/wechat-video-skill/skill.md +10 -10
- package/package.json +1 -1
- package/scripts/postinstall-sharp-check.mjs +58 -58
- package/src/__tests__/agent-delegate-task-rpc.test.ts +165 -165
- package/src/__tests__/builtin-config.test.ts +33 -33
- package/src/__tests__/card-plain-text.test.ts +5 -5
- package/src/__tests__/cardkit.test.ts +60 -60
- package/src/__tests__/cards.test.ts +77 -77
- package/src/__tests__/chatgpt-subscription-rpc.test.ts +89 -89
- package/src/__tests__/chatgpt-subscription.test.ts +135 -135
- package/src/__tests__/chrome-devtools-guard.test.ts +165 -165
- package/src/__tests__/claude-adapter.test.ts +592 -592
- package/src/__tests__/codex-reset-actions.test.ts +146 -146
- package/src/__tests__/config-reload.test.ts +4 -4
- package/src/__tests__/config-sample.test.ts +17 -17
- package/src/__tests__/feishu-api.test.ts +60 -60
- package/src/__tests__/feishu-platform.test.ts +22 -22
- package/src/__tests__/format-message.test.ts +47 -47
- package/src/__tests__/orchestrator.test.ts +120 -120
- package/src/__tests__/privacy.test.ts +198 -198
- package/src/__tests__/raw-stream-log.test.ts +106 -106
- package/src/__tests__/session.test.ts +17 -17
- package/src/__tests__/shared-prefix.test.ts +36 -36
- package/src/__tests__/stream-state.test.ts +42 -42
- package/src/__tests__/web-ui.test.ts +209 -209
- package/src/adapters/claude-adapter.ts +566 -566
- package/src/adapters/claude-session-meta-store.ts +120 -120
- package/src/adapters/codex-adapter.ts +30 -30
- package/src/adapters/cursor-adapter.ts +46 -46
- package/src/adapters/raw-stream-log.ts +124 -124
- package/src/adapters/resource-monitor.ts +140 -140
- package/src/agent-delegate-task-rpc.ts +153 -153
- package/src/agent-delegate-task.ts +81 -81
- package/src/agent-stop-stuck.ts +129 -129
- package/src/builtin/cli.ts +204 -189
- package/src/builtin/index.ts +170 -170
- package/src/cards.ts +137 -137
- package/src/chatgpt-subscription-rpc.ts +27 -27
- package/src/chatgpt-subscription.ts +299 -299
- package/src/chrome-devtools-guard.ts +318 -318
- package/src/codex-reset-actions.ts +184 -184
- package/src/config.ts +86 -86
- package/src/feishu-platform.ts +20 -20
- package/src/format-message.ts +293 -293
- package/src/litellm-proxy.ts +374 -374
- package/src/orchestrator.ts +143 -143
- package/src/privacy.ts +118 -118
- package/src/session-chat-binding.ts +6 -6
- package/src/session-name.ts +8 -8
- package/src/session.ts +98 -98
- package/src/shared-prefix.ts +29 -29
- package/src/sim-platform.ts +20 -20
- package/src/turn-cards.ts +117 -117
- package/src/web-ui.ts +205 -205
package/src/builtin/index.ts
CHANGED
|
@@ -1,170 +1,170 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* builtin/index.ts — ChatCCC 内置 Agent 核心 API
|
|
3
|
-
*
|
|
4
|
-
* ChatSession 是程序化入口,既可以被 CLI 调用,也可以被其他模块(如 ToolAdapter)调用。
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { createOpenAICompatible } from "@ai-sdk/openai-compatible";
|
|
8
|
-
import { streamText } from "ai";
|
|
9
|
-
|
|
10
|
-
import { config as appConfig } from "../config.ts";
|
|
11
|
-
|
|
12
|
-
// ---------------------------------------------------------------------------
|
|
13
|
-
// 系统提示词 — 编译期冻结常量
|
|
14
|
-
// ---------------------------------------------------------------------------
|
|
15
|
-
|
|
16
|
-
const SYSTEM_PROMPT = [
|
|
17
|
-
"你是 ChatCCC 内置 AI 编程助手,运行在终端环境中。",
|
|
18
|
-
"",
|
|
19
|
-
"## 基本规则",
|
|
20
|
-
"- 用中文回复,但代码、命令、文件名保持原文",
|
|
21
|
-
"- 优先给出直接可用的方案,而非长篇解释",
|
|
22
|
-
"- 如果用户的问题涉及代码,直接给出代码并说明用法",
|
|
23
|
-
"- 保持简洁,一次聚焦一个问题",
|
|
24
|
-
].join("\n");
|
|
25
|
-
|
|
26
|
-
// ---------------------------------------------------------------------------
|
|
27
|
-
// 类型定义
|
|
28
|
-
// ---------------------------------------------------------------------------
|
|
29
|
-
|
|
30
|
-
export interface ChatSessionConfig {
|
|
31
|
-
/** DeepSeek API 兼容的服务地址;传入时覆盖 config.ccc.DEEPSEEK_BASE_URL */
|
|
32
|
-
baseURL?: string;
|
|
33
|
-
/** API Key;传入时覆盖 config.ccc.DEEPSEEK_API_KEY */
|
|
34
|
-
apiKey?: string;
|
|
35
|
-
/** 模型名称;传入时覆盖 config.ccc.model */
|
|
36
|
-
model?: string;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export interface ChatSessionOptions {
|
|
40
|
-
/** 会话工作目录 */
|
|
41
|
-
cwd?: string;
|
|
42
|
-
/** 自定义系统提示词(会拼接到默认提示词之后) */
|
|
43
|
-
systemPrompt?: string;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* 流式响应事件
|
|
48
|
-
*/
|
|
49
|
-
export type ChatEvent =
|
|
50
|
-
| { type: "text"; text: string; accumulated: string }
|
|
51
|
-
| { type: "done"; text: string }
|
|
52
|
-
| { type: "error"; message: string };
|
|
53
|
-
|
|
54
|
-
// ---------------------------------------------------------------------------
|
|
55
|
-
// ChatSession
|
|
56
|
-
// ---------------------------------------------------------------------------
|
|
57
|
-
|
|
58
|
-
/** 消息角色 */
|
|
59
|
-
type MessageRole = "system" | "user" | "assistant" | "tool";
|
|
60
|
-
|
|
61
|
-
/** 内部消息类型 */
|
|
62
|
-
interface ChatMessage {
|
|
63
|
-
role: MessageRole;
|
|
64
|
-
content: string;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
export class ChatSession {
|
|
68
|
-
private model: any;
|
|
69
|
-
private systemPrompt: string;
|
|
70
|
-
private messages: ChatMessage[];
|
|
71
|
-
|
|
72
|
-
constructor(
|
|
73
|
-
overrides: ChatSessionConfig = {},
|
|
74
|
-
options: ChatSessionOptions = {},
|
|
75
|
-
) {
|
|
76
|
-
const apiKey = overrides.apiKey ?? appConfig.ccc.DEEPSEEK_API_KEY;
|
|
77
|
-
if (!apiKey) {
|
|
78
|
-
throw new Error(
|
|
79
|
-
"ccc.DEEPSEEK_API_KEY 未设置。请在 config.json 中配置,或通过 --api-key 临时传入",
|
|
80
|
-
);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
const baseURL = overrides.baseURL ?? appConfig.ccc.DEEPSEEK_BASE_URL;
|
|
84
|
-
const modelId = overrides.model ?? appConfig.ccc.model;
|
|
85
|
-
|
|
86
|
-
const provider = createOpenAICompatible({
|
|
87
|
-
name: "deepseek",
|
|
88
|
-
baseURL,
|
|
89
|
-
apiKey,
|
|
90
|
-
});
|
|
91
|
-
this.model = provider(modelId);
|
|
92
|
-
|
|
93
|
-
// 构建系统提示词
|
|
94
|
-
const systemContent = [SYSTEM_PROMPT];
|
|
95
|
-
if (options?.systemPrompt) {
|
|
96
|
-
systemContent.push("", options.systemPrompt);
|
|
97
|
-
}
|
|
98
|
-
if (options?.cwd) {
|
|
99
|
-
systemContent.push("", `当前工作目录: ${options.cwd}`);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
this.systemPrompt = systemContent.join("\n");
|
|
103
|
-
this.messages = [];
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* 发送用户消息,返回异步可迭代的文本流。
|
|
108
|
-
*
|
|
109
|
-
* 使用方式:
|
|
110
|
-
* ```typescript
|
|
111
|
-
* const session = new ChatSession();
|
|
112
|
-
* for await (const event of session.chat("帮我看看 package.json")) {
|
|
113
|
-
* if (event.type === "text") process.stdout.write(event.text);
|
|
114
|
-
* }
|
|
115
|
-
* console.log("完成");
|
|
116
|
-
* ```
|
|
117
|
-
*/
|
|
118
|
-
async *chat(
|
|
119
|
-
userMessage: string,
|
|
120
|
-
signal?: AbortSignal,
|
|
121
|
-
): AsyncIterable<ChatEvent> {
|
|
122
|
-
this.messages.push({ role: "user", content: userMessage });
|
|
123
|
-
|
|
124
|
-
let fullText = "";
|
|
125
|
-
|
|
126
|
-
try {
|
|
127
|
-
const result = streamText({
|
|
128
|
-
model: this.model,
|
|
129
|
-
system: this.systemPrompt,
|
|
130
|
-
messages: this.messages as any,
|
|
131
|
-
abortSignal: signal,
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
for await (const chunk of result.textStream) {
|
|
135
|
-
fullText += chunk;
|
|
136
|
-
yield { type: "text", text: chunk, accumulated: fullText };
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
this.messages.push({ role: "assistant", content: fullText });
|
|
140
|
-
yield { type: "done", text: fullText };
|
|
141
|
-
} catch (err) {
|
|
142
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
143
|
-
if ((err as Error).name === "AbortError" || signal?.aborted) {
|
|
144
|
-
// 被中断时,不保存不完整的助手消息
|
|
145
|
-
if (fullText) {
|
|
146
|
-
this.messages.push({ role: "assistant", content: fullText + "\n[已中断]" });
|
|
147
|
-
}
|
|
148
|
-
yield { type: "done", text: fullText };
|
|
149
|
-
return;
|
|
150
|
-
}
|
|
151
|
-
yield { type: "error", message };
|
|
152
|
-
throw err;
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
/** 返回当前的会话历史(只读) */
|
|
157
|
-
get history(): ReadonlyArray<ChatMessage> {
|
|
158
|
-
return [{ role: "system", content: this.systemPrompt }, ...this.messages];
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
/** 返回当前轮数(不含 system 消息) */
|
|
162
|
-
get turnCount(): number {
|
|
163
|
-
return this.messages.length;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
/** 清空会话历史,保留 system 消息 */
|
|
167
|
-
reset(): void {
|
|
168
|
-
this.messages = [];
|
|
169
|
-
}
|
|
170
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* builtin/index.ts — ChatCCC 内置 Agent 核心 API
|
|
3
|
+
*
|
|
4
|
+
* ChatSession 是程序化入口,既可以被 CLI 调用,也可以被其他模块(如 ToolAdapter)调用。
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { createOpenAICompatible } from "@ai-sdk/openai-compatible";
|
|
8
|
+
import { streamText } from "ai";
|
|
9
|
+
|
|
10
|
+
import { config as appConfig } from "../config.ts";
|
|
11
|
+
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
13
|
+
// 系统提示词 — 编译期冻结常量
|
|
14
|
+
// ---------------------------------------------------------------------------
|
|
15
|
+
|
|
16
|
+
const SYSTEM_PROMPT = [
|
|
17
|
+
"你是 ChatCCC 内置 AI 编程助手,运行在终端环境中。",
|
|
18
|
+
"",
|
|
19
|
+
"## 基本规则",
|
|
20
|
+
"- 用中文回复,但代码、命令、文件名保持原文",
|
|
21
|
+
"- 优先给出直接可用的方案,而非长篇解释",
|
|
22
|
+
"- 如果用户的问题涉及代码,直接给出代码并说明用法",
|
|
23
|
+
"- 保持简洁,一次聚焦一个问题",
|
|
24
|
+
].join("\n");
|
|
25
|
+
|
|
26
|
+
// ---------------------------------------------------------------------------
|
|
27
|
+
// 类型定义
|
|
28
|
+
// ---------------------------------------------------------------------------
|
|
29
|
+
|
|
30
|
+
export interface ChatSessionConfig {
|
|
31
|
+
/** DeepSeek API 兼容的服务地址;传入时覆盖 config.ccc.DEEPSEEK_BASE_URL */
|
|
32
|
+
baseURL?: string;
|
|
33
|
+
/** API Key;传入时覆盖 config.ccc.DEEPSEEK_API_KEY */
|
|
34
|
+
apiKey?: string;
|
|
35
|
+
/** 模型名称;传入时覆盖 config.ccc.model */
|
|
36
|
+
model?: string;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface ChatSessionOptions {
|
|
40
|
+
/** 会话工作目录 */
|
|
41
|
+
cwd?: string;
|
|
42
|
+
/** 自定义系统提示词(会拼接到默认提示词之后) */
|
|
43
|
+
systemPrompt?: string;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* 流式响应事件
|
|
48
|
+
*/
|
|
49
|
+
export type ChatEvent =
|
|
50
|
+
| { type: "text"; text: string; accumulated: string }
|
|
51
|
+
| { type: "done"; text: string }
|
|
52
|
+
| { type: "error"; message: string };
|
|
53
|
+
|
|
54
|
+
// ---------------------------------------------------------------------------
|
|
55
|
+
// ChatSession
|
|
56
|
+
// ---------------------------------------------------------------------------
|
|
57
|
+
|
|
58
|
+
/** 消息角色 */
|
|
59
|
+
type MessageRole = "system" | "user" | "assistant" | "tool";
|
|
60
|
+
|
|
61
|
+
/** 内部消息类型 */
|
|
62
|
+
interface ChatMessage {
|
|
63
|
+
role: MessageRole;
|
|
64
|
+
content: string;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export class ChatSession {
|
|
68
|
+
private model: any;
|
|
69
|
+
private systemPrompt: string;
|
|
70
|
+
private messages: ChatMessage[];
|
|
71
|
+
|
|
72
|
+
constructor(
|
|
73
|
+
overrides: ChatSessionConfig = {},
|
|
74
|
+
options: ChatSessionOptions = {},
|
|
75
|
+
) {
|
|
76
|
+
const apiKey = overrides.apiKey ?? appConfig.ccc.DEEPSEEK_API_KEY;
|
|
77
|
+
if (!apiKey) {
|
|
78
|
+
throw new Error(
|
|
79
|
+
"ccc.DEEPSEEK_API_KEY 未设置。请在 config.json 中配置,或通过 --api-key 临时传入",
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const baseURL = overrides.baseURL ?? appConfig.ccc.DEEPSEEK_BASE_URL;
|
|
84
|
+
const modelId = overrides.model ?? appConfig.ccc.model;
|
|
85
|
+
|
|
86
|
+
const provider = createOpenAICompatible({
|
|
87
|
+
name: "deepseek",
|
|
88
|
+
baseURL,
|
|
89
|
+
apiKey,
|
|
90
|
+
});
|
|
91
|
+
this.model = provider(modelId);
|
|
92
|
+
|
|
93
|
+
// 构建系统提示词
|
|
94
|
+
const systemContent = [SYSTEM_PROMPT];
|
|
95
|
+
if (options?.systemPrompt) {
|
|
96
|
+
systemContent.push("", options.systemPrompt);
|
|
97
|
+
}
|
|
98
|
+
if (options?.cwd) {
|
|
99
|
+
systemContent.push("", `当前工作目录: ${options.cwd}`);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
this.systemPrompt = systemContent.join("\n");
|
|
103
|
+
this.messages = [];
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* 发送用户消息,返回异步可迭代的文本流。
|
|
108
|
+
*
|
|
109
|
+
* 使用方式:
|
|
110
|
+
* ```typescript
|
|
111
|
+
* const session = new ChatSession();
|
|
112
|
+
* for await (const event of session.chat("帮我看看 package.json")) {
|
|
113
|
+
* if (event.type === "text") process.stdout.write(event.text);
|
|
114
|
+
* }
|
|
115
|
+
* console.log("完成");
|
|
116
|
+
* ```
|
|
117
|
+
*/
|
|
118
|
+
async *chat(
|
|
119
|
+
userMessage: string,
|
|
120
|
+
signal?: AbortSignal,
|
|
121
|
+
): AsyncIterable<ChatEvent> {
|
|
122
|
+
this.messages.push({ role: "user", content: userMessage });
|
|
123
|
+
|
|
124
|
+
let fullText = "";
|
|
125
|
+
|
|
126
|
+
try {
|
|
127
|
+
const result = streamText({
|
|
128
|
+
model: this.model,
|
|
129
|
+
system: this.systemPrompt,
|
|
130
|
+
messages: this.messages as any,
|
|
131
|
+
abortSignal: signal,
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
for await (const chunk of result.textStream) {
|
|
135
|
+
fullText += chunk;
|
|
136
|
+
yield { type: "text", text: chunk, accumulated: fullText };
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
this.messages.push({ role: "assistant", content: fullText });
|
|
140
|
+
yield { type: "done", text: fullText };
|
|
141
|
+
} catch (err) {
|
|
142
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
143
|
+
if ((err as Error).name === "AbortError" || signal?.aborted) {
|
|
144
|
+
// 被中断时,不保存不完整的助手消息
|
|
145
|
+
if (fullText) {
|
|
146
|
+
this.messages.push({ role: "assistant", content: fullText + "\n[已中断]" });
|
|
147
|
+
}
|
|
148
|
+
yield { type: "done", text: fullText };
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
yield { type: "error", message };
|
|
152
|
+
throw err;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/** 返回当前的会话历史(只读) */
|
|
157
|
+
get history(): ReadonlyArray<ChatMessage> {
|
|
158
|
+
return [{ role: "system", content: this.systemPrompt }, ...this.messages];
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/** 返回当前轮数(不含 system 消息) */
|
|
162
|
+
get turnCount(): number {
|
|
163
|
+
return this.messages.length;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/** 清空会话历史,保留 system 消息 */
|
|
167
|
+
reset(): void {
|
|
168
|
+
this.messages = [];
|
|
169
|
+
}
|
|
170
|
+
}
|
package/src/cards.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
// ---------------------------------------------------------------------------
|
|
2
|
-
// Button helpers
|
|
3
|
-
// ---------------------------------------------------------------------------
|
|
4
|
-
|
|
5
|
-
import { ABD_HELP_LINE } from "./shared-prefix.ts";
|
|
6
|
-
|
|
7
|
-
export interface ButtonDef {
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// Button helpers
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
|
|
5
|
+
import { ABD_HELP_LINE } from "./shared-prefix.ts";
|
|
6
|
+
|
|
7
|
+
export interface ButtonDef {
|
|
8
8
|
text: string;
|
|
9
9
|
value: string;
|
|
10
10
|
type?: "primary" | "default" | "danger";
|
|
@@ -137,11 +137,11 @@ export function buildHelpCard(
|
|
|
137
137
|
"发送 **/newh** 重置当前会话(沿用当前工作目录,不切换)",
|
|
138
138
|
"发送 **/plan** 以规划模式提问(只读,不执行写操作)",
|
|
139
139
|
"发送 **/ask** 以问答模式提问(只读,不执行写操作)",
|
|
140
|
-
"发送 **/usage** 查看 Codex 5h/周用量,以及查询/使用主动重置卡",
|
|
141
|
-
"发送 **/restart** 重启 ChatCCC 进程",
|
|
142
|
-
"发送 **/update** 更新并重启(仅 npm 全局安装可用)",
|
|
143
|
-
ABD_HELP_LINE,
|
|
144
|
-
].join("\n");
|
|
140
|
+
"发送 **/usage** 查看 Codex 5h/周用量,以及查询/使用主动重置卡",
|
|
141
|
+
"发送 **/restart** 重启 ChatCCC 进程",
|
|
142
|
+
"发送 **/update** 更新并重启(仅 npm 全局安装可用)",
|
|
143
|
+
ABD_HELP_LINE,
|
|
144
|
+
].join("\n");
|
|
145
145
|
return JSON.stringify({
|
|
146
146
|
config: { wide_screen_mode: true },
|
|
147
147
|
header: { template: "blue", title: { content: "ChatCCC", tag: "plain_text" } },
|
|
@@ -410,11 +410,11 @@ export function buildQueueFullCard(): string {
|
|
|
410
410
|
}
|
|
411
411
|
|
|
412
412
|
// 状态卡片(带关闭按钮)
|
|
413
|
-
export function buildStatusCard(statusText: string, template = "blue"): string {
|
|
414
|
-
return JSON.stringify({
|
|
415
|
-
config: { wide_screen_mode: true },
|
|
416
|
-
header: { template, title: { content: "会话状态", tag: "plain_text" } },
|
|
417
|
-
elements: [
|
|
413
|
+
export function buildStatusCard(statusText: string, template = "blue"): string {
|
|
414
|
+
return JSON.stringify({
|
|
415
|
+
config: { wide_screen_mode: true },
|
|
416
|
+
header: { template, title: { content: "会话状态", tag: "plain_text" } },
|
|
417
|
+
elements: [
|
|
418
418
|
{ tag: "div", text: { tag: "lark_md", content: statusText } },
|
|
419
419
|
{ tag: "hr" },
|
|
420
420
|
{
|
|
@@ -426,82 +426,82 @@ export function buildStatusCard(statusText: string, template = "blue"): string {
|
|
|
426
426
|
value: { action: "close" },
|
|
427
427
|
}],
|
|
428
428
|
},
|
|
429
|
-
],
|
|
430
|
-
});
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
export function buildCodexUsageCard(content: string, resetCreditsAvailable: number | null): string {
|
|
434
|
-
const elements: object[] = [
|
|
435
|
-
{ tag: "div", text: { tag: "lark_md", content } },
|
|
436
|
-
];
|
|
437
|
-
if (resetCreditsAvailable !== null && resetCreditsAvailable > 0) {
|
|
438
|
-
elements.push({ tag: "hr" });
|
|
439
|
-
elements.push({
|
|
440
|
-
tag: "action",
|
|
441
|
-
actions: [{
|
|
442
|
-
tag: "button",
|
|
443
|
-
text: { tag: "plain_text", content: "发起重置" },
|
|
444
|
-
type: "primary",
|
|
445
|
-
value: { action: "codex_reset_request", availableCount: resetCreditsAvailable },
|
|
446
|
-
}],
|
|
447
|
-
});
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
return JSON.stringify({
|
|
451
|
-
config: { wide_screen_mode: true },
|
|
452
|
-
header: { template: "blue", title: { content: "Codex Usage", tag: "plain_text" } },
|
|
453
|
-
elements,
|
|
454
|
-
});
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
export function buildCodexResetConfirmCard(params: {
|
|
458
|
-
availableCount: number;
|
|
459
|
-
parentMessageId: string;
|
|
460
|
-
requestId: string;
|
|
461
|
-
}): string {
|
|
462
|
-
const valueBase = {
|
|
463
|
-
parentMessageId: params.parentMessageId,
|
|
464
|
-
requestId: params.requestId,
|
|
465
|
-
};
|
|
466
|
-
return JSON.stringify({
|
|
467
|
-
config: { wide_screen_mode: true },
|
|
468
|
-
header: { template: "yellow", title: { content: "确认 Codex 主动重置", tag: "plain_text" } },
|
|
469
|
-
elements: [
|
|
470
|
-
{
|
|
471
|
-
tag: "div",
|
|
472
|
-
text: {
|
|
473
|
-
tag: "lark_md",
|
|
474
|
-
content: `当前可用主动重置次数:**${params.availableCount}**。\n\n确认后会消耗 1 次主动重置,并重置当前可重置的 Codex 用量窗口。`,
|
|
475
|
-
},
|
|
476
|
-
},
|
|
477
|
-
{ tag: "hr" },
|
|
478
|
-
{
|
|
479
|
-
tag: "action",
|
|
480
|
-
actions: [
|
|
481
|
-
{
|
|
482
|
-
tag: "button",
|
|
483
|
-
text: { tag: "plain_text", content: "是,发起重置" },
|
|
484
|
-
type: "danger",
|
|
485
|
-
value: { action: "codex_reset_confirm", decision: "yes", ...valueBase },
|
|
486
|
-
},
|
|
487
|
-
{
|
|
488
|
-
tag: "button",
|
|
489
|
-
text: { tag: "plain_text", content: "否" },
|
|
490
|
-
type: "default",
|
|
491
|
-
value: { action: "codex_reset_confirm", decision: "no", ...valueBase },
|
|
492
|
-
},
|
|
493
|
-
],
|
|
494
|
-
},
|
|
495
|
-
],
|
|
496
|
-
});
|
|
497
|
-
}
|
|
498
|
-
|
|
499
|
-
/** 模型切换卡片(/model 命令,飞书专用,含切换按钮) */
|
|
500
|
-
export function buildModelCard(
|
|
501
|
-
currentModel: string,
|
|
502
|
-
models: string[],
|
|
503
|
-
tool?: string,
|
|
504
|
-
): string {
|
|
429
|
+
],
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
export function buildCodexUsageCard(content: string, resetCreditsAvailable: number | null): string {
|
|
434
|
+
const elements: object[] = [
|
|
435
|
+
{ tag: "div", text: { tag: "lark_md", content } },
|
|
436
|
+
];
|
|
437
|
+
if (resetCreditsAvailable !== null && resetCreditsAvailable > 0) {
|
|
438
|
+
elements.push({ tag: "hr" });
|
|
439
|
+
elements.push({
|
|
440
|
+
tag: "action",
|
|
441
|
+
actions: [{
|
|
442
|
+
tag: "button",
|
|
443
|
+
text: { tag: "plain_text", content: "发起重置" },
|
|
444
|
+
type: "primary",
|
|
445
|
+
value: { action: "codex_reset_request", availableCount: resetCreditsAvailable },
|
|
446
|
+
}],
|
|
447
|
+
});
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
return JSON.stringify({
|
|
451
|
+
config: { wide_screen_mode: true },
|
|
452
|
+
header: { template: "blue", title: { content: "Codex Usage", tag: "plain_text" } },
|
|
453
|
+
elements,
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
export function buildCodexResetConfirmCard(params: {
|
|
458
|
+
availableCount: number;
|
|
459
|
+
parentMessageId: string;
|
|
460
|
+
requestId: string;
|
|
461
|
+
}): string {
|
|
462
|
+
const valueBase = {
|
|
463
|
+
parentMessageId: params.parentMessageId,
|
|
464
|
+
requestId: params.requestId,
|
|
465
|
+
};
|
|
466
|
+
return JSON.stringify({
|
|
467
|
+
config: { wide_screen_mode: true },
|
|
468
|
+
header: { template: "yellow", title: { content: "确认 Codex 主动重置", tag: "plain_text" } },
|
|
469
|
+
elements: [
|
|
470
|
+
{
|
|
471
|
+
tag: "div",
|
|
472
|
+
text: {
|
|
473
|
+
tag: "lark_md",
|
|
474
|
+
content: `当前可用主动重置次数:**${params.availableCount}**。\n\n确认后会消耗 1 次主动重置,并重置当前可重置的 Codex 用量窗口。`,
|
|
475
|
+
},
|
|
476
|
+
},
|
|
477
|
+
{ tag: "hr" },
|
|
478
|
+
{
|
|
479
|
+
tag: "action",
|
|
480
|
+
actions: [
|
|
481
|
+
{
|
|
482
|
+
tag: "button",
|
|
483
|
+
text: { tag: "plain_text", content: "是,发起重置" },
|
|
484
|
+
type: "danger",
|
|
485
|
+
value: { action: "codex_reset_confirm", decision: "yes", ...valueBase },
|
|
486
|
+
},
|
|
487
|
+
{
|
|
488
|
+
tag: "button",
|
|
489
|
+
text: { tag: "plain_text", content: "否" },
|
|
490
|
+
type: "default",
|
|
491
|
+
value: { action: "codex_reset_confirm", decision: "no", ...valueBase },
|
|
492
|
+
},
|
|
493
|
+
],
|
|
494
|
+
},
|
|
495
|
+
],
|
|
496
|
+
});
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
/** 模型切换卡片(/model 命令,飞书专用,含切换按钮) */
|
|
500
|
+
export function buildModelCard(
|
|
501
|
+
currentModel: string,
|
|
502
|
+
models: string[],
|
|
503
|
+
tool?: string,
|
|
504
|
+
): string {
|
|
505
505
|
const toolLabel = tool ? ` (${tool})` : "";
|
|
506
506
|
const currentLine = currentModel
|
|
507
507
|
? `**当前模型:** \`${currentModel}\``
|
|
@@ -535,48 +535,48 @@ export function buildModelCard(
|
|
|
535
535
|
{ tag: "div", text: { tag: "lark_md", content: lines.join("\n") } },
|
|
536
536
|
{ tag: "hr" },
|
|
537
537
|
buildButtons(buttons),
|
|
538
|
-
],
|
|
539
|
-
});
|
|
540
|
-
}
|
|
541
|
-
|
|
542
|
-
export function buildEffortCard(
|
|
543
|
-
currentEffort: string,
|
|
544
|
-
efforts: string[],
|
|
545
|
-
tool?: string,
|
|
546
|
-
): string {
|
|
547
|
-
const toolLabel = tool ? ` (${tool})` : "";
|
|
548
|
-
const currentLine = currentEffort
|
|
549
|
-
? `**当前 effort:** \`${currentEffort}\``
|
|
550
|
-
: "**当前 effort:** 未指定";
|
|
551
|
-
|
|
552
|
-
const lines: string[] = [currentLine];
|
|
553
|
-
if (efforts.length > 0) {
|
|
554
|
-
lines.push("", "**可切换 effort**");
|
|
555
|
-
for (const effort of efforts) {
|
|
556
|
-
lines.push(`- \`${effort}\``);
|
|
557
|
-
}
|
|
558
|
-
lines.push("", "点击按钮切换 effort,或输入 `/effort clear` 恢复默认");
|
|
559
|
-
} else {
|
|
560
|
-
lines.push("", "当前 agent 不支持 effort 切换。");
|
|
561
|
-
}
|
|
562
|
-
|
|
563
|
-
const buttons: ButtonDef[] = [];
|
|
564
|
-
for (const effort of efforts.slice(0, 20)) {
|
|
565
|
-
buttons.push({
|
|
566
|
-
text: `/effort ${effort}`,
|
|
567
|
-
value: JSON.stringify({ cmd: `/effort ${effort}` }),
|
|
568
|
-
type: "primary",
|
|
569
|
-
});
|
|
570
|
-
}
|
|
571
|
-
|
|
572
|
-
return JSON.stringify({
|
|
573
|
-
config: { wide_screen_mode: true },
|
|
574
|
-
header: { template: "blue", title: { content: `Effort 切换${toolLabel}`, tag: "plain_text" } },
|
|
575
|
-
elements: [
|
|
576
|
-
{ tag: "div", text: { tag: "lark_md", content: lines.join("\n") } },
|
|
577
|
-
{ tag: "hr" },
|
|
578
|
-
buildButtons(buttons),
|
|
579
|
-
],
|
|
580
|
-
});
|
|
581
|
-
}
|
|
538
|
+
],
|
|
539
|
+
});
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
export function buildEffortCard(
|
|
543
|
+
currentEffort: string,
|
|
544
|
+
efforts: string[],
|
|
545
|
+
tool?: string,
|
|
546
|
+
): string {
|
|
547
|
+
const toolLabel = tool ? ` (${tool})` : "";
|
|
548
|
+
const currentLine = currentEffort
|
|
549
|
+
? `**当前 effort:** \`${currentEffort}\``
|
|
550
|
+
: "**当前 effort:** 未指定";
|
|
551
|
+
|
|
552
|
+
const lines: string[] = [currentLine];
|
|
553
|
+
if (efforts.length > 0) {
|
|
554
|
+
lines.push("", "**可切换 effort**");
|
|
555
|
+
for (const effort of efforts) {
|
|
556
|
+
lines.push(`- \`${effort}\``);
|
|
557
|
+
}
|
|
558
|
+
lines.push("", "点击按钮切换 effort,或输入 `/effort clear` 恢复默认");
|
|
559
|
+
} else {
|
|
560
|
+
lines.push("", "当前 agent 不支持 effort 切换。");
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
const buttons: ButtonDef[] = [];
|
|
564
|
+
for (const effort of efforts.slice(0, 20)) {
|
|
565
|
+
buttons.push({
|
|
566
|
+
text: `/effort ${effort}`,
|
|
567
|
+
value: JSON.stringify({ cmd: `/effort ${effort}` }),
|
|
568
|
+
type: "primary",
|
|
569
|
+
});
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
return JSON.stringify({
|
|
573
|
+
config: { wide_screen_mode: true },
|
|
574
|
+
header: { template: "blue", title: { content: `Effort 切换${toolLabel}`, tag: "plain_text" } },
|
|
575
|
+
elements: [
|
|
576
|
+
{ tag: "div", text: { tag: "lark_md", content: lines.join("\n") } },
|
|
577
|
+
{ tag: "hr" },
|
|
578
|
+
buildButtons(buttons),
|
|
579
|
+
],
|
|
580
|
+
});
|
|
581
|
+
}
|
|
582
582
|
|