bingocode 1.1.200-beta.19 → 1.1.200-beta.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/package.json
CHANGED
|
@@ -1,229 +1,229 @@
|
|
|
1
|
-
version: 2
|
|
2
|
-
|
|
3
|
-
# Provider Preset Configuration
|
|
4
|
-
# fields array declares fields to be filled when adding
|
|
5
|
-
# key: 'name' | 'apiKey' | 'baseUrl' mapped directly to top-level fields, others saved in extra.<key>
|
|
6
|
-
# secret: true uses mask display in frontend
|
|
7
|
-
#
|
|
8
|
-
# modelsUrl: model list path relative to baseUrl, empty string means dynamic pulling not supported
|
|
9
|
-
# modelsAuthStyle: bearer → Authorization: Bearer <apiKey>
|
|
10
|
-
# x-api-key → x-api-key: <apiKey> + anthropic-version header
|
|
11
|
-
# modelsDataPath: record field name for models array in JSON response (almost always 'data')
|
|
12
|
-
|
|
13
|
-
presets:
|
|
14
|
-
- id: official
|
|
15
|
-
name: Claude Official
|
|
16
|
-
baseUrl: ''
|
|
17
|
-
apiFormat: anthropic
|
|
18
|
-
needsApiKey: false
|
|
19
|
-
websiteUrl: https://www.anthropic.com/claude-code
|
|
20
|
-
modelsUrl: /v1/models
|
|
21
|
-
modelsAuthStyle: x-api-key
|
|
22
|
-
modelsDataPath: data
|
|
23
|
-
fields:
|
|
24
|
-
- key: name
|
|
25
|
-
label: Provider Nickname
|
|
26
|
-
required: true
|
|
27
|
-
secret: false
|
|
28
|
-
placeholder: 'e.g. Claude Official'
|
|
29
|
-
|
|
30
|
-
- id: openai
|
|
31
|
-
name: OpenAI
|
|
32
|
-
baseUrl: https://api.openai.com/v1
|
|
33
|
-
apiFormat: openai_chat
|
|
34
|
-
needsApiKey: true
|
|
35
|
-
websiteUrl: https://platform.openai.com
|
|
36
|
-
modelsUrl: /v1/models
|
|
37
|
-
modelsAuthStyle: bearer
|
|
38
|
-
modelsDataPath: data
|
|
39
|
-
fields:
|
|
40
|
-
- key: name
|
|
41
|
-
label: Provider Nickname
|
|
42
|
-
required: true
|
|
43
|
-
secret: false
|
|
44
|
-
placeholder: 'e.g. My OpenAI'
|
|
45
|
-
- key: apiKey
|
|
46
|
-
label: API Key
|
|
47
|
-
required: true
|
|
48
|
-
secret: true
|
|
49
|
-
placeholder: 'sk-...'
|
|
50
|
-
- key: baseUrl
|
|
51
|
-
label: Base URL (Optional)
|
|
52
|
-
required: false
|
|
53
|
-
secret: false
|
|
54
|
-
default: https://api.openai.com/v1
|
|
55
|
-
placeholder: 'https://api.openai.com/v1'
|
|
56
|
-
|
|
57
|
-
- id: gemini
|
|
58
|
-
name: Google Gemini
|
|
59
|
-
baseUrl: https://generativelanguage.googleapis.com/v1beta/openai
|
|
60
|
-
apiFormat: openai_chat
|
|
61
|
-
needsApiKey: true
|
|
62
|
-
websiteUrl: https://aistudio.google.com
|
|
63
|
-
modelsUrl: /v1/models
|
|
64
|
-
modelsAuthStyle: bearer
|
|
65
|
-
modelsDataPath: data
|
|
66
|
-
fields:
|
|
67
|
-
- key: name
|
|
68
|
-
label: Provider Nickname
|
|
69
|
-
required: true
|
|
70
|
-
secret: false
|
|
71
|
-
placeholder: 'e.g. My Gemini'
|
|
72
|
-
- key: apiKey
|
|
73
|
-
label: API Key
|
|
74
|
-
required: true
|
|
75
|
-
secret: true
|
|
76
|
-
placeholder: 'Gemini API Key'
|
|
77
|
-
|
|
78
|
-
- id: mistral
|
|
79
|
-
name: Mistral AI
|
|
80
|
-
baseUrl: https://api.mistral.ai/v1
|
|
81
|
-
apiFormat: openai_chat
|
|
82
|
-
needsApiKey: true
|
|
83
|
-
websiteUrl: https://console.mistral.ai
|
|
84
|
-
modelsUrl: /v1/models
|
|
85
|
-
modelsAuthStyle: bearer
|
|
86
|
-
modelsDataPath: data
|
|
87
|
-
fields:
|
|
88
|
-
- key: name
|
|
89
|
-
label: Provider Nickname
|
|
90
|
-
required: true
|
|
91
|
-
secret: false
|
|
92
|
-
placeholder: 'e.g. My Mistral'
|
|
93
|
-
- key: apiKey
|
|
94
|
-
label: API Key
|
|
95
|
-
required: true
|
|
96
|
-
secret: true
|
|
97
|
-
placeholder: 'Mistral API Key'
|
|
98
|
-
|
|
99
|
-
- id: deepseek
|
|
100
|
-
name: DeepSeek
|
|
101
|
-
baseUrl: https://api.deepseek.com/anthropic
|
|
102
|
-
apiFormat: anthropic
|
|
103
|
-
needsApiKey: true
|
|
104
|
-
websiteUrl: https://platform.deepseek.com
|
|
105
|
-
# Models list follows OpenAI endpoint (no /v1/models under /anthropic)
|
|
106
|
-
modelsUrl: https://api.deepseek.com/v1/models
|
|
107
|
-
modelsAuthStyle: bearer
|
|
108
|
-
modelsDataPath: data
|
|
109
|
-
fields:
|
|
110
|
-
- key: name
|
|
111
|
-
label: Provider Nickname
|
|
112
|
-
required: true
|
|
113
|
-
secret: false
|
|
114
|
-
placeholder: 'e.g. My DeepSeek'
|
|
115
|
-
- key: apiKey
|
|
116
|
-
label: API Key
|
|
117
|
-
required: true
|
|
118
|
-
secret: true
|
|
119
|
-
placeholder: 'sk-...'
|
|
120
|
-
|
|
121
|
-
- id: nvidia
|
|
122
|
-
name: NVIDIA API
|
|
123
|
-
baseUrl: https://integrate.api.nvidia.com/v1
|
|
124
|
-
apiFormat: openai_chat
|
|
125
|
-
needsApiKey: true
|
|
126
|
-
websiteUrl: https://build.nvidia.com/explore/discover
|
|
127
|
-
modelsUrl: /models
|
|
128
|
-
modelsAuthStyle: bearer
|
|
129
|
-
modelsDataPath: data
|
|
130
|
-
fields:
|
|
131
|
-
- key: name
|
|
132
|
-
label: Provider Nickname
|
|
133
|
-
required: true
|
|
134
|
-
secret: false
|
|
135
|
-
placeholder: 'e.g. My NVIDIA'
|
|
136
|
-
- key: apiKey
|
|
137
|
-
label: API Key
|
|
138
|
-
required: true
|
|
139
|
-
secret: true
|
|
140
|
-
placeholder: 'nvapi-...'
|
|
141
|
-
|
|
142
|
-
- id: zhipuglm
|
|
143
|
-
name: Zhipu GLM
|
|
144
|
-
baseUrl: https://open.bigmodel.cn/api/paas/v4
|
|
145
|
-
apiFormat: openai_chat
|
|
146
|
-
needsApiKey: true
|
|
147
|
-
websiteUrl: https://open.bigmodel.cn
|
|
148
|
-
modelsUrl: /v4/models
|
|
149
|
-
modelsAuthStyle: bearer
|
|
150
|
-
modelsDataPath: data
|
|
151
|
-
fields:
|
|
152
|
-
- key: name
|
|
153
|
-
label: Provider Nickname
|
|
154
|
-
required: true
|
|
155
|
-
secret: false
|
|
156
|
-
placeholder: 'e.g. My GLM'
|
|
157
|
-
- key: apiKey
|
|
158
|
-
label: API Key
|
|
159
|
-
required: true
|
|
160
|
-
secret: true
|
|
161
|
-
placeholder: 'Zhipu API Key (glm-5.1)'
|
|
162
|
-
|
|
163
|
-
- id: kimi
|
|
164
|
-
name: Kimi
|
|
165
|
-
baseUrl: https://api.moonshot.ai/v1
|
|
166
|
-
apiFormat: openai_chat
|
|
167
|
-
needsApiKey: true
|
|
168
|
-
websiteUrl: https://platform.moonshot.cn
|
|
169
|
-
modelsUrl: /models
|
|
170
|
-
modelsAuthStyle: bearer
|
|
171
|
-
modelsDataPath: data
|
|
172
|
-
fields:
|
|
173
|
-
- key: name
|
|
174
|
-
label: Provider Nickname
|
|
175
|
-
required: true
|
|
176
|
-
secret: false
|
|
177
|
-
placeholder: 'e.g. My Kimi'
|
|
178
|
-
- key: apiKey
|
|
179
|
-
label: API Key
|
|
180
|
-
required: true
|
|
181
|
-
secret: true
|
|
182
|
-
placeholder: 'Moonshot API Key (kimi-k2.6)'
|
|
183
|
-
|
|
184
|
-
- id: minimax
|
|
185
|
-
name: MiniMax
|
|
186
|
-
baseUrl: https://api.minimax.io/v1
|
|
187
|
-
apiFormat: openai_chat
|
|
188
|
-
needsApiKey: true
|
|
189
|
-
websiteUrl: https://platform.minimaxi.com
|
|
190
|
-
modelsUrl: /models
|
|
191
|
-
modelsAuthStyle: bearer
|
|
192
|
-
modelsDataPath: data
|
|
193
|
-
fields:
|
|
194
|
-
- key: name
|
|
195
|
-
label: Provider Nickname
|
|
196
|
-
required: true
|
|
197
|
-
secret: false
|
|
198
|
-
placeholder: 'e.g. My MiniMax'
|
|
199
|
-
- key: apiKey
|
|
200
|
-
label: API Key
|
|
201
|
-
required: true
|
|
202
|
-
secret: true
|
|
203
|
-
placeholder: 'MiniMax API Key (MiniMax-M2.7)'
|
|
204
|
-
|
|
205
|
-
- id: custom
|
|
206
|
-
name: Custom
|
|
207
|
-
baseUrl: ''
|
|
208
|
-
apiFormat: openai_chat
|
|
209
|
-
needsApiKey: true
|
|
210
|
-
websiteUrl: ''
|
|
211
|
-
modelsUrl: /v1/models
|
|
212
|
-
modelsAuthStyle: bearer
|
|
213
|
-
modelsDataPath: data
|
|
214
|
-
fields:
|
|
215
|
-
- key: name
|
|
216
|
-
label: Provider Nickname
|
|
217
|
-
required: true
|
|
218
|
-
secret: false
|
|
219
|
-
placeholder: 'e.g. My Custom Provider'
|
|
220
|
-
- key: baseUrl
|
|
221
|
-
label: Base URL
|
|
222
|
-
required: true
|
|
223
|
-
secret: false
|
|
224
|
-
placeholder: 'https://your-api-endpoint.com/v1'
|
|
225
|
-
- key: apiKey
|
|
226
|
-
label: API Key
|
|
227
|
-
required: false
|
|
228
|
-
secret: true
|
|
229
|
-
placeholder: '(Optional) API Key'
|
|
1
|
+
version: 2
|
|
2
|
+
|
|
3
|
+
# Provider Preset Configuration
|
|
4
|
+
# fields array declares fields to be filled when adding
|
|
5
|
+
# key: 'name' | 'apiKey' | 'baseUrl' mapped directly to top-level fields, others saved in extra.<key>
|
|
6
|
+
# secret: true uses mask display in frontend
|
|
7
|
+
#
|
|
8
|
+
# modelsUrl: model list path relative to baseUrl, empty string means dynamic pulling not supported
|
|
9
|
+
# modelsAuthStyle: bearer → Authorization: Bearer <apiKey>
|
|
10
|
+
# x-api-key → x-api-key: <apiKey> + anthropic-version header
|
|
11
|
+
# modelsDataPath: record field name for models array in JSON response (almost always 'data')
|
|
12
|
+
|
|
13
|
+
presets:
|
|
14
|
+
- id: official
|
|
15
|
+
name: Claude Official
|
|
16
|
+
baseUrl: ''
|
|
17
|
+
apiFormat: anthropic
|
|
18
|
+
needsApiKey: false
|
|
19
|
+
websiteUrl: https://www.anthropic.com/claude-code
|
|
20
|
+
modelsUrl: /v1/models
|
|
21
|
+
modelsAuthStyle: x-api-key
|
|
22
|
+
modelsDataPath: data
|
|
23
|
+
fields:
|
|
24
|
+
- key: name
|
|
25
|
+
label: Provider Nickname
|
|
26
|
+
required: true
|
|
27
|
+
secret: false
|
|
28
|
+
placeholder: 'e.g. Claude Official'
|
|
29
|
+
|
|
30
|
+
- id: openai
|
|
31
|
+
name: OpenAI
|
|
32
|
+
baseUrl: https://api.openai.com/v1
|
|
33
|
+
apiFormat: openai_chat
|
|
34
|
+
needsApiKey: true
|
|
35
|
+
websiteUrl: https://platform.openai.com
|
|
36
|
+
modelsUrl: /v1/models
|
|
37
|
+
modelsAuthStyle: bearer
|
|
38
|
+
modelsDataPath: data
|
|
39
|
+
fields:
|
|
40
|
+
- key: name
|
|
41
|
+
label: Provider Nickname
|
|
42
|
+
required: true
|
|
43
|
+
secret: false
|
|
44
|
+
placeholder: 'e.g. My OpenAI'
|
|
45
|
+
- key: apiKey
|
|
46
|
+
label: API Key
|
|
47
|
+
required: true
|
|
48
|
+
secret: true
|
|
49
|
+
placeholder: 'sk-...'
|
|
50
|
+
- key: baseUrl
|
|
51
|
+
label: Base URL (Optional)
|
|
52
|
+
required: false
|
|
53
|
+
secret: false
|
|
54
|
+
default: https://api.openai.com/v1
|
|
55
|
+
placeholder: 'https://api.openai.com/v1'
|
|
56
|
+
|
|
57
|
+
- id: gemini
|
|
58
|
+
name: Google Gemini
|
|
59
|
+
baseUrl: https://generativelanguage.googleapis.com/v1beta/openai
|
|
60
|
+
apiFormat: openai_chat
|
|
61
|
+
needsApiKey: true
|
|
62
|
+
websiteUrl: https://aistudio.google.com
|
|
63
|
+
modelsUrl: /v1/models
|
|
64
|
+
modelsAuthStyle: bearer
|
|
65
|
+
modelsDataPath: data
|
|
66
|
+
fields:
|
|
67
|
+
- key: name
|
|
68
|
+
label: Provider Nickname
|
|
69
|
+
required: true
|
|
70
|
+
secret: false
|
|
71
|
+
placeholder: 'e.g. My Gemini'
|
|
72
|
+
- key: apiKey
|
|
73
|
+
label: API Key
|
|
74
|
+
required: true
|
|
75
|
+
secret: true
|
|
76
|
+
placeholder: 'Gemini API Key'
|
|
77
|
+
|
|
78
|
+
- id: mistral
|
|
79
|
+
name: Mistral AI
|
|
80
|
+
baseUrl: https://api.mistral.ai/v1
|
|
81
|
+
apiFormat: openai_chat
|
|
82
|
+
needsApiKey: true
|
|
83
|
+
websiteUrl: https://console.mistral.ai
|
|
84
|
+
modelsUrl: /v1/models
|
|
85
|
+
modelsAuthStyle: bearer
|
|
86
|
+
modelsDataPath: data
|
|
87
|
+
fields:
|
|
88
|
+
- key: name
|
|
89
|
+
label: Provider Nickname
|
|
90
|
+
required: true
|
|
91
|
+
secret: false
|
|
92
|
+
placeholder: 'e.g. My Mistral'
|
|
93
|
+
- key: apiKey
|
|
94
|
+
label: API Key
|
|
95
|
+
required: true
|
|
96
|
+
secret: true
|
|
97
|
+
placeholder: 'Mistral API Key'
|
|
98
|
+
|
|
99
|
+
- id: deepseek
|
|
100
|
+
name: DeepSeek
|
|
101
|
+
baseUrl: https://api.deepseek.com/anthropic
|
|
102
|
+
apiFormat: anthropic
|
|
103
|
+
needsApiKey: true
|
|
104
|
+
websiteUrl: https://platform.deepseek.com
|
|
105
|
+
# Models list follows OpenAI endpoint (no /v1/models under /anthropic)
|
|
106
|
+
modelsUrl: https://api.deepseek.com/v1/models
|
|
107
|
+
modelsAuthStyle: bearer
|
|
108
|
+
modelsDataPath: data
|
|
109
|
+
fields:
|
|
110
|
+
- key: name
|
|
111
|
+
label: Provider Nickname
|
|
112
|
+
required: true
|
|
113
|
+
secret: false
|
|
114
|
+
placeholder: 'e.g. My DeepSeek'
|
|
115
|
+
- key: apiKey
|
|
116
|
+
label: API Key
|
|
117
|
+
required: true
|
|
118
|
+
secret: true
|
|
119
|
+
placeholder: 'sk-...'
|
|
120
|
+
|
|
121
|
+
- id: nvidia
|
|
122
|
+
name: NVIDIA API
|
|
123
|
+
baseUrl: https://integrate.api.nvidia.com/v1
|
|
124
|
+
apiFormat: openai_chat
|
|
125
|
+
needsApiKey: true
|
|
126
|
+
websiteUrl: https://build.nvidia.com/explore/discover
|
|
127
|
+
modelsUrl: /models
|
|
128
|
+
modelsAuthStyle: bearer
|
|
129
|
+
modelsDataPath: data
|
|
130
|
+
fields:
|
|
131
|
+
- key: name
|
|
132
|
+
label: Provider Nickname
|
|
133
|
+
required: true
|
|
134
|
+
secret: false
|
|
135
|
+
placeholder: 'e.g. My NVIDIA'
|
|
136
|
+
- key: apiKey
|
|
137
|
+
label: API Key
|
|
138
|
+
required: true
|
|
139
|
+
secret: true
|
|
140
|
+
placeholder: 'nvapi-...'
|
|
141
|
+
|
|
142
|
+
- id: zhipuglm
|
|
143
|
+
name: Zhipu GLM
|
|
144
|
+
baseUrl: https://open.bigmodel.cn/api/paas/v4
|
|
145
|
+
apiFormat: openai_chat
|
|
146
|
+
needsApiKey: true
|
|
147
|
+
websiteUrl: https://open.bigmodel.cn
|
|
148
|
+
modelsUrl: /v4/models
|
|
149
|
+
modelsAuthStyle: bearer
|
|
150
|
+
modelsDataPath: data
|
|
151
|
+
fields:
|
|
152
|
+
- key: name
|
|
153
|
+
label: Provider Nickname
|
|
154
|
+
required: true
|
|
155
|
+
secret: false
|
|
156
|
+
placeholder: 'e.g. My GLM'
|
|
157
|
+
- key: apiKey
|
|
158
|
+
label: API Key
|
|
159
|
+
required: true
|
|
160
|
+
secret: true
|
|
161
|
+
placeholder: 'Zhipu API Key (glm-5.1)'
|
|
162
|
+
|
|
163
|
+
- id: kimi
|
|
164
|
+
name: Kimi
|
|
165
|
+
baseUrl: https://api.moonshot.ai/v1
|
|
166
|
+
apiFormat: openai_chat
|
|
167
|
+
needsApiKey: true
|
|
168
|
+
websiteUrl: https://platform.moonshot.cn
|
|
169
|
+
modelsUrl: /models
|
|
170
|
+
modelsAuthStyle: bearer
|
|
171
|
+
modelsDataPath: data
|
|
172
|
+
fields:
|
|
173
|
+
- key: name
|
|
174
|
+
label: Provider Nickname
|
|
175
|
+
required: true
|
|
176
|
+
secret: false
|
|
177
|
+
placeholder: 'e.g. My Kimi'
|
|
178
|
+
- key: apiKey
|
|
179
|
+
label: API Key
|
|
180
|
+
required: true
|
|
181
|
+
secret: true
|
|
182
|
+
placeholder: 'Moonshot API Key (kimi-k2.6)'
|
|
183
|
+
|
|
184
|
+
- id: minimax
|
|
185
|
+
name: MiniMax
|
|
186
|
+
baseUrl: https://api.minimax.io/v1
|
|
187
|
+
apiFormat: openai_chat
|
|
188
|
+
needsApiKey: true
|
|
189
|
+
websiteUrl: https://platform.minimaxi.com
|
|
190
|
+
modelsUrl: /models
|
|
191
|
+
modelsAuthStyle: bearer
|
|
192
|
+
modelsDataPath: data
|
|
193
|
+
fields:
|
|
194
|
+
- key: name
|
|
195
|
+
label: Provider Nickname
|
|
196
|
+
required: true
|
|
197
|
+
secret: false
|
|
198
|
+
placeholder: 'e.g. My MiniMax'
|
|
199
|
+
- key: apiKey
|
|
200
|
+
label: API Key
|
|
201
|
+
required: true
|
|
202
|
+
secret: true
|
|
203
|
+
placeholder: 'MiniMax API Key (MiniMax-M2.7)'
|
|
204
|
+
|
|
205
|
+
- id: custom
|
|
206
|
+
name: Custom
|
|
207
|
+
baseUrl: ''
|
|
208
|
+
apiFormat: openai_chat
|
|
209
|
+
needsApiKey: true
|
|
210
|
+
websiteUrl: ''
|
|
211
|
+
modelsUrl: /v1/models
|
|
212
|
+
modelsAuthStyle: bearer
|
|
213
|
+
modelsDataPath: data
|
|
214
|
+
fields:
|
|
215
|
+
- key: name
|
|
216
|
+
label: Provider Nickname
|
|
217
|
+
required: true
|
|
218
|
+
secret: false
|
|
219
|
+
placeholder: 'e.g. My Custom Provider'
|
|
220
|
+
- key: baseUrl
|
|
221
|
+
label: Base URL
|
|
222
|
+
required: true
|
|
223
|
+
secret: false
|
|
224
|
+
placeholder: 'https://your-api-endpoint.com/v1'
|
|
225
|
+
- key: apiKey
|
|
226
|
+
label: API Key
|
|
227
|
+
required: false
|
|
228
|
+
secret: true
|
|
229
|
+
placeholder: '(Optional) API Key'
|
|
@@ -269,6 +269,18 @@ export class ProviderService {
|
|
|
269
269
|
// --- Settings sync ---
|
|
270
270
|
|
|
271
271
|
private async syncToSettings(provider: SavedProvider): Promise<void> {
|
|
272
|
+
// Prefer slot-based model IDs when slots are configured, so that the
|
|
273
|
+
// slot table (set via "Configure Model Slots" in the TUI) is the single
|
|
274
|
+
// source of truth. Falling back to provider.models only when no slots
|
|
275
|
+
// exist keeps things working for users who haven't configured slots yet.
|
|
276
|
+
const slots = await this.readSlots()
|
|
277
|
+
const hasSlots = Object.keys(slots).length > 0
|
|
278
|
+
if (hasSlots) {
|
|
279
|
+
await this.syncSettingsForSlots(slots)
|
|
280
|
+
return
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// Legacy fallback: no slots configured — use provider.models directly
|
|
272
284
|
const settings = await this.readSettings()
|
|
273
285
|
const existingEnv = (settings.env as Record<string, string>) || {}
|
|
274
286
|
|
|
@@ -5,7 +5,7 @@ import { ConfigurableShortcutHint } from 'src/components/ConfigurableShortcutHin
|
|
|
5
5
|
import { CtrlOToExpand, SubAgentProvider } from 'src/components/CtrlOToExpand.js';
|
|
6
6
|
import { Byline } from 'src/components/design-system/Byline.js';
|
|
7
7
|
import { KeyboardShortcutHint } from 'src/components/design-system/KeyboardShortcutHint.js';
|
|
8
|
-
import
|
|
8
|
+
import { z } from 'zod/v4';
|
|
9
9
|
import { AgentProgressLine } from '../../components/AgentProgressLine.js';
|
|
10
10
|
import { FallbackToolUseErrorMessage } from '../../components/FallbackToolUseErrorMessage.js';
|
|
11
11
|
import { FallbackToolUseRejectedMessage } from '../../components/FallbackToolUseRejectedMessage.js';
|
|
@@ -15,7 +15,7 @@ import { MessageResponse } from '../../components/MessageResponse.js';
|
|
|
15
15
|
import { ToolUseLoader } from '../../components/ToolUseLoader.js';
|
|
16
16
|
import { Box, Text } from '../../ink.js';
|
|
17
17
|
import { getDumpPromptsPath } from '../../services/api/dumpPrompts.js';
|
|
18
|
-
import { findToolByName, type Tools } from '../../Tool.js';
|
|
18
|
+
import { buildTool, findToolByName, type Tools } from '../../Tool.js';
|
|
19
19
|
import type { Message, ProgressMessage } from '../../types/message.js';
|
|
20
20
|
import type { AgentToolProgress } from '../../types/tools.js';
|
|
21
21
|
import { count } from '../../utils/array.js';
|
|
@@ -540,6 +540,35 @@ export function renderToolUseProgressMessage(progressMessages: ProgressMessage<P
|
|
|
540
540
|
lookups: subagentLookups,
|
|
541
541
|
inProgressToolUseIDs: collapsedInProgressIDs
|
|
542
542
|
} = buildSubagentLookups(progressMessages.filter((pm): pm is ProgressMessage<AgentToolProgress> => hasProgressMessage(pm.data)).map(pm => pm.data));
|
|
543
|
+
|
|
544
|
+
// Augment tools with fallback entries for sub-agent tools not in the
|
|
545
|
+
// coordinator's tool set. In brain mode the coordinator only has
|
|
546
|
+
// [Agent, AskUserQuestion], but sub-agents call Read/Grep/Bash/Edit/etc.
|
|
547
|
+
// Without fallbacks, findToolByName returns null and renders blank lines.
|
|
548
|
+
const knownToolNames = new Set(tools.map(t => t.name))
|
|
549
|
+
let augmentedTools = tools
|
|
550
|
+
for (const block of subagentLookups.toolUseByToolUseID.values()) {
|
|
551
|
+
if (!knownToolNames.has(block.name)) {
|
|
552
|
+
knownToolNames.add(block.name)
|
|
553
|
+
const fallback = buildTool({
|
|
554
|
+
name: block.name,
|
|
555
|
+
inputSchema: z.object({}).passthrough(),
|
|
556
|
+
description: async () => `Sub-agent tool: ${block.name}`,
|
|
557
|
+
call: async () => ({ data: {} as unknown }) as any,
|
|
558
|
+
maxResultSizeChars: 100_000,
|
|
559
|
+
prompt: async () => '',
|
|
560
|
+
mapToolResultToToolResultBlockParam: (content: unknown, toolUseID: string) => ({
|
|
561
|
+
tool_use_id: toolUseID,
|
|
562
|
+
content: [{ type: 'text' as const, text: String(content) }],
|
|
563
|
+
type: 'tool_result' as const,
|
|
564
|
+
}),
|
|
565
|
+
renderToolUseMessage: () => block.name,
|
|
566
|
+
renderToolResultMessage: () => null,
|
|
567
|
+
})
|
|
568
|
+
augmentedTools = [...augmentedTools, fallback]
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
|
|
543
572
|
return <MessageResponse>
|
|
544
573
|
<Box flexDirection="column">
|
|
545
574
|
<SubAgentProvider>
|
|
@@ -558,7 +587,7 @@ export function renderToolUseProgressMessage(progressMessages: ProgressMessage<P
|
|
|
558
587
|
// content (tool not found, renderToolUseMessage returns null)
|
|
559
588
|
// doesn't leave a blank line. Tool call headers are single-line
|
|
560
589
|
// anyway so truncation isn't needed.
|
|
561
|
-
return <MessageComponent key={processed.message.uuid} message={processed.message.data.message} lookups={subagentLookups} addMargin={false} tools={
|
|
590
|
+
return <MessageComponent key={processed.message.uuid} message={processed.message.data.message} lookups={subagentLookups} addMargin={false} tools={augmentedTools} commands={[]} verbose={verbose} inProgressToolUseIDs={collapsedInProgressIDs} progressMessagesForMessage={[]} shouldAnimate={false} shouldShowDot={false} style="condensed" isTranscriptMode={false} isStatic={true} />;
|
|
562
591
|
})}
|
|
563
592
|
</SubAgentProvider>
|
|
564
593
|
{hiddenToolUseCount > 0 && <Text dimColor>
|