minimal-agent 0.18.13 → 0.18.14
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/package.json +1 -3
- package/plugins/workflow-runner/src/runtime/context.js +1 -1
- package/plugins/workflow-runner/src/runtime/context.ts +1 -1
- package/plugins/workflow-runner/test/embeddedExecution.test.ts +2 -5
- package/plugins/workflow-runner/test/execLifetime.test.ts +15 -2
- package/skills/ssh-remote-dev/SKILL.md +61 -0
- package/skills/ssh-remote-dev/agents/openai.yaml +4 -0
- package/src/advisor/README.md +62 -24
- package/src/advisor/advisorNudge.js +199 -0
- package/src/advisor/advisorNudge.ts +232 -0
- package/src/advisor/deliveryReview.js +35 -12
- package/src/advisor/deliveryReview.ts +35 -11
- package/src/advisor/presentation.js +7 -10
- package/src/advisor/presentation.ts +10 -13
- package/src/advisor/reviewContext.js +22 -58
- package/src/advisor/reviewContext.ts +24 -67
- package/src/cli/configMenu.js +17 -128
- package/src/cli/configMenu.tsx +17 -193
- package/src/cli/print.js +2 -0
- package/src/cli/print.ts +2 -0
- package/src/cli/streamJson.js +2 -0
- package/src/cli/streamJson.ts +2 -0
- package/src/cli/wizards/advisorWizard.js +9 -7
- package/src/cli/wizards/advisorWizard.tsx +9 -7
- package/src/cli/wizards/contextAdvisorWizard.js +9 -7
- package/src/cli/wizards/contextAdvisorWizard.tsx +9 -7
- package/src/cli/wizards/providerPresets.js +27 -1
- package/src/cli/wizards/providerPresets.ts +44 -2
- package/src/cli/wizards/providerWizard.js +51 -10
- package/src/cli/wizards/providerWizard.tsx +59 -9
- package/src/config/configDefaults.js +1 -1
- package/src/config/configDefaults.ts +1 -1
- package/src/config/configDiagnostics.js +1 -21
- package/src/config/configDiagnostics.ts +3 -23
- package/src/config/configFile.js +11 -4
- package/src/config/configFile.ts +27 -7
- package/src/config/configManagement.js +1 -0
- package/src/config/configManagement.ts +2 -0
- package/src/config/configService.js +12 -8
- package/src/config/configService.ts +16 -11
- package/src/config/numericLimits.js +0 -4
- package/src/config/numericLimits.ts +0 -4
- package/src/config/reasoningEffort.js +16 -0
- package/src/config/reasoningEffort.ts +18 -0
- package/src/context/budgetPlan.js +1 -1
- package/src/context/budgetPlan.ts +1 -1
- package/src/context/optimizeConversation.js +1 -1
- package/src/context/optimizeConversation.ts +1 -1
- package/src/harness/stallGuard.js +8 -13
- package/src/harness/stallGuard.ts +8 -12
- package/src/llm/client.js +64 -17
- package/src/llm/client.ts +62 -7
- package/src/llm/providers/openaiFormat.js +14 -3
- package/src/llm/providers/openaiFormat.ts +17 -3
- package/src/llm/providers/responsesFormat.js +275 -0
- package/src/llm/providers/responsesFormat.ts +306 -0
- package/src/loop/README.md +18 -3
- package/src/loop/liveDiagramGate.js +63 -0
- package/src/loop/liveDiagramGate.ts +61 -0
- package/src/loop/messages.js +12 -0
- package/src/loop/messages.ts +13 -0
- package/src/loop/options.ts +7 -2
- package/src/loop/toolBatch.js +0 -1
- package/src/loop/toolBatch.ts +0 -1
- package/src/loop/toolExecutor.js +11 -46
- package/src/loop/toolExecutor.ts +12 -55
- package/src/loop/toolPresentation.js +2 -13
- package/src/loop/toolPresentation.ts +2 -13
- package/src/loop/toolSemantics.js +3 -4
- package/src/loop/toolSemantics.ts +4 -6
- package/src/loop.js +222 -214
- package/src/loop.ts +226 -232
- package/src/memory/dependencies.js +11 -3
- package/src/memory/dependencies.ts +11 -3
- package/src/memory/episodicMemory.js +59 -18
- package/src/memory/episodicMemory.ts +58 -18
- package/src/memory/experienceStore.js +4 -3
- package/src/memory/experienceStore.ts +4 -3
- package/src/memory/factCandidates.js +53 -1
- package/src/memory/factCandidates.ts +54 -1
- package/src/memory/factLearning.js +2 -2
- package/src/memory/factLearning.ts +2 -2
- package/src/memory/jobPolicy.js +24 -5
- package/src/memory/jobPolicy.ts +25 -5
- package/src/memory/learning.js +2 -2
- package/src/memory/learning.ts +2 -2
- package/src/memory/learningModel.js +7 -0
- package/src/memory/learningModel.ts +7 -0
- package/src/memory/managementService.js +8 -7
- package/src/memory/managementService.ts +16 -8
- package/src/memory/memoryService.js +104 -33
- package/src/memory/memoryService.ts +132 -28
- package/src/memory/projectKnowledge.js +39 -3
- package/src/memory/projectKnowledge.ts +45 -3
- package/src/memory/recallQuery.js +56 -0
- package/src/memory/recallQuery.ts +58 -0
- package/src/memory/retrieval.js +39 -10
- package/src/memory/retrieval.ts +46 -11
- package/src/memory/turnJournal.js +75 -10
- package/src/memory/turnJournal.ts +66 -10
- package/src/memory/types.ts +7 -1
- package/src/prompts/delegation.js +2 -1
- package/src/prompts/delegation.ts +3 -1
- package/src/prompts/policyRegistry.js +9 -12
- package/src/prompts/policyRegistry.ts +9 -12
- package/src/prompts/promptAssembly.js +6 -5
- package/src/prompts/promptAssembly.ts +8 -6
- package/src/prompts/visualPresentation.js +39 -10
- package/src/prompts/visualPresentation.ts +38 -9
- package/src/runtime/answerPreparation.js +1 -1
- package/src/runtime/answerPreparation.ts +1 -1
- package/src/runtime/fileLock.js +19 -3
- package/src/runtime/fileLock.ts +19 -3
- package/src/runtime/invocationPolicy.js +1 -1
- package/src/runtime/invocationPolicy.ts +1 -1
- package/src/runtime/outputContract.js +0 -4
- package/src/runtime/outputContract.ts +0 -7
- package/src/session/runAgentTurn.js +3 -0
- package/src/session/runAgentTurn.ts +3 -0
- package/src/team/onlineToolContract.js +0 -1
- package/src/team/onlineToolContract.ts +0 -1
- package/src/tools/advisor/advisor.js +207 -365
- package/src/tools/advisor/advisor.ts +211 -383
- package/src/tools/agent/agentTypes.js +0 -1
- package/src/tools/agent/agentTypes.ts +0 -1
- package/src/tools/agent/coordinator.js +4 -1
- package/src/tools/agent/coordinator.ts +4 -1
- package/src/tools/bash/semantics.js +4 -5
- package/src/tools/bash/semantics.ts +4 -5
- package/src/tools/capabilities.js +2 -3
- package/src/tools/capabilities.ts +2 -4
- package/src/tools/index.js +0 -16
- package/src/tools/index.ts +0 -16
- package/src/tools/memory/maintenance.js +8 -9
- package/src/tools/memory/maintenance.ts +13 -11
- package/src/tools/memory/memory.js +5 -1
- package/src/tools/memory/memory.ts +5 -0
- package/src/tools/optimizeConversation/README.md +4 -6
- package/src/tools/toolPromptGuides.js +2 -9
- package/src/tools/toolPromptGuides.ts +2 -9
- package/src/types.ts +28 -105
- package/src/ui/App.js +2 -0
- package/src/ui/App.tsx +1 -0
- package/src/ui/MessageList.js +8 -44
- package/src/ui/MessageList.tsx +3 -81
- package/src/ui/hooks/useChat.js +2 -0
- package/src/ui/hooks/useChat.ts +2 -0
- package/src/ui/toolProgress.js +1 -1
- package/src/ui/toolProgress.ts +1 -1
- package/src/web/protocol.ts +10 -3
- package/src/advisor/advisorCoordinator.js +0 -734
- package/src/advisor/advisorCoordinator.ts +0 -825
- package/src/cli/wizards/sshHostWizard.js +0 -156
- package/src/cli/wizards/sshHostWizard.tsx +0 -214
- package/src/context/sshHosts.js +0 -290
- package/src/context/sshHosts.ts +0 -312
- package/src/loop/publication.js +0 -94
- package/src/loop/publication.ts +0 -124
- package/src/runtime/finalAnswer.js +0 -9
- package/src/runtime/finalAnswer.ts +0 -13
- package/src/tools/advisor/advisorDecision.js +0 -79
- package/src/tools/advisor/advisorDecision.ts +0 -92
- package/src/tools/ssh/ssh.js +0 -152
- package/src/tools/ssh/ssh.ts +0 -167
- package/src/tools/ssh/sshAvailability.js +0 -35
- package/src/tools/ssh/sshAvailability.ts +0 -39
- package/src/tools/ssh/sshClient.js +0 -177
- package/src/tools/ssh/sshClient.ts +0 -189
- package/src/tools/ssh/sshDownload.js +0 -77
- package/src/tools/ssh/sshDownload.ts +0 -92
- package/src/tools/ssh/sshHostsTool.js +0 -36
- package/src/tools/ssh/sshHostsTool.ts +0 -48
- package/src/tools/ssh/sshUpload.js +0 -72
- package/src/tools/ssh/sshUpload.ts +0 -85
|
@@ -92,6 +92,14 @@ export function AdvisorWizard({ existing, models, onDone, onCancel }) {
|
|
|
92
92
|
default: existing?.mode ?? 'auto',
|
|
93
93
|
hint: 'auto=主循环自主判断时机调用 · manual=仅 /advisor ask 手动触发',
|
|
94
94
|
},
|
|
95
|
+
{
|
|
96
|
+
key: 'enforcement',
|
|
97
|
+
label: '补问方式',
|
|
98
|
+
type: 'select',
|
|
99
|
+
options: ['remind', 'followup'],
|
|
100
|
+
default: existing?.enforcement ?? 'remind',
|
|
101
|
+
hint: 'remind=只提醒 · followup=实质回答未复核时再发一次请求,让模型自己补问顾问(弱基座模型用)',
|
|
102
|
+
},
|
|
95
103
|
{
|
|
96
104
|
key: 'timeoutSeconds',
|
|
97
105
|
label: '最长等待(秒)',
|
|
@@ -99,12 +107,6 @@ export function AdvisorWizard({ existing, models, onDone, onCancel }) {
|
|
|
99
107
|
default: String(Math.round((existing?.timeoutMs ?? DEFAULT_ADVISOR_CONFIG.timeoutMs) / 1000)),
|
|
100
108
|
optional: true,
|
|
101
109
|
},
|
|
102
|
-
{
|
|
103
|
-
key: 'shareSensitive',
|
|
104
|
-
label: '是否允许把敏感内容一并发给顾问',
|
|
105
|
-
type: 'boolean',
|
|
106
|
-
default: existing?.shareSensitive ?? false,
|
|
107
|
-
},
|
|
108
110
|
], onSubmit: async (values) => {
|
|
109
111
|
// 只在这最后一步才真正落盘——ESC 在任何前置阶段取消都不留半成品模型。
|
|
110
112
|
// newModelDraft 在 add 成功后立即清空 + 把新 id 记入 chosenModelId:若紧接着
|
|
@@ -140,8 +142,8 @@ export function AdvisorWizard({ existing, models, onDone, onCancel }) {
|
|
|
140
142
|
advisor: {
|
|
141
143
|
enabled: values.enabled,
|
|
142
144
|
mode: values.mode === 'manual' ? 'manual' : 'auto',
|
|
145
|
+
enforcement: values.enforcement === 'followup' ? 'followup' : 'remind',
|
|
143
146
|
modelId,
|
|
144
|
-
shareSensitive: values.shareSensitive,
|
|
145
147
|
timeoutMs: normalizeLimited(parsePositiveInt(values.timeoutSeconds, DEFAULT_ADVISOR_CONFIG.timeoutMs / 1000) * 1000, CONFIG_LIMITS.advisorTimeoutMs, DEFAULT_ADVISOR_CONFIG.timeoutMs),
|
|
146
148
|
},
|
|
147
149
|
});
|
|
@@ -136,6 +136,14 @@ export function AdvisorWizard({ existing, models, onDone, onCancel }: Props): JS
|
|
|
136
136
|
default: existing?.mode ?? 'auto',
|
|
137
137
|
hint: 'auto=主循环自主判断时机调用 · manual=仅 /advisor ask 手动触发',
|
|
138
138
|
},
|
|
139
|
+
{
|
|
140
|
+
key: 'enforcement',
|
|
141
|
+
label: '补问方式',
|
|
142
|
+
type: 'select',
|
|
143
|
+
options: ['remind', 'followup'],
|
|
144
|
+
default: existing?.enforcement ?? 'remind',
|
|
145
|
+
hint: 'remind=只提醒 · followup=实质回答未复核时再发一次请求,让模型自己补问顾问(弱基座模型用)',
|
|
146
|
+
},
|
|
139
147
|
{
|
|
140
148
|
key: 'timeoutSeconds',
|
|
141
149
|
label: '最长等待(秒)',
|
|
@@ -143,12 +151,6 @@ export function AdvisorWizard({ existing, models, onDone, onCancel }: Props): JS
|
|
|
143
151
|
default: String(Math.round((existing?.timeoutMs ?? DEFAULT_ADVISOR_CONFIG.timeoutMs) / 1000)),
|
|
144
152
|
optional: true,
|
|
145
153
|
},
|
|
146
|
-
{
|
|
147
|
-
key: 'shareSensitive',
|
|
148
|
-
label: '是否允许把敏感内容一并发给顾问',
|
|
149
|
-
type: 'boolean',
|
|
150
|
-
default: existing?.shareSensitive ?? false,
|
|
151
|
-
},
|
|
152
154
|
]}
|
|
153
155
|
onSubmit={async (values) => {
|
|
154
156
|
// 只在这最后一步才真正落盘——ESC 在任何前置阶段取消都不留半成品模型。
|
|
@@ -184,8 +186,8 @@ export function AdvisorWizard({ existing, models, onDone, onCancel }: Props): JS
|
|
|
184
186
|
advisor: {
|
|
185
187
|
enabled: values.enabled as boolean,
|
|
186
188
|
mode: values.mode === 'manual' ? 'manual' : 'auto',
|
|
189
|
+
enforcement: values.enforcement === 'followup' ? 'followup' : 'remind',
|
|
187
190
|
modelId,
|
|
188
|
-
shareSensitive: values.shareSensitive as boolean,
|
|
189
191
|
timeoutMs: normalizeLimited(
|
|
190
192
|
parsePositiveInt(values.timeoutSeconds, DEFAULT_ADVISOR_CONFIG.timeoutMs / 1000) * 1000,
|
|
191
193
|
CONFIG_LIMITS.advisorTimeoutMs,
|
|
@@ -45,6 +45,14 @@ export function ContextAdvisorWizard({ compactRatio, advisor, models, onDone, on
|
|
|
45
45
|
options: ['auto', 'manual'],
|
|
46
46
|
default: advisor?.mode ?? 'auto',
|
|
47
47
|
},
|
|
48
|
+
{
|
|
49
|
+
key: 'enforcement',
|
|
50
|
+
label: '补问方式',
|
|
51
|
+
type: 'select',
|
|
52
|
+
options: ['remind', 'followup'],
|
|
53
|
+
default: advisor?.enforcement ?? 'remind',
|
|
54
|
+
hint: 'remind=只提醒 · followup=实质回答未复核时再发一次请求,让模型自己补问顾问(弱基座模型用)',
|
|
55
|
+
},
|
|
48
56
|
{
|
|
49
57
|
key: 'inputTokenBudget',
|
|
50
58
|
label: '顾问输入 Token 预算',
|
|
@@ -57,12 +65,6 @@ export function ContextAdvisorWizard({ compactRatio, advisor, models, onDone, on
|
|
|
57
65
|
type: 'text',
|
|
58
66
|
default: String(Math.round((advisor?.timeoutMs ?? DEFAULT_ADVISOR_CONFIG.timeoutMs) / 1000)),
|
|
59
67
|
},
|
|
60
|
-
{
|
|
61
|
-
key: 'shareSensitive',
|
|
62
|
-
label: '允许向顾问发送敏感内容',
|
|
63
|
-
type: 'boolean',
|
|
64
|
-
default: advisor?.shareSensitive ?? false,
|
|
65
|
-
},
|
|
66
68
|
], onSubmit: async (values) => {
|
|
67
69
|
const ratio = normalizeLimited(numberValue(values.compactPercent, 85) / 100, CONFIG_LIMITS.compactRatio, 0.85);
|
|
68
70
|
const modelIndex = options.indexOf(String(values.advisorModel));
|
|
@@ -73,10 +75,10 @@ export function ContextAdvisorWizard({ compactRatio, advisor, models, onDone, on
|
|
|
73
75
|
? {
|
|
74
76
|
enabled: values.enabled === true,
|
|
75
77
|
mode: values.mode === 'manual' ? 'manual' : 'auto',
|
|
78
|
+
enforcement: values.enforcement === 'followup' ? 'followup' : 'remind',
|
|
76
79
|
modelId,
|
|
77
80
|
inputTokenBudget: normalizeLimited(numberValue(values.inputTokenBudget, DEFAULT_ADVISOR_CONFIG.inputTokenBudget), CONFIG_LIMITS.advisorInputTokenBudget, DEFAULT_ADVISOR_CONFIG.inputTokenBudget),
|
|
78
81
|
timeoutMs: normalizeLimited(numberValue(values.timeoutSeconds, DEFAULT_ADVISOR_CONFIG.timeoutMs / 1000) * 1000, CONFIG_LIMITS.advisorTimeoutMs, DEFAULT_ADVISOR_CONFIG.timeoutMs),
|
|
79
|
-
shareSensitive: values.shareSensitive === true,
|
|
80
82
|
}
|
|
81
83
|
: { clear: true },
|
|
82
84
|
});
|
|
@@ -69,6 +69,14 @@ export function ContextAdvisorWizard({
|
|
|
69
69
|
options: ['auto', 'manual'],
|
|
70
70
|
default: advisor?.mode ?? 'auto',
|
|
71
71
|
},
|
|
72
|
+
{
|
|
73
|
+
key: 'enforcement',
|
|
74
|
+
label: '补问方式',
|
|
75
|
+
type: 'select',
|
|
76
|
+
options: ['remind', 'followup'],
|
|
77
|
+
default: advisor?.enforcement ?? 'remind',
|
|
78
|
+
hint: 'remind=只提醒 · followup=实质回答未复核时再发一次请求,让模型自己补问顾问(弱基座模型用)',
|
|
79
|
+
},
|
|
72
80
|
{
|
|
73
81
|
key: 'inputTokenBudget',
|
|
74
82
|
label: '顾问输入 Token 预算',
|
|
@@ -81,12 +89,6 @@ export function ContextAdvisorWizard({
|
|
|
81
89
|
type: 'text',
|
|
82
90
|
default: String(Math.round((advisor?.timeoutMs ?? DEFAULT_ADVISOR_CONFIG.timeoutMs) / 1000)),
|
|
83
91
|
},
|
|
84
|
-
{
|
|
85
|
-
key: 'shareSensitive',
|
|
86
|
-
label: '允许向顾问发送敏感内容',
|
|
87
|
-
type: 'boolean',
|
|
88
|
-
default: advisor?.shareSensitive ?? false,
|
|
89
|
-
},
|
|
90
92
|
]}
|
|
91
93
|
onSubmit={async (values) => {
|
|
92
94
|
const ratio = normalizeLimited(
|
|
@@ -102,6 +104,7 @@ export function ContextAdvisorWizard({
|
|
|
102
104
|
? {
|
|
103
105
|
enabled: values.enabled === true,
|
|
104
106
|
mode: values.mode === 'manual' ? 'manual' : 'auto',
|
|
107
|
+
enforcement: values.enforcement === 'followup' ? 'followup' : 'remind',
|
|
105
108
|
modelId,
|
|
106
109
|
inputTokenBudget: normalizeLimited(
|
|
107
110
|
numberValue(values.inputTokenBudget, DEFAULT_ADVISOR_CONFIG.inputTokenBudget),
|
|
@@ -113,7 +116,6 @@ export function ContextAdvisorWizard({
|
|
|
113
116
|
CONFIG_LIMITS.advisorTimeoutMs,
|
|
114
117
|
DEFAULT_ADVISOR_CONFIG.timeoutMs,
|
|
115
118
|
),
|
|
116
|
-
shareSensitive: values.shareSensitive === true,
|
|
117
119
|
}
|
|
118
120
|
: { clear: true },
|
|
119
121
|
});
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* baseURL 预设表。
|
|
8
8
|
* ============================================================
|
|
9
9
|
*/
|
|
10
|
+
import { REASONING_EFFORTS, normalizeReasoningEffort, } from '../../config/reasoningEffort.js';
|
|
10
11
|
// 兜底值:custom 或表外 model 都退到这里。
|
|
11
12
|
// 与 src/config.ts 的同名常量含义对齐("既没 env、saved 也没填 contextWindow" 的最终兜底)。
|
|
12
13
|
export const FALLBACK_CONTEXT_WINDOW = 128_000;
|
|
@@ -57,11 +58,25 @@ export const PRESETS = [
|
|
|
57
58
|
contextWindow: 128_000,
|
|
58
59
|
},
|
|
59
60
|
{
|
|
61
|
+
// OpenAI 当前主推的 Responses API(POST /v1/responses)。模型与推理强度都在请求体里,
|
|
62
|
+
// 不换端点。模型 ID 以官方模型页为准——这里只是常用项,向导里可直接改。
|
|
63
|
+
name: 'openai-responses',
|
|
64
|
+
label: 'OpenAI(Responses API,推荐)',
|
|
65
|
+
baseURL: 'https://api.openai.com/v1/responses',
|
|
66
|
+
models: ['gpt-6.1-terra', 'gpt-5.6-luna'],
|
|
67
|
+
contextWindow: 128_000,
|
|
68
|
+
apiFormat: 'openai-responses',
|
|
69
|
+
supportsReasoningEffort: true,
|
|
70
|
+
reasoningEffort: 'medium',
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
// 仍然可用的 Chat Completions;OpenAI 官方端点认顶层 reasoning_effort。
|
|
60
74
|
name: 'openai',
|
|
61
|
-
label: 'OpenAI',
|
|
75
|
+
label: 'OpenAI(Chat Completions)',
|
|
62
76
|
baseURL: 'https://api.openai.com/v1/chat/completions',
|
|
63
77
|
models: ['gpt-4o', 'gpt-4o-mini'],
|
|
64
78
|
contextWindow: 128_000,
|
|
79
|
+
supportsReasoningEffort: true,
|
|
65
80
|
},
|
|
66
81
|
{
|
|
67
82
|
name: 'openrouter',
|
|
@@ -97,6 +112,17 @@ export const PRESETS = [
|
|
|
97
112
|
contextWindow: FALLBACK_CONTEXT_WINDOW,
|
|
98
113
|
},
|
|
99
114
|
];
|
|
115
|
+
/** 向导里「不设置」的显示文案:不发送该参数,沿用服务端对该模型的默认强度。 */
|
|
116
|
+
export const REASONING_EFFORT_UNSET = '不设置(沿用模型默认)';
|
|
117
|
+
export const REASONING_EFFORT_CHOICES = [REASONING_EFFORT_UNSET, ...REASONING_EFFORTS];
|
|
118
|
+
export function reasoningEffortFromChoice(choice) {
|
|
119
|
+
return normalizeReasoningEffort(choice);
|
|
120
|
+
}
|
|
121
|
+
export function reasoningEffortToChoice(effort) {
|
|
122
|
+
return effort ?? REASONING_EFFORT_UNSET;
|
|
123
|
+
}
|
|
124
|
+
/** 选「自定义」时可手选的协议;已有模型沿用它自己的协议。 */
|
|
125
|
+
export const API_FORMAT_CHOICES = ['openai', 'openai-responses', 'anthropic'];
|
|
100
126
|
export function resolveContextWindow(preset, model) {
|
|
101
127
|
return (preset.modelContextWindows?.[model] ??
|
|
102
128
|
preset.contextWindow ??
|
|
@@ -8,6 +8,15 @@
|
|
|
8
8
|
* ============================================================
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
+
// 只引纯逻辑模块:Desktop 浏览器端经 `minimal-agent/provider-presets` 引用本文件,
|
|
12
|
+
// 不能把 configFile.ts(node:fs)拖进前端包。ApiFormat 仅类型引用,编译后抹掉。
|
|
13
|
+
import type { ApiFormat } from '../../config/configFile.js';
|
|
14
|
+
import {
|
|
15
|
+
REASONING_EFFORTS,
|
|
16
|
+
type ReasoningEffort,
|
|
17
|
+
normalizeReasoningEffort,
|
|
18
|
+
} from '../../config/reasoningEffort.js';
|
|
19
|
+
|
|
11
20
|
// 兜底值:custom 或表外 model 都退到这里。
|
|
12
21
|
// 与 src/config.ts 的同名常量含义对齐("既没 env、saved 也没填 contextWindow" 的最终兜底)。
|
|
13
22
|
export const FALLBACK_CONTEXT_WINDOW = 128_000;
|
|
@@ -19,7 +28,11 @@ export interface ProviderPreset {
|
|
|
19
28
|
models: string[];
|
|
20
29
|
/** 该 provider 的默认 context window(token 数) */
|
|
21
30
|
contextWindow: number;
|
|
22
|
-
apiFormat?:
|
|
31
|
+
apiFormat?: ApiFormat;
|
|
32
|
+
/** 该服务商的模型有「推理强度」档位:向导的快速配置也会问。 */
|
|
33
|
+
supportsReasoningEffort?: boolean;
|
|
34
|
+
/** 向导里推理强度的预选值。 */
|
|
35
|
+
reasoningEffort?: ReasoningEffort;
|
|
23
36
|
promptCacheMode?: 'auto' | 'session-key' | 'disabled';
|
|
24
37
|
/** Default reasoning switch for providers that expose an OpenAI-compatible extension. */
|
|
25
38
|
reasoning?: boolean;
|
|
@@ -74,11 +87,25 @@ export const PRESETS: ProviderPreset[] = [
|
|
|
74
87
|
contextWindow: 128_000,
|
|
75
88
|
},
|
|
76
89
|
{
|
|
90
|
+
// OpenAI 当前主推的 Responses API(POST /v1/responses)。模型与推理强度都在请求体里,
|
|
91
|
+
// 不换端点。模型 ID 以官方模型页为准——这里只是常用项,向导里可直接改。
|
|
92
|
+
name: 'openai-responses',
|
|
93
|
+
label: 'OpenAI(Responses API,推荐)',
|
|
94
|
+
baseURL: 'https://api.openai.com/v1/responses',
|
|
95
|
+
models: ['gpt-6.1-terra', 'gpt-5.6-luna'],
|
|
96
|
+
contextWindow: 128_000,
|
|
97
|
+
apiFormat: 'openai-responses',
|
|
98
|
+
supportsReasoningEffort: true,
|
|
99
|
+
reasoningEffort: 'medium',
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
// 仍然可用的 Chat Completions;OpenAI 官方端点认顶层 reasoning_effort。
|
|
77
103
|
name: 'openai',
|
|
78
|
-
label: 'OpenAI',
|
|
104
|
+
label: 'OpenAI(Chat Completions)',
|
|
79
105
|
baseURL: 'https://api.openai.com/v1/chat/completions',
|
|
80
106
|
models: ['gpt-4o', 'gpt-4o-mini'],
|
|
81
107
|
contextWindow: 128_000,
|
|
108
|
+
supportsReasoningEffort: true,
|
|
82
109
|
},
|
|
83
110
|
{
|
|
84
111
|
name: 'openrouter',
|
|
@@ -115,6 +142,21 @@ export const PRESETS: ProviderPreset[] = [
|
|
|
115
142
|
},
|
|
116
143
|
];
|
|
117
144
|
|
|
145
|
+
/** 向导里「不设置」的显示文案:不发送该参数,沿用服务端对该模型的默认强度。 */
|
|
146
|
+
export const REASONING_EFFORT_UNSET = '不设置(沿用模型默认)';
|
|
147
|
+
export const REASONING_EFFORT_CHOICES: string[] = [REASONING_EFFORT_UNSET, ...REASONING_EFFORTS];
|
|
148
|
+
|
|
149
|
+
export function reasoningEffortFromChoice(choice: unknown): ReasoningEffort | undefined {
|
|
150
|
+
return normalizeReasoningEffort(choice);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export function reasoningEffortToChoice(effort: ReasoningEffort | undefined): string {
|
|
154
|
+
return effort ?? REASONING_EFFORT_UNSET;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/** 选「自定义」时可手选的协议;已有模型沿用它自己的协议。 */
|
|
158
|
+
export const API_FORMAT_CHOICES: ApiFormat[] = ['openai', 'openai-responses', 'anthropic'];
|
|
159
|
+
|
|
118
160
|
export function resolveContextWindow(preset: ProviderPreset, model: string): number {
|
|
119
161
|
return (
|
|
120
162
|
preset.modelContextWindows?.[model] ??
|
|
@@ -6,7 +6,7 @@ import { defaultMaxTokens } from '../../config/configFile.js';
|
|
|
6
6
|
import { configService } from '../../config/configService.js';
|
|
7
7
|
import { CONFIG_LIMITS, normalizeLimited } from '../../config/numericLimits.js';
|
|
8
8
|
import { FieldForm } from './fieldForm.js';
|
|
9
|
-
import { PRESETS, findPresetIndex, resolveContextWindow, } from './providerPresets.js';
|
|
9
|
+
import { API_FORMAT_CHOICES, PRESETS, REASONING_EFFORT_CHOICES, findPresetIndex, reasoningEffortFromChoice, reasoningEffortToChoice, resolveContextWindow, } from './providerPresets.js';
|
|
10
10
|
const numberValue = (value, fallback) => {
|
|
11
11
|
const parsed = Number(String(value ?? '').trim());
|
|
12
12
|
return Number.isFinite(parsed) ? parsed : fallback;
|
|
@@ -52,6 +52,18 @@ export function ProviderWizard({ existing, setAsBase = true, quick = false, onDo
|
|
|
52
52
|
: '添加模型' }), _jsx(Text, { color: "gray", children: "\u2191\u2193 \u9009\u62E9\u670D\u52A1\u5546 \u00B7 Enter \u7EE7\u7EED \u00B7 ESC \u8FD4\u56DE" }), _jsx(Box, { flexDirection: "column", marginTop: 1, children: PRESETS.map((item, index) => (_jsxs(Text, { color: index === presetIndex ? 'cyan' : undefined, children: [index === presetIndex ? '> ' : ' ', item.label] }, item.name))) })] }));
|
|
53
53
|
if (phase === 'quick-choice')
|
|
54
54
|
return (_jsxs(Box, { flexDirection: "column", paddingX: 1, children: [_jsx(Text, { color: "cyan", bold: true, children: "\u9009\u62E9\u914D\u7F6E\u6DF1\u5EA6" }), _jsx(Text, { color: "gray", children: "\u5FEB\u901F\u914D\u7F6E\u4F7F\u7528\u670D\u52A1\u5546\u63A8\u8350\u7684\u7A97\u53E3\u3001\u8F93\u51FA\u4E0A\u9650\u548C\u7F13\u5B58\u7B56\u7565\u3002" }), _jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsxs(Text, { color: !advanced ? 'cyan' : undefined, children: [!advanced ? '> ' : ' ', "\u5FEB\u901F\u914D\u7F6E\uFF08\u63A8\u8350\uFF09"] }), _jsxs(Text, { color: advanced ? 'cyan' : undefined, children: [advanced ? '> ' : ' ', "\u9AD8\u7EA7\u914D\u7F6E"] })] })] }));
|
|
55
|
+
// 协议:选了具体服务商就跟服务商走(编辑时换服务商可以顺带换协议);
|
|
56
|
+
// 「自定义」没有预设,沿用已有模型自己的协议,新建时在完整设置里让用户选。
|
|
57
|
+
const presetFormat = preset.name === 'custom' ? existing?.apiFormat : (preset.apiFormat ?? 'openai');
|
|
58
|
+
const askFormat = preset.name === 'custom' && (!quick || advanced);
|
|
59
|
+
const knownFormat = presetFormat ?? 'openai';
|
|
60
|
+
// 推理强度是 OpenAI 系模型最常调的一项:快速配置也要问,不藏进高级里。
|
|
61
|
+
const showEffort = knownFormat !== 'anthropic' &&
|
|
62
|
+
(preset.supportsReasoningEffort === true ||
|
|
63
|
+
knownFormat === 'openai-responses' ||
|
|
64
|
+
!!existing?.reasoningEffort ||
|
|
65
|
+
!quick ||
|
|
66
|
+
advanced);
|
|
55
67
|
const defaultModel = existing?.model ?? preset.models[0] ?? '';
|
|
56
68
|
const defaultContext = existing?.contextWindow ?? resolveContextWindow(preset, defaultModel);
|
|
57
69
|
const fields = [
|
|
@@ -81,6 +93,24 @@ export function ProviderWizard({ existing, setAsBase = true, quick = false, onDo
|
|
|
81
93
|
: undefined,
|
|
82
94
|
},
|
|
83
95
|
];
|
|
96
|
+
if (askFormat)
|
|
97
|
+
fields.push({
|
|
98
|
+
key: 'apiFormat',
|
|
99
|
+
label: '接口协议',
|
|
100
|
+
type: 'select',
|
|
101
|
+
options: API_FORMAT_CHOICES,
|
|
102
|
+
default: existing?.apiFormat ?? 'openai',
|
|
103
|
+
hint: 'openai = Chat Completions(多数国内服务商);openai-responses = OpenAI Responses API;anthropic = Messages API(未经真实端点验证)',
|
|
104
|
+
});
|
|
105
|
+
if (showEffort)
|
|
106
|
+
fields.push({
|
|
107
|
+
key: 'reasoningEffort',
|
|
108
|
+
label: '推理强度',
|
|
109
|
+
type: 'select',
|
|
110
|
+
options: REASONING_EFFORT_CHOICES,
|
|
111
|
+
default: reasoningEffortToChoice(existing ? existing.reasoningEffort : preset.reasoningEffort),
|
|
112
|
+
hint: '越高越慢越贵(推理 Token 照常计费)。各模型支持的档位不同;服务端不接受时会自动去掉该参数重发并告警。',
|
|
113
|
+
});
|
|
84
114
|
if (!quick || advanced)
|
|
85
115
|
fields.push({
|
|
86
116
|
key: 'displayName',
|
|
@@ -105,13 +135,17 @@ export function ProviderWizard({ existing, setAsBase = true, quick = false, onDo
|
|
|
105
135
|
type: 'select',
|
|
106
136
|
options: ['auto', 'session-key', 'disabled'],
|
|
107
137
|
default: existing?.promptCache?.mode ?? preset.promptCacheMode ?? 'auto',
|
|
108
|
-
},
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
138
|
+
}, ...(knownFormat === 'openai-responses'
|
|
139
|
+
? []
|
|
140
|
+
: [
|
|
141
|
+
{
|
|
142
|
+
key: 'reasoning',
|
|
143
|
+
label: '启用 Reasoning(Provider 支持时)',
|
|
144
|
+
type: 'boolean',
|
|
145
|
+
default: existing?.reasoning ?? preset.reasoning ?? false,
|
|
146
|
+
hint: '仅显式启用时发送 reasoning.enabled=true;普通 OpenAI 端点保持默认行为',
|
|
147
|
+
},
|
|
148
|
+
]));
|
|
115
149
|
return (_jsx(FieldForm, { title: quick
|
|
116
150
|
? '快速模型配置'
|
|
117
151
|
: existing
|
|
@@ -129,7 +163,12 @@ export function ProviderWizard({ existing, setAsBase = true, quick = false, onDo
|
|
|
129
163
|
const maxTokens = rawMax
|
|
130
164
|
? normalizeLimited(numberValue(rawMax, defaultMaxTokens(contextWindow)), CONFIG_LIMITS.modelMaxTokens, defaultMaxTokens(contextWindow))
|
|
131
165
|
: undefined;
|
|
132
|
-
const apiFormat =
|
|
166
|
+
const apiFormat = askFormat
|
|
167
|
+
? (API_FORMAT_CHOICES.find((item) => item === values.apiFormat) ?? knownFormat)
|
|
168
|
+
: knownFormat;
|
|
169
|
+
const reasoningEffort = showEffort
|
|
170
|
+
? reasoningEffortFromChoice(values.reasoningEffort)
|
|
171
|
+
: existing?.reasoningEffort;
|
|
133
172
|
const draft = {
|
|
134
173
|
apiFormat,
|
|
135
174
|
displayName: quick && !advanced
|
|
@@ -141,6 +180,7 @@ export function ProviderWizard({ existing, setAsBase = true, quick = false, onDo
|
|
|
141
180
|
contextWindow,
|
|
142
181
|
...(maxTokens ? { maxTokens } : {}),
|
|
143
182
|
supportsVision: existing?.supportsVision !== false,
|
|
183
|
+
...(reasoningEffort ? { reasoningEffort } : {}),
|
|
144
184
|
reasoning: quick && !advanced
|
|
145
185
|
? (preset.reasoning ?? false)
|
|
146
186
|
: values.reasoning === true,
|
|
@@ -155,7 +195,8 @@ export function ProviderWizard({ existing, setAsBase = true, quick = false, onDo
|
|
|
155
195
|
throw new Error(diagnostic.message);
|
|
156
196
|
if (existing) {
|
|
157
197
|
await configService.savePatch({
|
|
158
|
-
|
|
198
|
+
// null = 清除之前设的强度(选了「不设置」);不带这个字段则保留旧值。
|
|
199
|
+
models: [{ op: 'update', id: existing.id, patch: { ...draft, reasoningEffort: reasoningEffort ?? null } }],
|
|
159
200
|
...(setAsBase ? { baseModelId: existing.id } : {}),
|
|
160
201
|
});
|
|
161
202
|
}
|
|
@@ -8,8 +8,12 @@ import { configService } from '../../config/configService.js';
|
|
|
8
8
|
import { CONFIG_LIMITS, normalizeLimited } from '../../config/numericLimits.js';
|
|
9
9
|
import { type FieldDef, FieldForm } from './fieldForm.js';
|
|
10
10
|
import {
|
|
11
|
+
API_FORMAT_CHOICES,
|
|
11
12
|
PRESETS,
|
|
13
|
+
REASONING_EFFORT_CHOICES,
|
|
12
14
|
findPresetIndex,
|
|
15
|
+
reasoningEffortFromChoice,
|
|
16
|
+
reasoningEffortToChoice,
|
|
13
17
|
resolveContextWindow,
|
|
14
18
|
} from './providerPresets.js';
|
|
15
19
|
|
|
@@ -26,6 +30,7 @@ export type ExistingProvider = Pick<
|
|
|
26
30
|
| 'supportsVision'
|
|
27
31
|
| 'promptCache'
|
|
28
32
|
| 'reasoning'
|
|
33
|
+
| 'reasoningEffort'
|
|
29
34
|
>;
|
|
30
35
|
|
|
31
36
|
interface Props {
|
|
@@ -124,6 +129,20 @@ export function ProviderWizard({
|
|
|
124
129
|
</Box>
|
|
125
130
|
);
|
|
126
131
|
|
|
132
|
+
// 协议:选了具体服务商就跟服务商走(编辑时换服务商可以顺带换协议);
|
|
133
|
+
// 「自定义」没有预设,沿用已有模型自己的协议,新建时在完整设置里让用户选。
|
|
134
|
+
const presetFormat: ApiFormat | undefined =
|
|
135
|
+
preset.name === 'custom' ? existing?.apiFormat : (preset.apiFormat ?? 'openai');
|
|
136
|
+
const askFormat = preset.name === 'custom' && (!quick || advanced);
|
|
137
|
+
const knownFormat: ApiFormat = presetFormat ?? 'openai';
|
|
138
|
+
// 推理强度是 OpenAI 系模型最常调的一项:快速配置也要问,不藏进高级里。
|
|
139
|
+
const showEffort =
|
|
140
|
+
knownFormat !== 'anthropic' &&
|
|
141
|
+
(preset.supportsReasoningEffort === true ||
|
|
142
|
+
knownFormat === 'openai-responses' ||
|
|
143
|
+
!!existing?.reasoningEffort ||
|
|
144
|
+
!quick ||
|
|
145
|
+
advanced);
|
|
127
146
|
const defaultModel = existing?.model ?? preset.models[0] ?? '';
|
|
128
147
|
const defaultContext =
|
|
129
148
|
existing?.contextWindow ?? resolveContextWindow(preset, defaultModel);
|
|
@@ -154,6 +173,26 @@ export function ProviderWizard({
|
|
|
154
173
|
: undefined,
|
|
155
174
|
},
|
|
156
175
|
];
|
|
176
|
+
if (askFormat)
|
|
177
|
+
fields.push({
|
|
178
|
+
key: 'apiFormat',
|
|
179
|
+
label: '接口协议',
|
|
180
|
+
type: 'select',
|
|
181
|
+
options: API_FORMAT_CHOICES,
|
|
182
|
+
default: existing?.apiFormat ?? 'openai',
|
|
183
|
+
hint: 'openai = Chat Completions(多数国内服务商);openai-responses = OpenAI Responses API;anthropic = Messages API(未经真实端点验证)',
|
|
184
|
+
});
|
|
185
|
+
if (showEffort)
|
|
186
|
+
fields.push({
|
|
187
|
+
key: 'reasoningEffort',
|
|
188
|
+
label: '推理强度',
|
|
189
|
+
type: 'select',
|
|
190
|
+
options: REASONING_EFFORT_CHOICES,
|
|
191
|
+
default: reasoningEffortToChoice(
|
|
192
|
+
existing ? existing.reasoningEffort : preset.reasoningEffort,
|
|
193
|
+
),
|
|
194
|
+
hint: '越高越慢越贵(推理 Token 照常计费)。各模型支持的档位不同;服务端不接受时会自动去掉该参数重发并告警。',
|
|
195
|
+
});
|
|
157
196
|
if (!quick || advanced)
|
|
158
197
|
fields.push(
|
|
159
198
|
{
|
|
@@ -184,13 +223,17 @@ export function ProviderWizard({
|
|
|
184
223
|
default:
|
|
185
224
|
existing?.promptCache?.mode ?? preset.promptCacheMode ?? 'auto',
|
|
186
225
|
},
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
226
|
+
...(knownFormat === 'openai-responses'
|
|
227
|
+
? []
|
|
228
|
+
: [
|
|
229
|
+
{
|
|
230
|
+
key: 'reasoning',
|
|
231
|
+
label: '启用 Reasoning(Provider 支持时)',
|
|
232
|
+
type: 'boolean' as const,
|
|
233
|
+
default: existing?.reasoning ?? preset.reasoning ?? false,
|
|
234
|
+
hint: '仅显式启用时发送 reasoning.enabled=true;普通 OpenAI 端点保持默认行为',
|
|
235
|
+
},
|
|
236
|
+
]),
|
|
194
237
|
);
|
|
195
238
|
|
|
196
239
|
return (
|
|
@@ -225,7 +268,12 @@ export function ProviderWizard({
|
|
|
225
268
|
defaultMaxTokens(contextWindow),
|
|
226
269
|
)
|
|
227
270
|
: undefined;
|
|
228
|
-
const apiFormat: ApiFormat =
|
|
271
|
+
const apiFormat: ApiFormat = askFormat
|
|
272
|
+
? (API_FORMAT_CHOICES.find((item) => item === values.apiFormat) ?? knownFormat)
|
|
273
|
+
: knownFormat;
|
|
274
|
+
const reasoningEffort = showEffort
|
|
275
|
+
? reasoningEffortFromChoice(values.reasoningEffort)
|
|
276
|
+
: existing?.reasoningEffort;
|
|
229
277
|
const draft = {
|
|
230
278
|
apiFormat,
|
|
231
279
|
displayName:
|
|
@@ -238,6 +286,7 @@ export function ProviderWizard({
|
|
|
238
286
|
contextWindow,
|
|
239
287
|
...(maxTokens ? { maxTokens } : {}),
|
|
240
288
|
supportsVision: existing?.supportsVision !== false,
|
|
289
|
+
...(reasoningEffort ? { reasoningEffort } : {}),
|
|
241
290
|
reasoning:
|
|
242
291
|
quick && !advanced
|
|
243
292
|
? (preset.reasoning ?? false)
|
|
@@ -253,7 +302,8 @@ export function ProviderWizard({
|
|
|
253
302
|
if (!diagnostic.ok) throw new Error(diagnostic.message);
|
|
254
303
|
if (existing) {
|
|
255
304
|
await configService.savePatch({
|
|
256
|
-
|
|
305
|
+
// null = 清除之前设的强度(选了「不设置」);不带这个字段则保留旧值。
|
|
306
|
+
models: [{ op: 'update', id: existing.id, patch: { ...draft, reasoningEffort: reasoningEffort ?? null } }],
|
|
257
307
|
...(setAsBase ? { baseModelId: existing.id } : {}),
|
|
258
308
|
});
|
|
259
309
|
} else {
|
|
@@ -61,9 +61,9 @@ export const DEFAULT_ADVISOR_CONFIG = {
|
|
|
61
61
|
// 顾问会增加额外模型调用和延迟;必须由用户显式开启。
|
|
62
62
|
enabled: false,
|
|
63
63
|
mode: 'auto',
|
|
64
|
+
enforcement: 'remind',
|
|
64
65
|
modelId: null,
|
|
65
66
|
contextPolicy: 'full-relevant',
|
|
66
|
-
shareSensitive: false,
|
|
67
67
|
inputTokenBudget: 2_000_000,
|
|
68
68
|
timeoutMs: 120_000,
|
|
69
69
|
};
|
|
@@ -72,9 +72,9 @@ export const DEFAULT_ADVISOR_CONFIG: AdvisorConfig = {
|
|
|
72
72
|
// 顾问会增加额外模型调用和延迟;必须由用户显式开启。
|
|
73
73
|
enabled: false,
|
|
74
74
|
mode: 'auto',
|
|
75
|
+
enforcement: 'remind',
|
|
75
76
|
modelId: null,
|
|
76
77
|
contextPolicy: 'full-relevant',
|
|
77
|
-
shareSensitive: false,
|
|
78
78
|
inputTokenBudget: 2_000_000,
|
|
79
79
|
timeoutMs: 120_000,
|
|
80
80
|
};
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { resolveSshHost } from '../context/sshHosts.js';
|
|
2
|
-
import { defaultSshConnect } from '../tools/ssh/sshClient.js';
|
|
3
1
|
import { configService } from './configService.js';
|
|
4
2
|
function providerFromModel(model) {
|
|
5
3
|
return {
|
|
@@ -13,6 +11,7 @@ function providerFromModel(model) {
|
|
|
13
11
|
supportsVision: model.supportsVision !== false,
|
|
14
12
|
promptCache: model.promptCache ?? { mode: 'auto' },
|
|
15
13
|
...(model.reasoning === true ? { reasoning: true } : {}),
|
|
14
|
+
...(model.reasoningEffort ? { reasoningEffort: model.reasoningEffort } : {}),
|
|
16
15
|
};
|
|
17
16
|
}
|
|
18
17
|
export async function testModelConnection(model, timeoutMs = 45_000) {
|
|
@@ -119,22 +118,3 @@ export async function testToolConnection(tool, service = configService) {
|
|
|
119
118
|
clearTimeout(timer);
|
|
120
119
|
}
|
|
121
120
|
}
|
|
122
|
-
/** 测试当前工作区某个 SSH 主机是否能建立连接(只连不执行任何命令,连上即断开)。 */
|
|
123
|
-
export async function testSshHostConnection(workspaceId, alias) {
|
|
124
|
-
const resolved = await resolveSshHost(workspaceId, alias);
|
|
125
|
-
if (!resolved.ok)
|
|
126
|
-
return { ok: false, code: 'missing-config', message: resolved.error };
|
|
127
|
-
try {
|
|
128
|
-
const connection = await defaultSshConnect(resolved.host, 10_000);
|
|
129
|
-
connection.end();
|
|
130
|
-
return { ok: true, code: 'ok', message: `已成功连接 ${resolved.host.username}@${resolved.host.host}:${resolved.host.port}` };
|
|
131
|
-
}
|
|
132
|
-
catch (error) {
|
|
133
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
134
|
-
return {
|
|
135
|
-
ok: false,
|
|
136
|
-
code: /timeout|ETIMEDOUT/i.test(message) ? 'timeout' : 'network',
|
|
137
|
-
message: `连接失败:${message}`,
|
|
138
|
-
};
|
|
139
|
-
}
|
|
140
|
-
}
|
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
import type { LocalProvider } from '../types.js';
|
|
2
|
-
import { resolveSshHost } from '../context/sshHosts.js';
|
|
3
|
-
import { defaultSshConnect } from '../tools/ssh/sshClient.js';
|
|
4
2
|
import type { ModelConfig } from './configFile.js';
|
|
5
3
|
import { type ConfigService, configService } from './configService.js';
|
|
6
4
|
|
|
@@ -29,6 +27,7 @@ function providerFromModel(
|
|
|
29
27
|
| 'supportsVision'
|
|
30
28
|
| 'promptCache'
|
|
31
29
|
| 'reasoning'
|
|
30
|
+
| 'reasoningEffort'
|
|
32
31
|
>,
|
|
33
32
|
): LocalProvider {
|
|
34
33
|
return {
|
|
@@ -42,6 +41,7 @@ function providerFromModel(
|
|
|
42
41
|
supportsVision: model.supportsVision !== false,
|
|
43
42
|
promptCache: model.promptCache ?? { mode: 'auto' },
|
|
44
43
|
...(model.reasoning === true ? { reasoning: true } : {}),
|
|
44
|
+
...(model.reasoningEffort ? { reasoningEffort: model.reasoningEffort } : {}),
|
|
45
45
|
};
|
|
46
46
|
}
|
|
47
47
|
|
|
@@ -58,6 +58,7 @@ export async function testModelConnection(
|
|
|
58
58
|
| 'supportsVision'
|
|
59
59
|
| 'promptCache'
|
|
60
60
|
| 'reasoning'
|
|
61
|
+
| 'reasoningEffort'
|
|
61
62
|
>,
|
|
62
63
|
timeoutMs = 45_000,
|
|
63
64
|
): Promise<ConfigDiagnosticResult> {
|
|
@@ -170,24 +171,3 @@ export async function testToolConnection(
|
|
|
170
171
|
clearTimeout(timer);
|
|
171
172
|
}
|
|
172
173
|
}
|
|
173
|
-
|
|
174
|
-
/** 测试当前工作区某个 SSH 主机是否能建立连接(只连不执行任何命令,连上即断开)。 */
|
|
175
|
-
export async function testSshHostConnection(
|
|
176
|
-
workspaceId: string,
|
|
177
|
-
alias: string,
|
|
178
|
-
): Promise<ConfigDiagnosticResult> {
|
|
179
|
-
const resolved = await resolveSshHost(workspaceId, alias);
|
|
180
|
-
if (!resolved.ok) return { ok: false, code: 'missing-config', message: resolved.error };
|
|
181
|
-
try {
|
|
182
|
-
const connection = await defaultSshConnect(resolved.host, 10_000);
|
|
183
|
-
connection.end();
|
|
184
|
-
return { ok: true, code: 'ok', message: `已成功连接 ${resolved.host.username}@${resolved.host.host}:${resolved.host.port}` };
|
|
185
|
-
} catch (error) {
|
|
186
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
187
|
-
return {
|
|
188
|
-
ok: false,
|
|
189
|
-
code: /timeout|ETIMEDOUT/i.test(message) ? 'timeout' : 'network',
|
|
190
|
-
message: `连接失败:${message}`,
|
|
191
|
-
};
|
|
192
|
-
}
|
|
193
|
-
}
|