chatccc 0.2.55 → 0.2.57
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/README.md +6 -4
- package/config.sample.json +8 -7
- package/package.json +59 -59
- package/src/__tests__/claude-adapter.test.ts +48 -9
- package/src/__tests__/config-reload.test.ts +14 -10
- package/src/__tests__/config-sample.test.ts +22 -11
- package/src/__tests__/privacy.test.ts +142 -142
- package/src/__tests__/session.test.ts +2 -2
- package/src/__tests__/simplify.test.ts +282 -282
- package/src/__tests__/web-ui.test.ts +23 -6
- package/src/__tests__/wechat-platform.test.ts +25 -0
- package/src/adapters/claude-adapter.ts +49 -28
- package/src/adapters/codex-adapter.ts +4 -0
- package/src/adapters/cursor-adapter.ts +4 -0
- package/src/config.ts +14 -1
- package/src/index.ts +15 -12
- package/src/privacy.ts +67 -67
- package/src/session.ts +10 -3
- package/src/simplify.ts +119 -119
- package/src/web-ui.ts +53 -9
- package/src/wechat-platform.ts +1 -1
package/src/simplify.ts
CHANGED
|
@@ -1,120 +1,120 @@
|
|
|
1
|
-
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
-
import { resolve as resolvePath } from "node:path";
|
|
3
|
-
import { PROJECT_ROOT } from "./config.ts";
|
|
4
|
-
|
|
5
|
-
// ---------------------------------------------------------------------------
|
|
6
|
-
// 消息简化规则 —— 数据驱动,在 simplify.json 中配置
|
|
7
|
-
// ---------------------------------------------------------------------------
|
|
8
|
-
|
|
9
|
-
interface ToolRule {
|
|
10
|
-
template: string;
|
|
11
|
-
maxLength: number;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
interface SimplifyConfig {
|
|
15
|
-
tool_use?: Record<string, ToolRule>;
|
|
16
|
-
tool_result?: Record<string, ToolRule>;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
let config: SimplifyConfig | null = null;
|
|
20
|
-
let loaded = false;
|
|
21
|
-
|
|
22
|
-
function loadConfig(): SimplifyConfig {
|
|
23
|
-
const filePath = resolvePath(PROJECT_ROOT, "simplify.json");
|
|
24
|
-
if (!existsSync(filePath)) return {};
|
|
25
|
-
try {
|
|
26
|
-
const raw = readFileSync(filePath, "utf-8");
|
|
27
|
-
const parsed = JSON.parse(raw);
|
|
28
|
-
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
29
|
-
console.error("[SIMPLIFY] simplify.json 格式错误:应为对象");
|
|
30
|
-
return {};
|
|
31
|
-
}
|
|
32
|
-
return parsed as SimplifyConfig;
|
|
33
|
-
} catch (err) {
|
|
34
|
-
console.error(`[SIMPLIFY] 读取 simplify.json 失败: ${(err as Error).message}`);
|
|
35
|
-
return {};
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
function getConfig(): SimplifyConfig {
|
|
40
|
-
if (!loaded) {
|
|
41
|
-
config = loadConfig();
|
|
42
|
-
loaded = true;
|
|
43
|
-
}
|
|
44
|
-
return config!;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/** 热重载 */
|
|
48
|
-
export function reloadSimplifyConfig(): void {
|
|
49
|
-
loaded = false;
|
|
50
|
-
config = null;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* 对模板字符串中的 {field} 占位符做替换。
|
|
55
|
-
* fields 为可用字段映射,extra 是额外的上下文(如 tool_use_id 的 id)。
|
|
56
|
-
*/
|
|
57
|
-
function resolveTemplate(template: string, fields: Record<string, unknown>, extra?: Record<string, string>): string {
|
|
58
|
-
let result = template;
|
|
59
|
-
if (extra) {
|
|
60
|
-
for (const [k, v] of Object.entries(extra)) {
|
|
61
|
-
result = result.split(`{${k}}`).join(v);
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
for (const [k, v] of Object.entries(fields)) {
|
|
65
|
-
const strVal = typeof v === "string" ? v : JSON.stringify(v);
|
|
66
|
-
result = result.split(`{${k}}`).join(strVal);
|
|
67
|
-
}
|
|
68
|
-
return result;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* 简化 tool_use 展示。
|
|
73
|
-
* 返回 null 表示无规则,调用方应回退到默认格式化。
|
|
74
|
-
*/
|
|
75
|
-
export function simplifyToolUse(name: string, input: unknown): string | null {
|
|
76
|
-
const cfg = getConfig();
|
|
77
|
-
const rules = cfg.tool_use;
|
|
78
|
-
if (!rules) return null;
|
|
79
|
-
const rule = rules[name];
|
|
80
|
-
if (!rule) return null;
|
|
81
|
-
|
|
82
|
-
const fields = typeof input === "object" && input !== null
|
|
83
|
-
? input as Record<string, unknown>
|
|
84
|
-
: {};
|
|
85
|
-
let result = resolveTemplate(rule.template, fields);
|
|
86
|
-
if (result.length > rule.maxLength) {
|
|
87
|
-
result = result.slice(0, rule.maxLength) + "...";
|
|
88
|
-
}
|
|
89
|
-
return result;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* 简化 tool_result 展示。
|
|
94
|
-
* 返回 null 表示无规则,调用方应回退到默认格式化。
|
|
95
|
-
* toolCallInput 为对应的 tool_use 输入(可选),用于在 result 模板中引用输入字段。
|
|
96
|
-
*/
|
|
97
|
-
export function simplifyToolResult(
|
|
98
|
-
name: string,
|
|
99
|
-
toolUseId: string,
|
|
100
|
-
isError: boolean,
|
|
101
|
-
toolCallInput?: unknown,
|
|
102
|
-
): string | null {
|
|
103
|
-
const cfg = getConfig();
|
|
104
|
-
const rules = cfg.tool_result;
|
|
105
|
-
if (!rules) return null;
|
|
106
|
-
const rule = rules[name];
|
|
107
|
-
if (!rule) return null;
|
|
108
|
-
|
|
109
|
-
const id = toolUseId.slice(-6);
|
|
110
|
-
const extra = { id };
|
|
111
|
-
const fields = toolCallInput && typeof toolCallInput === "object"
|
|
112
|
-
? toolCallInput as Record<string, unknown>
|
|
113
|
-
: {};
|
|
114
|
-
let result = resolveTemplate(rule.template, fields, extra);
|
|
115
|
-
if (isError) result = "❌ " + result;
|
|
116
|
-
if (result.length > rule.maxLength) {
|
|
117
|
-
result = result.slice(0, rule.maxLength) + "...";
|
|
118
|
-
}
|
|
119
|
-
return result;
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { resolve as resolvePath } from "node:path";
|
|
3
|
+
import { PROJECT_ROOT } from "./config.ts";
|
|
4
|
+
|
|
5
|
+
// ---------------------------------------------------------------------------
|
|
6
|
+
// 消息简化规则 —— 数据驱动,在 simplify.json 中配置
|
|
7
|
+
// ---------------------------------------------------------------------------
|
|
8
|
+
|
|
9
|
+
interface ToolRule {
|
|
10
|
+
template: string;
|
|
11
|
+
maxLength: number;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
interface SimplifyConfig {
|
|
15
|
+
tool_use?: Record<string, ToolRule>;
|
|
16
|
+
tool_result?: Record<string, ToolRule>;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
let config: SimplifyConfig | null = null;
|
|
20
|
+
let loaded = false;
|
|
21
|
+
|
|
22
|
+
function loadConfig(): SimplifyConfig {
|
|
23
|
+
const filePath = resolvePath(PROJECT_ROOT, "simplify.json");
|
|
24
|
+
if (!existsSync(filePath)) return {};
|
|
25
|
+
try {
|
|
26
|
+
const raw = readFileSync(filePath, "utf-8");
|
|
27
|
+
const parsed = JSON.parse(raw);
|
|
28
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
29
|
+
console.error("[SIMPLIFY] simplify.json 格式错误:应为对象");
|
|
30
|
+
return {};
|
|
31
|
+
}
|
|
32
|
+
return parsed as SimplifyConfig;
|
|
33
|
+
} catch (err) {
|
|
34
|
+
console.error(`[SIMPLIFY] 读取 simplify.json 失败: ${(err as Error).message}`);
|
|
35
|
+
return {};
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function getConfig(): SimplifyConfig {
|
|
40
|
+
if (!loaded) {
|
|
41
|
+
config = loadConfig();
|
|
42
|
+
loaded = true;
|
|
43
|
+
}
|
|
44
|
+
return config!;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** 热重载 */
|
|
48
|
+
export function reloadSimplifyConfig(): void {
|
|
49
|
+
loaded = false;
|
|
50
|
+
config = null;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* 对模板字符串中的 {field} 占位符做替换。
|
|
55
|
+
* fields 为可用字段映射,extra 是额外的上下文(如 tool_use_id 的 id)。
|
|
56
|
+
*/
|
|
57
|
+
function resolveTemplate(template: string, fields: Record<string, unknown>, extra?: Record<string, string>): string {
|
|
58
|
+
let result = template;
|
|
59
|
+
if (extra) {
|
|
60
|
+
for (const [k, v] of Object.entries(extra)) {
|
|
61
|
+
result = result.split(`{${k}}`).join(v);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
for (const [k, v] of Object.entries(fields)) {
|
|
65
|
+
const strVal = typeof v === "string" ? v : JSON.stringify(v);
|
|
66
|
+
result = result.split(`{${k}}`).join(strVal);
|
|
67
|
+
}
|
|
68
|
+
return result;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* 简化 tool_use 展示。
|
|
73
|
+
* 返回 null 表示无规则,调用方应回退到默认格式化。
|
|
74
|
+
*/
|
|
75
|
+
export function simplifyToolUse(name: string, input: unknown): string | null {
|
|
76
|
+
const cfg = getConfig();
|
|
77
|
+
const rules = cfg.tool_use;
|
|
78
|
+
if (!rules) return null;
|
|
79
|
+
const rule = rules[name];
|
|
80
|
+
if (!rule) return null;
|
|
81
|
+
|
|
82
|
+
const fields = typeof input === "object" && input !== null
|
|
83
|
+
? input as Record<string, unknown>
|
|
84
|
+
: {};
|
|
85
|
+
let result = resolveTemplate(rule.template, fields);
|
|
86
|
+
if (result.length > rule.maxLength) {
|
|
87
|
+
result = result.slice(0, rule.maxLength) + "...";
|
|
88
|
+
}
|
|
89
|
+
return result;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* 简化 tool_result 展示。
|
|
94
|
+
* 返回 null 表示无规则,调用方应回退到默认格式化。
|
|
95
|
+
* toolCallInput 为对应的 tool_use 输入(可选),用于在 result 模板中引用输入字段。
|
|
96
|
+
*/
|
|
97
|
+
export function simplifyToolResult(
|
|
98
|
+
name: string,
|
|
99
|
+
toolUseId: string,
|
|
100
|
+
isError: boolean,
|
|
101
|
+
toolCallInput?: unknown,
|
|
102
|
+
): string | null {
|
|
103
|
+
const cfg = getConfig();
|
|
104
|
+
const rules = cfg.tool_result;
|
|
105
|
+
if (!rules) return null;
|
|
106
|
+
const rule = rules[name];
|
|
107
|
+
if (!rule) return null;
|
|
108
|
+
|
|
109
|
+
const id = toolUseId.slice(-6);
|
|
110
|
+
const extra = { id };
|
|
111
|
+
const fields = toolCallInput && typeof toolCallInput === "object"
|
|
112
|
+
? toolCallInput as Record<string, unknown>
|
|
113
|
+
: {};
|
|
114
|
+
let result = resolveTemplate(rule.template, fields, extra);
|
|
115
|
+
if (isError) result = "❌ " + result;
|
|
116
|
+
if (result.length > rule.maxLength) {
|
|
117
|
+
result = result.slice(0, rule.maxLength) + "...";
|
|
118
|
+
}
|
|
119
|
+
return result;
|
|
120
120
|
}
|
package/src/web-ui.ts
CHANGED
|
@@ -31,7 +31,7 @@ interface AppConfig {
|
|
|
31
31
|
platforms?: { feishu?: { enabled?: boolean }; ilink?: { enabled?: boolean } };
|
|
32
32
|
port?: number;
|
|
33
33
|
gitTimeoutSeconds?: number;
|
|
34
|
-
claude?: { enabled?: boolean; defaultAgent?: boolean; model?: string; effort?: string; apiKey?: string; baseUrl?: string };
|
|
34
|
+
claude?: { enabled?: boolean; defaultAgent?: boolean; model?: string; subagentModel?: string; effort?: string; apiKey?: string; baseUrl?: string };
|
|
35
35
|
// `command` 是已废弃的旧字段名,保留只读以兼容升级前的 config.json
|
|
36
36
|
cursor?: { enabled?: boolean; defaultAgent?: boolean; path?: string; command?: string; model?: string };
|
|
37
37
|
codex?: { enabled?: boolean; defaultAgent?: boolean; path?: string; command?: string; model?: string; effort?: string };
|
|
@@ -126,7 +126,11 @@ function readToolPath(tool?: { path?: string; command?: string }): string {
|
|
|
126
126
|
function loadConfig(): AppConfig {
|
|
127
127
|
if (!existsSync(CONFIG_FILE)) return {};
|
|
128
128
|
try {
|
|
129
|
-
|
|
129
|
+
let raw = readFileSync(CONFIG_FILE, "utf8");
|
|
130
|
+
// 移除可能意外写入的 UTF-8 BOM,避免 JSON.parse 失败导致返回空对象、
|
|
131
|
+
// UI 显示所有配置为空。
|
|
132
|
+
if (raw.charCodeAt(0) === 0xfeff) raw = raw.slice(1);
|
|
133
|
+
return JSON.parse(raw);
|
|
130
134
|
} catch {
|
|
131
135
|
return {};
|
|
132
136
|
}
|
|
@@ -330,7 +334,7 @@ function deepMerge(target: Record<string, unknown>, source: Record<string, unkno
|
|
|
330
334
|
}
|
|
331
335
|
|
|
332
336
|
// Convert flat key-value pairs to nested config structure
|
|
333
|
-
function unflattenConfig(flat: Record<string, unknown>): Record<string, unknown> {
|
|
337
|
+
export function unflattenConfig(flat: Record<string, unknown>): Record<string, unknown> {
|
|
334
338
|
const result: Record<string, unknown> = {};
|
|
335
339
|
for (const [key, val] of Object.entries(flat)) {
|
|
336
340
|
if (key === "CHATCCC_APP_ID") {
|
|
@@ -360,6 +364,9 @@ function unflattenConfig(flat: Record<string, unknown>): Record<string, unknown>
|
|
|
360
364
|
} else if (key === "CHATCCC_ANTHROPIC_MODEL") {
|
|
361
365
|
result.claude = result.claude || {};
|
|
362
366
|
(result.claude as Record<string, unknown>).model = val;
|
|
367
|
+
} else if (key === "CHATCCC_ANTHROPIC_SUBAGENT_MODEL") {
|
|
368
|
+
result.claude = result.claude || {};
|
|
369
|
+
(result.claude as Record<string, unknown>).subagentModel = val;
|
|
363
370
|
} else if (key === "CHATCCC_ANTHROPIC_EFFORT") {
|
|
364
371
|
result.claude = result.claude || {};
|
|
365
372
|
(result.claude as Record<string, unknown>).effort = val;
|
|
@@ -705,6 +712,10 @@ header .badge{font-size:13px;padding:4px 12px;border-radius:12px;font-weight:500
|
|
|
705
712
|
<label>模型</label>
|
|
706
713
|
<input type="text" id="field-CHATCCC_ANTHROPIC_MODEL" placeholder="留空表示不向 SDK 传 model">
|
|
707
714
|
</div>
|
|
715
|
+
<div class="form-group" id="claude-subagent-model-field">
|
|
716
|
+
<label>Subagent 模型</label>
|
|
717
|
+
<input type="text" id="field-CHATCCC_ANTHROPIC_SUBAGENT_MODEL" placeholder="留空表示不向 SDK 传 CLAUDE_CODE_SUBAGENT_MODEL">
|
|
718
|
+
</div>
|
|
708
719
|
<div class="form-group">
|
|
709
720
|
<label>思考深度 (Effort)</label>
|
|
710
721
|
<input type="text" id="field-CHATCCC_ANTHROPIC_EFFORT" placeholder="留空表示不向 SDK 传 effort">
|
|
@@ -844,6 +855,7 @@ header .badge{font-size:13px;padding:4px 12px;border-radius:12px;font-weight:500
|
|
|
844
855
|
<div class="config-row" id="cfg-row-CLAUDE_API_KEY"><span class="key">API Key</span><span class="val" id="cfg-CLAUDE_API_KEY">-</span></div>
|
|
845
856
|
<div class="config-row" id="cfg-row-CLAUDE_BASE_URL"><span class="key">Base URL</span><span class="val" id="cfg-CLAUDE_BASE_URL">-</span></div>
|
|
846
857
|
<div class="config-row"><span class="key">模型</span><span class="val" id="cfg-ANTHROPIC_MODEL">-</span></div>
|
|
858
|
+
<div class="config-row" id="cfg-row-ANTHROPIC_SUBAGENT_MODEL"><span class="key">Subagent 模型</span><span class="val" id="cfg-ANTHROPIC_SUBAGENT_MODEL">-</span></div>
|
|
847
859
|
<div class="config-row"><span class="key">Effort</span><span class="val" id="cfg-ANTHROPIC_EFFORT">-</span></div>
|
|
848
860
|
<label class="agent-default-row" style="margin-top:10px"><input type="checkbox" id="dash-default-claude" onchange="setDashboardDefaultAgent('claude', this.checked)"> 设为默认 Agent</label>
|
|
849
861
|
<button class="btn btn-outline" style="margin-top:8px" onclick="editSection('claude')">编辑</button>
|
|
@@ -911,7 +923,7 @@ let state = {
|
|
|
911
923
|
var step2InputBound = false;
|
|
912
924
|
|
|
913
925
|
const AGENT_FIELDS = {
|
|
914
|
-
claude: ['CLAUDE_API_KEY','CLAUDE_BASE_URL','CHATCCC_ANTHROPIC_MODEL','CHATCCC_ANTHROPIC_EFFORT'],
|
|
926
|
+
claude: ['CLAUDE_API_KEY','CLAUDE_BASE_URL','CHATCCC_ANTHROPIC_MODEL','CHATCCC_ANTHROPIC_SUBAGENT_MODEL','CHATCCC_ANTHROPIC_EFFORT'],
|
|
915
927
|
cursor: ['CHATCCC_CURSOR_PATH','CHATCCC_CURSOR_MODEL'],
|
|
916
928
|
codex: ['CHATCCC_CODEX_PATH','CHATCCC_CODEX_MODEL','CHATCCC_CODEX_EFFORT']
|
|
917
929
|
};
|
|
@@ -925,7 +937,11 @@ var claudeApiMode = 'official';
|
|
|
925
937
|
// 示例只是引导);官方模式不列举任何具体值,避免给出过期/不支持的取值产生误导。
|
|
926
938
|
var CLAUDE_MODEL_PLACEHOLDER = {
|
|
927
939
|
official: '留空表示不向 SDK 传 model',
|
|
928
|
-
thirdparty: '
|
|
940
|
+
thirdparty: 'claude-sonnet-4-6'
|
|
941
|
+
};
|
|
942
|
+
var CLAUDE_SUBAGENT_MODEL_PLACEHOLDER = {
|
|
943
|
+
official: '留空表示不向 SDK 传 CLAUDE_CODE_SUBAGENT_MODEL',
|
|
944
|
+
thirdparty: 'claude-haiku-4-5-20251001'
|
|
929
945
|
};
|
|
930
946
|
var CLAUDE_EFFORT_PLACEHOLDER = {
|
|
931
947
|
official: '留空表示不向 SDK 传 effort',
|
|
@@ -943,13 +959,23 @@ function onClaudeApiModeChange(mode) {
|
|
|
943
959
|
if (editThirdPartyEl) {
|
|
944
960
|
editThirdPartyEl.classList.toggle('hidden', mode !== 'thirdparty');
|
|
945
961
|
}
|
|
962
|
+
var wizardSubagentField = document.getElementById('claude-subagent-model-field');
|
|
963
|
+
if (wizardSubagentField) wizardSubagentField.classList.toggle('hidden', mode !== 'thirdparty');
|
|
964
|
+
document.querySelectorAll('[data-claude-subagent-field]').forEach(function(el){
|
|
965
|
+
el.classList.toggle('hidden', mode !== 'thirdparty');
|
|
966
|
+
});
|
|
946
967
|
// 同步 model / effort 输入框的 placeholder(Wizard + Edit Modal 两处都更新)
|
|
947
968
|
var modelPlaceholder = CLAUDE_MODEL_PLACEHOLDER[mode] || CLAUDE_MODEL_PLACEHOLDER.official;
|
|
969
|
+
var subagentModelPlaceholder = CLAUDE_SUBAGENT_MODEL_PLACEHOLDER[mode] || CLAUDE_SUBAGENT_MODEL_PLACEHOLDER.official;
|
|
948
970
|
var effortPlaceholder = CLAUDE_EFFORT_PLACEHOLDER[mode] || CLAUDE_EFFORT_PLACEHOLDER.official;
|
|
949
971
|
var wizardModelEl = document.getElementById('field-CHATCCC_ANTHROPIC_MODEL');
|
|
950
972
|
if (wizardModelEl) wizardModelEl.placeholder = modelPlaceholder;
|
|
951
973
|
var editModelEl = document.getElementById('edit-CHATCCC_ANTHROPIC_MODEL');
|
|
952
974
|
if (editModelEl) editModelEl.placeholder = modelPlaceholder;
|
|
975
|
+
var wizardSubagentModelEl = document.getElementById('field-CHATCCC_ANTHROPIC_SUBAGENT_MODEL');
|
|
976
|
+
if (wizardSubagentModelEl) wizardSubagentModelEl.placeholder = subagentModelPlaceholder;
|
|
977
|
+
var editSubagentModelEl = document.getElementById('edit-CHATCCC_ANTHROPIC_SUBAGENT_MODEL');
|
|
978
|
+
if (editSubagentModelEl) editSubagentModelEl.placeholder = subagentModelPlaceholder;
|
|
953
979
|
var wizardEffortEl = document.getElementById('field-CHATCCC_ANTHROPIC_EFFORT');
|
|
954
980
|
if (wizardEffortEl) wizardEffortEl.placeholder = effortPlaceholder;
|
|
955
981
|
var editEffortEl = document.getElementById('edit-CHATCCC_ANTHROPIC_EFFORT');
|
|
@@ -1200,7 +1226,7 @@ function isAgentEnabled(node, keys) {
|
|
|
1200
1226
|
return false;
|
|
1201
1227
|
}
|
|
1202
1228
|
|
|
1203
|
-
var CLAUDE_FALLBACK_KEYS = ['apiKey','baseUrl','model','effort'];
|
|
1229
|
+
var CLAUDE_FALLBACK_KEYS = ['apiKey','baseUrl','model','subagentModel','effort'];
|
|
1204
1230
|
var CURSOR_FALLBACK_KEYS = ['path','command','model'];
|
|
1205
1231
|
var CODEX_FALLBACK_KEYS = ['path','command','model','effort'];
|
|
1206
1232
|
|
|
@@ -1210,6 +1236,7 @@ function renderStep2() {
|
|
|
1210
1236
|
prefillNested('field-CLAUDE_API_KEY', c.claude.apiKey);
|
|
1211
1237
|
prefillNested('field-CLAUDE_BASE_URL', c.claude.baseUrl);
|
|
1212
1238
|
prefillNested('field-CHATCCC_ANTHROPIC_MODEL', c.claude.model);
|
|
1239
|
+
prefillNested('field-CHATCCC_ANTHROPIC_SUBAGENT_MODEL', c.claude.subagentModel);
|
|
1213
1240
|
prefillNested('field-CHATCCC_ANTHROPIC_EFFORT', c.claude.effort);
|
|
1214
1241
|
}
|
|
1215
1242
|
// 按已有 apiKey/baseUrl 判定初始 API 模式,并相应显示/隐藏字段
|
|
@@ -1285,6 +1312,7 @@ function collectAllFields() {
|
|
|
1285
1312
|
vars.CHATCCC_CODEX_DEFAULT_AGENT = state.defaultAgent === 'codex';
|
|
1286
1313
|
if (state.agentsEnabled.claude) {
|
|
1287
1314
|
AGENT_FIELDS.claude.forEach(function(key){
|
|
1315
|
+
if (claudeApiMode !== 'thirdparty' && key === 'CHATCCC_ANTHROPIC_SUBAGENT_MODEL') return;
|
|
1288
1316
|
var el = document.getElementById('field-' + key);
|
|
1289
1317
|
if (el && el.value.trim()) vars[key] = el.value.trim();
|
|
1290
1318
|
});
|
|
@@ -1345,6 +1373,7 @@ function renderStep3() {
|
|
|
1345
1373
|
if (claudeApiMode === 'thirdparty') {
|
|
1346
1374
|
lines.push('<div class="config-row"><span class="key">API Key</span><span class="val">' + (vars.CLAUDE_API_KEY ? '***已设置***' : '(未设置)') + '</span></div>');
|
|
1347
1375
|
if (vars.CLAUDE_BASE_URL) lines.push('<div class="config-row"><span class="key">Base URL</span><span class="val">' + vars.CLAUDE_BASE_URL + '</span></div>');
|
|
1376
|
+
lines.push('<div class="config-row"><span class="key">Subagent 模型</span><span class="val">' + (vars.CHATCCC_ANTHROPIC_SUBAGENT_MODEL || '(留空)') + '</span></div>');
|
|
1348
1377
|
}
|
|
1349
1378
|
lines.push('<div class="config-row"><span class="key">模型</span><span class="val">' + (vars.CHATCCC_ANTHROPIC_MODEL || '(留空)') + '</span></div>');
|
|
1350
1379
|
lines.push('<div class="config-row"><span class="key">Effort</span><span class="val">' + (vars.CHATCCC_ANTHROPIC_EFFORT || '(留空)') + '</span></div>');
|
|
@@ -1542,6 +1571,8 @@ function updateDashboardUI() {
|
|
|
1542
1571
|
document.getElementById('cfg-CLAUDE_API_KEY').textContent = claudeApiKey ? '***已设置***' : '-';
|
|
1543
1572
|
document.getElementById('cfg-CLAUDE_BASE_URL').textContent = claudeBaseUrl || '-';
|
|
1544
1573
|
document.getElementById('cfg-ANTHROPIC_MODEL').textContent = (c.claude && c.claude.model) || '(留空)';
|
|
1574
|
+
document.getElementById('cfg-row-ANTHROPIC_SUBAGENT_MODEL').style.display = isThirdPartyClaude ? '' : 'none';
|
|
1575
|
+
document.getElementById('cfg-ANTHROPIC_SUBAGENT_MODEL').textContent = (c.claude && c.claude.subagentModel) || '(留空)';
|
|
1545
1576
|
document.getElementById('cfg-ANTHROPIC_EFFORT').textContent = (c.claude && c.claude.effort) || '(留空)';
|
|
1546
1577
|
document.getElementById('cfg-CURSOR_PATH').textContent = (c.cursor && (c.cursor.path || c.cursor.command)) || '-';
|
|
1547
1578
|
document.getElementById('cfg-CURSOR_MODEL').textContent = (c.cursor && c.cursor.model) || '(留空)';
|
|
@@ -1603,7 +1634,7 @@ function editSection(section) {
|
|
|
1603
1634
|
var labelMap = {
|
|
1604
1635
|
'CHATCCC_APP_ID': 'App ID', 'CHATCCC_APP_SECRET': 'App Secret',
|
|
1605
1636
|
'CLAUDE_API_KEY': 'API Key', 'CLAUDE_BASE_URL': 'Base URL',
|
|
1606
|
-
'CHATCCC_ANTHROPIC_MODEL': '模型', 'CHATCCC_ANTHROPIC_EFFORT': 'Effort',
|
|
1637
|
+
'CHATCCC_ANTHROPIC_MODEL': '模型', 'CHATCCC_ANTHROPIC_SUBAGENT_MODEL': 'Subagent 模型', 'CHATCCC_ANTHROPIC_EFFORT': 'Effort',
|
|
1607
1638
|
'CHATCCC_CURSOR_PATH': 'CLI 路径', 'CHATCCC_CURSOR_MODEL': '模型',
|
|
1608
1639
|
'CHATCCC_CODEX_PATH': 'CLI 路径', 'CHATCCC_CODEX_MODEL': '模型', 'CHATCCC_CODEX_EFFORT': 'Effort'
|
|
1609
1640
|
};
|
|
@@ -1630,6 +1661,7 @@ function editSection(section) {
|
|
|
1630
1661
|
}
|
|
1631
1662
|
|
|
1632
1663
|
var thirdPartyOpened = false;
|
|
1664
|
+
var thirdPartyClosed = false;
|
|
1633
1665
|
fields.forEach(function(key){
|
|
1634
1666
|
var val = state.config[key] || '';
|
|
1635
1667
|
// Also check nested config
|
|
@@ -1641,6 +1673,7 @@ function editSection(section) {
|
|
|
1641
1673
|
if (key === 'CLAUDE_API_KEY') val = state.config.claude.apiKey || '';
|
|
1642
1674
|
else if (key === 'CLAUDE_BASE_URL') val = state.config.claude.baseUrl || '';
|
|
1643
1675
|
else if (key === 'CHATCCC_ANTHROPIC_MODEL') val = state.config.claude.model || '';
|
|
1676
|
+
else if (key === 'CHATCCC_ANTHROPIC_SUBAGENT_MODEL') val = state.config.claude.subagentModel || '';
|
|
1644
1677
|
else if (key === 'CHATCCC_ANTHROPIC_EFFORT') val = state.config.claude.effort || '';
|
|
1645
1678
|
} else if (section === 'cursor' && state.config.cursor) {
|
|
1646
1679
|
if (key === 'CHATCCC_CURSOR_PATH') val = state.config.cursor.path || state.config.cursor.command || '';
|
|
@@ -1653,18 +1686,28 @@ function editSection(section) {
|
|
|
1653
1686
|
}
|
|
1654
1687
|
var isSecret = key.includes('SECRET') || key.includes('API_KEY');
|
|
1655
1688
|
var isClaudeThirdPartyField = section === 'claude' && (key === 'CLAUDE_API_KEY' || key === 'CLAUDE_BASE_URL');
|
|
1689
|
+
var isClaudeSubagentField = section === 'claude' && key === 'CHATCCC_ANTHROPIC_SUBAGENT_MODEL';
|
|
1656
1690
|
|
|
1657
1691
|
if (isClaudeThirdPartyField && !thirdPartyOpened) {
|
|
1658
1692
|
html += '<div id="edit-claude-thirdparty-fields"' + (claudeApiMode === 'thirdparty' ? '' : ' class="hidden"') + '>';
|
|
1659
1693
|
thirdPartyOpened = true;
|
|
1660
1694
|
}
|
|
1661
1695
|
|
|
1662
|
-
|
|
1696
|
+
// 在第三方字段之后、第一个通用字段之前闭合 wrapper,
|
|
1697
|
+
// 避免 model / subagentModel / effort 被包裹在 hidden div 中。
|
|
1698
|
+
if (thirdPartyOpened && !thirdPartyClosed && !isClaudeThirdPartyField) {
|
|
1699
|
+
html += '</div>';
|
|
1700
|
+
thirdPartyClosed = true;
|
|
1701
|
+
}
|
|
1702
|
+
|
|
1703
|
+
var groupClass = 'form-group' + (isClaudeSubagentField && claudeApiMode !== 'thirdparty' ? ' hidden' : '');
|
|
1704
|
+
var subagentAttr = isClaudeSubagentField ? ' data-claude-subagent-field="1"' : '';
|
|
1705
|
+
html += '<div class="' + groupClass + '"' + subagentAttr + '><label>' + (labelMap[key] || key) + '</label>';
|
|
1663
1706
|
html += '<input type="' + (isSecret ? 'password' : 'text') + '" id="edit-' + key + '" value="' + String(val).replace(/"/g,'"') + '">';
|
|
1664
1707
|
html += '</div>';
|
|
1665
1708
|
});
|
|
1666
1709
|
|
|
1667
|
-
if (thirdPartyOpened) html += '</div>';
|
|
1710
|
+
if (thirdPartyOpened && !thirdPartyClosed) html += '</div>';
|
|
1668
1711
|
|
|
1669
1712
|
document.getElementById('edit-modal-fields').innerHTML = html;
|
|
1670
1713
|
document.getElementById('edit-modal').classList.remove('hidden');
|
|
@@ -1688,6 +1731,7 @@ async function saveEdit() {
|
|
|
1688
1731
|
|
|
1689
1732
|
var vars = {};
|
|
1690
1733
|
fields.forEach(function(key){
|
|
1734
|
+
if (editSectionType === 'claude' && claudeApiMode !== 'thirdparty' && key === 'CHATCCC_ANTHROPIC_SUBAGENT_MODEL') return;
|
|
1691
1735
|
var el = document.getElementById('edit-' + key);
|
|
1692
1736
|
if (el) vars[key] = el.value.trim();
|
|
1693
1737
|
});
|
package/src/wechat-platform.ts
CHANGED
|
@@ -157,7 +157,7 @@ export function createWechatAdapter(
|
|
|
157
157
|
|
|
158
158
|
// 第10条且非最终消息:附加 claw 限制提示
|
|
159
159
|
if (count === 10 && !isFinal) {
|
|
160
|
-
text = text + "\n
|
|
160
|
+
text = text + "\n━━ 后台工作中,由于微信claw机制限制,请唤醒我才能继续发送消息";
|
|
161
161
|
}
|
|
162
162
|
|
|
163
163
|
// 超过10条后非最终消息不再发送(claw 限制)
|