evolcore 0.0.9 → 0.0.11
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/CHANGELOG.md +29 -0
- package/README.md +3 -3
- package/dist/agents/baseagent.js +4 -0
- package/dist/agents/claude-runner.js +123 -42
- package/dist/agents/codex-app-server-client.js +33 -9
- package/dist/agents/codex-runner.js +58 -8
- package/dist/agents/ecagent-runner.js +17 -2
- package/dist/agents/request-identity.js +55 -0
- package/dist/aun/outbox.js +28 -31
- package/dist/channels/aun.js +131 -128
- package/dist/cli/agent-command.js +16 -9
- package/dist/cli/agent.js +82 -19
- package/dist/cli/daemon-commands.js +21 -2
- package/dist/cli/index.js +76 -61
- package/dist/cli/init-cancel.js +208 -0
- package/dist/cli/init-channel.js +343 -195
- package/dist/cli/init.js +21 -9
- package/dist/config/builtin-roles.js +1 -0
- package/dist/config/contact-book-store.js +1 -1
- package/dist/config/gateway-config.js +26 -10
- package/dist/core/agent-reload-coordinator.js +53 -0
- package/dist/core/auth/operation-authorizer.js +32 -147
- package/dist/core/auth/operation-catalog.js +80 -0
- package/dist/core/bootstrap-messages.js +50 -0
- package/dist/core/bootstrap-service.js +85 -10
- package/dist/core/channel-loader.js +23 -6
- package/dist/core/command/agent-control.js +14 -11
- package/dist/core/command/menu-handler.js +67 -76
- package/dist/core/command/slash-handler.js +4 -4
- package/dist/core/data-migration.js +79 -27
- package/dist/core/evolagent-registry.js +125 -35
- package/dist/core/evolagent.js +8 -3
- package/dist/core/inference/text-inference.js +38 -4
- package/dist/core/message/message-bridge.js +1 -1
- package/dist/core/message/message-log.js +22 -0
- package/dist/core/message/message-queue.js +19 -4
- package/dist/core/model/model-catalog.js +143 -24
- package/dist/core/model/model-diagnostics.js +28 -10
- package/dist/core/permission/index.js +1 -0
- package/dist/core/permission/readonly-shell-query.js +532 -0
- package/dist/core/permission/shell-environment.js +46 -0
- package/dist/core/permission/tool-policy.js +231 -93
- package/dist/core/protected-paths.js +10 -7
- package/dist/core/runner-reload-transaction.js +57 -0
- package/dist/index.js +262 -84
- package/dist/ipc.js +29 -11
- package/dist/utils/aid-bind.js +3 -8
- package/dist/utils/log-writer.js +6 -10
- package/dist/utils/logger.js +5 -5
- package/kits/docs/evolcore/msg.md +13 -0
- package/kits/rules/01-overview.md +9 -0
- package/kits/schemas/agent-config.schema.3.json +1 -1
- package/kits/schemas/agent-config.schema.4.json +1 -1
- package/kits/schemas/relation-config.schema.2.json +1 -1
- package/kits/schemas/role-config.schema.1.json +1 -1
- package/kits/templates/roles/admin.json +5 -0
- package/kits/templates/roles/member.json +17 -0
- package/kits/templates/roles/visitor.json +8 -0
- package/kits/templates/system-fragments/bootstrap.md +12 -6
- package/kits/templates/system-fragments/channel.md +6 -0
- package/kits/templates/system-fragments/session.md +2 -0
- package/package.json +2 -1
- package/skills/eclink/SKILL.md +15 -3
- package/skills/eclink/agents/openai.yaml +3 -3
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* model-catalog: 模型目录与单模型元数据。
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* 目录来源按 baseagent 隔离:Codex 预创建优先使用 CLI 动态目录;
|
|
5
|
+
* 其他场景探测本 baseagent 的 {baseUrl}/v1/models 与 {baseUrl}/models,
|
|
6
|
+
* 最后只回退到同 baseagent 的内置目录。
|
|
6
7
|
*
|
|
7
8
|
* baseUrl/apiKey 复用 baseagent 凭据解析链(与发消息同源),命令不接收 url/key 参数。
|
|
8
9
|
* 单模型详情(info)现阶段全部为 mock,{baseUrl}/models 接口补全字段后自动接真实数据。
|
|
@@ -10,28 +11,52 @@
|
|
|
10
11
|
* 详见 docs/model-command-design.md。
|
|
11
12
|
*/
|
|
12
13
|
import { resolveAnthropicConfig, resolveEcagentConfig, resolveOpenaiConfig } from '../../agents/baseagent.js';
|
|
14
|
+
import { buildModelRequestHeaders } from '../../agents/request-identity.js';
|
|
13
15
|
import { activeBaseagent } from './config-scope.js';
|
|
14
16
|
import { resolveEffective } from '../../config/config-manager.js';
|
|
17
|
+
import { loadDefaults } from '../../config-store.js';
|
|
18
|
+
import { execCodexCliSync } from '../../utils/codex-cli.js';
|
|
15
19
|
/** 取指定 baseagent 的 baseUrl + apiKey(复用现有解析链)。 */
|
|
16
20
|
function resolveCreds(self, ba) {
|
|
17
21
|
const baseagent = ba || activeBaseagent(self);
|
|
18
|
-
//
|
|
19
|
-
const config = self
|
|
22
|
+
// A new Agent has no self config yet, so resolve its gateway from defaults.
|
|
23
|
+
const config = self
|
|
24
|
+
? resolveEffective({ self }, { cache: true, expand: true })
|
|
25
|
+
: { baseagents: loadDefaults()?.baseagents ?? {} };
|
|
20
26
|
const block = (config.baseagents || {});
|
|
21
27
|
try {
|
|
22
28
|
if (baseagent === 'codex') {
|
|
23
29
|
const c = block.codex;
|
|
24
30
|
const r = resolveOpenaiConfig({ agents: { codex: c } }, c);
|
|
25
|
-
return {
|
|
31
|
+
return {
|
|
32
|
+
baseUrl: r.baseUrl,
|
|
33
|
+
apiKey: r.apiKey,
|
|
34
|
+
agentAid: self,
|
|
35
|
+
headers: buildModelRequestHeaders({ baseagent: 'codex', baseUrl: r.baseUrl, agentAid: self, configuredHeaders: r.headers }),
|
|
36
|
+
};
|
|
26
37
|
}
|
|
27
38
|
if (baseagent === 'ecagent') {
|
|
28
39
|
const c = block.ecagent;
|
|
29
40
|
const r = resolveEcagentConfig({ agents: { ecagent: c } }, c);
|
|
30
|
-
return {
|
|
41
|
+
return {
|
|
42
|
+
baseUrl: r.baseUrl,
|
|
43
|
+
apiKey: r.apiKey,
|
|
44
|
+
agentAid: self,
|
|
45
|
+
headers: buildModelRequestHeaders({ baseagent: 'ecagent', baseUrl: r.baseUrl, agentAid: self, configuredHeaders: r.headers }),
|
|
46
|
+
};
|
|
31
47
|
}
|
|
48
|
+
if (baseagent === 'gemini')
|
|
49
|
+
return {};
|
|
50
|
+
if (baseagent !== 'claude')
|
|
51
|
+
return {};
|
|
32
52
|
const c = block.claude;
|
|
33
53
|
const r = resolveAnthropicConfig({ agents: { claude: c } }, c);
|
|
34
|
-
return {
|
|
54
|
+
return {
|
|
55
|
+
baseUrl: r.baseUrl,
|
|
56
|
+
apiKey: r.apiKey,
|
|
57
|
+
agentAid: self,
|
|
58
|
+
headers: buildModelRequestHeaders({ baseagent: 'claude', baseUrl: r.baseUrl, agentAid: self, configuredHeaders: r.headers }),
|
|
59
|
+
};
|
|
35
60
|
}
|
|
36
61
|
catch {
|
|
37
62
|
return {};
|
|
@@ -97,15 +122,21 @@ export function parseModelList(json, url) {
|
|
|
97
122
|
}
|
|
98
123
|
return genericParse(json);
|
|
99
124
|
}
|
|
100
|
-
|
|
125
|
+
const MODEL_LIST_TIMEOUT_MS = 2000;
|
|
126
|
+
const MODEL_CATALOG_TTL_MS = 30_000;
|
|
127
|
+
const CODEX_CLI_CATALOG_TIMEOUT_MS = 2000;
|
|
128
|
+
async function fetchModelList(url, apiKey, requestHeaders) {
|
|
129
|
+
let timer;
|
|
101
130
|
try {
|
|
102
131
|
const controller = new AbortController();
|
|
103
|
-
|
|
132
|
+
timer = setTimeout(() => controller.abort(), MODEL_LIST_TIMEOUT_MS);
|
|
104
133
|
const resp = await fetch(url, {
|
|
105
134
|
signal: controller.signal,
|
|
106
|
-
headers:
|
|
135
|
+
headers: {
|
|
136
|
+
...(apiKey ? { Authorization: `Bearer ${apiKey}` } : {}),
|
|
137
|
+
...requestHeaders,
|
|
138
|
+
},
|
|
107
139
|
});
|
|
108
|
-
clearTimeout(timer);
|
|
109
140
|
if (!resp.ok)
|
|
110
141
|
return null;
|
|
111
142
|
const json = await resp.json();
|
|
@@ -115,6 +146,10 @@ async function fetchModelList(url, apiKey) {
|
|
|
115
146
|
catch {
|
|
116
147
|
return null;
|
|
117
148
|
}
|
|
149
|
+
finally {
|
|
150
|
+
if (timer)
|
|
151
|
+
clearTimeout(timer);
|
|
152
|
+
}
|
|
118
153
|
}
|
|
119
154
|
/** 内置 mock catalog(接口未就绪时的兜底;实测可用模型,见 docs 附录 A)。 */
|
|
120
155
|
const MOCK_CATALOG = [
|
|
@@ -131,6 +166,53 @@ const MOCK_CATALOG = [
|
|
|
131
166
|
{ id: 'glm-4.7', owned_by: 'zhipu' },
|
|
132
167
|
{ id: 'MiniMax-M2.7', owned_by: 'minimax' },
|
|
133
168
|
];
|
|
169
|
+
const CODEX_BUILTIN_CATALOG = [
|
|
170
|
+
{ id: 'gpt-5.5', owned_by: 'openai' },
|
|
171
|
+
{ id: 'gpt-5.4', owned_by: 'openai' },
|
|
172
|
+
{ id: 'gpt-5.4-mini', owned_by: 'openai' },
|
|
173
|
+
{ id: 'gpt-5.3-codex', owned_by: 'openai' },
|
|
174
|
+
{ id: 'gpt-5.2', owned_by: 'openai' },
|
|
175
|
+
];
|
|
176
|
+
const GEMINI_BUILTIN_CATALOG = [
|
|
177
|
+
{ id: 'gemini-2.5-pro', owned_by: 'google' },
|
|
178
|
+
{ id: 'gemini-2.5-flash', owned_by: 'google' },
|
|
179
|
+
{ id: 'gemini-2.5-flash-lite', owned_by: 'google' },
|
|
180
|
+
];
|
|
181
|
+
const catalogCache = new Map();
|
|
182
|
+
const catalogInFlight = new Map();
|
|
183
|
+
export function clearModelCatalogCache() {
|
|
184
|
+
catalogCache.clear();
|
|
185
|
+
catalogInFlight.clear();
|
|
186
|
+
}
|
|
187
|
+
/** A failed gateway may only fall back within the selected baseagent. */
|
|
188
|
+
export function builtinCatalog(baseagent) {
|
|
189
|
+
if (baseagent === 'codex')
|
|
190
|
+
return CODEX_BUILTIN_CATALOG.map(model => ({ ...model }));
|
|
191
|
+
if (baseagent === 'gemini')
|
|
192
|
+
return GEMINI_BUILTIN_CATALOG.map(model => ({ ...model }));
|
|
193
|
+
if (baseagent === 'ecagent')
|
|
194
|
+
return [{ id: 'claude-sonnet-4-6', owned_by: 'anthropic' }];
|
|
195
|
+
return MOCK_CATALOG.map(model => ({ ...model }));
|
|
196
|
+
}
|
|
197
|
+
function codexCliCatalog() {
|
|
198
|
+
try {
|
|
199
|
+
const output = execCodexCliSync(['debug', 'models'], {
|
|
200
|
+
encoding: 'utf-8',
|
|
201
|
+
timeout: CODEX_CLI_CATALOG_TIMEOUT_MS,
|
|
202
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
203
|
+
});
|
|
204
|
+
const payload = JSON.parse(String(output));
|
|
205
|
+
const models = Array.isArray(payload?.models)
|
|
206
|
+
? payload.models
|
|
207
|
+
.filter((model) => model?.visibility === 'list' && typeof model?.slug === 'string')
|
|
208
|
+
.map((model) => ({ id: model.slug, owned_by: 'openai' }))
|
|
209
|
+
: [];
|
|
210
|
+
return models.length > 0 ? models : null;
|
|
211
|
+
}
|
|
212
|
+
catch {
|
|
213
|
+
return null;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
134
216
|
export function modelMatches(agent, candidate, current) {
|
|
135
217
|
if (!current)
|
|
136
218
|
return false;
|
|
@@ -166,24 +248,61 @@ function withAliases(models, ba) {
|
|
|
166
248
|
.map(a => ({ id: a, owned_by: 'alias' }));
|
|
167
249
|
return [...aliasEntries, ...models];
|
|
168
250
|
}
|
|
169
|
-
/**
|
|
251
|
+
/** 拉取模型目录,并按 self + baseagent 缓存短时间结果。 */
|
|
170
252
|
export async function getCatalog(self, ba) {
|
|
171
253
|
const baseagent = ba || activeBaseagent(self);
|
|
172
|
-
const
|
|
254
|
+
const cacheKey = `${self ?? '<defaults>'}:${baseagent}`;
|
|
255
|
+
const cached = catalogCache.get(cacheKey);
|
|
256
|
+
if (cached && cached.expiresAt > Date.now())
|
|
257
|
+
return cached.value;
|
|
258
|
+
const pending = catalogInFlight.get(cacheKey);
|
|
259
|
+
if (pending)
|
|
260
|
+
return pending;
|
|
261
|
+
const promise = loadCatalog(self, baseagent)
|
|
262
|
+
.then(value => {
|
|
263
|
+
catalogCache.set(cacheKey, { value, expiresAt: Date.now() + MODEL_CATALOG_TTL_MS });
|
|
264
|
+
return value;
|
|
265
|
+
})
|
|
266
|
+
.finally(() => catalogInFlight.delete(cacheKey));
|
|
267
|
+
catalogInFlight.set(cacheKey, promise);
|
|
268
|
+
return promise;
|
|
269
|
+
}
|
|
270
|
+
async function loadCatalog(self, baseagent) {
|
|
271
|
+
// Pre-create has no runner yet. Mirror CodexRunner's dynamic CLI fallback
|
|
272
|
+
// without changing existing self-scoped catalog resolution.
|
|
273
|
+
if (!self && baseagent === 'codex') {
|
|
274
|
+
const cliModels = codexCliCatalog();
|
|
275
|
+
if (cliModels)
|
|
276
|
+
return { models: cliModels, source: 'codex-cli' };
|
|
277
|
+
}
|
|
278
|
+
const { baseUrl, apiKey, headers } = resolveCreds(self, baseagent);
|
|
173
279
|
if (baseUrl) {
|
|
174
280
|
const base = baseUrl.replace(/\/+$/, '');
|
|
175
|
-
const
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
281
|
+
const urls = [...new Set([
|
|
282
|
+
base.endsWith('/v1') ? `${base}/models` : `${base}/v1/models`,
|
|
283
|
+
`${base}/models`,
|
|
284
|
+
])];
|
|
285
|
+
// Probe compatible routes concurrently so a dead route does not add
|
|
286
|
+
// another full timeout before the other route is attempted.
|
|
287
|
+
const results = await Promise.all(urls.map(url => fetchModelList(url, apiKey, headers)));
|
|
288
|
+
const hitIndex = results.findIndex((models) => !!models);
|
|
289
|
+
if (hitIndex >= 0) {
|
|
290
|
+
return {
|
|
291
|
+
models: withAliases(results[hitIndex], baseagent),
|
|
292
|
+
source: hitIndex === 0 ? 'v1/models' : 'models',
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
// This remote directory is Claude-only. Never use it for Codex or Gemini.
|
|
297
|
+
if (baseagent === 'claude') {
|
|
298
|
+
const remote = await fetchModelList(REMOTE_CATALOG_URL, undefined, buildModelRequestHeaders({
|
|
299
|
+
baseagent: 'claude',
|
|
300
|
+
baseUrl: REMOTE_CATALOG_URL,
|
|
301
|
+
}));
|
|
302
|
+
if (remote)
|
|
303
|
+
return { models: withAliases(remote, baseagent), source: 'remote' };
|
|
181
304
|
}
|
|
182
|
-
|
|
183
|
-
const remote = await fetchModelList(REMOTE_CATALOG_URL, apiKey);
|
|
184
|
-
if (remote)
|
|
185
|
-
return { models: withAliases(remote, baseagent), source: 'remote' };
|
|
186
|
-
return { models: withAliases(MOCK_CATALOG, baseagent), source: 'mock' };
|
|
305
|
+
return { models: withAliases(builtinCatalog(baseagent), baseagent), source: 'builtin' };
|
|
187
306
|
}
|
|
188
307
|
/** claude 系判定:完整 ID 或别名(opus/sonnet/haiku)。 */
|
|
189
308
|
function isClaudeFamily(id) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { resolveAnthropicConfig, resolveOpenaiConfig } from '../../agents/baseagent.js';
|
|
1
|
+
import { resolveAnthropicConfig, resolveEcagentConfig, resolveOpenaiConfig } from '../../agents/baseagent.js';
|
|
2
|
+
import { buildModelRequestHeaders } from '../../agents/request-identity.js';
|
|
2
3
|
import { resolveEffective, resolveEffectiveFieldWithSource } from '../../config/config-manager.js';
|
|
3
4
|
import { constrainResolvedModelForRole } from './model-permission.js';
|
|
4
5
|
import { getCatalog } from './model-catalog.js';
|
|
@@ -17,17 +18,34 @@ async function fetchWithTimeout(url, opts, timeoutMs) {
|
|
|
17
18
|
}
|
|
18
19
|
function resolveGatewayCreds(self, baseagent) {
|
|
19
20
|
try {
|
|
20
|
-
const config = self ? resolveEffective({ self }, { cache: true }) : { baseagents: {} };
|
|
21
|
+
const config = self ? resolveEffective({ self }, { cache: true, expand: true }) : { baseagents: {} };
|
|
21
22
|
const block = config.baseagents || {};
|
|
22
23
|
if (baseagent === 'codex') {
|
|
23
24
|
const codexCfg = block.codex || {};
|
|
24
25
|
const resolved = resolveOpenaiConfig({ agents: { codex: codexCfg } }, codexCfg);
|
|
25
|
-
return {
|
|
26
|
+
return {
|
|
27
|
+
baseUrl: resolved.baseUrl,
|
|
28
|
+
apiKey: resolved.apiKey,
|
|
29
|
+
headers: buildModelRequestHeaders({ baseagent: 'codex', baseUrl: resolved.baseUrl, agentAid: self, configuredHeaders: resolved.headers }),
|
|
30
|
+
};
|
|
26
31
|
}
|
|
27
32
|
if (baseagent === 'claude') {
|
|
28
33
|
const claudeCfg = block.claude || {};
|
|
29
34
|
const resolved = resolveAnthropicConfig({ agents: { claude: claudeCfg } }, claudeCfg);
|
|
30
|
-
return {
|
|
35
|
+
return {
|
|
36
|
+
baseUrl: resolved.baseUrl,
|
|
37
|
+
apiKey: resolved.apiKey,
|
|
38
|
+
headers: buildModelRequestHeaders({ baseagent: 'claude', baseUrl: resolved.baseUrl, agentAid: self, configuredHeaders: resolved.headers }),
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
if (baseagent === 'ecagent') {
|
|
42
|
+
const ecagentCfg = block.ecagent || {};
|
|
43
|
+
const resolved = resolveEcagentConfig({ agents: { ecagent: ecagentCfg } }, ecagentCfg);
|
|
44
|
+
return {
|
|
45
|
+
baseUrl: resolved.baseUrl,
|
|
46
|
+
apiKey: resolved.apiKey,
|
|
47
|
+
headers: buildModelRequestHeaders({ baseagent: 'ecagent', baseUrl: resolved.baseUrl, agentAid: self, configuredHeaders: resolved.headers }),
|
|
48
|
+
};
|
|
31
49
|
}
|
|
32
50
|
}
|
|
33
51
|
catch {
|
|
@@ -46,7 +64,7 @@ async function responseError(resp) {
|
|
|
46
64
|
}
|
|
47
65
|
return String(message).slice(0, 80);
|
|
48
66
|
}
|
|
49
|
-
export async function probeModel(baseUrl, apiKey, modelId, timeoutMs) {
|
|
67
|
+
export async function probeModel(baseUrl, apiKey, modelId, timeoutMs, requestHeaders) {
|
|
50
68
|
const base = baseUrl.replace(/\/+$/, '');
|
|
51
69
|
const authHeaders = apiKey
|
|
52
70
|
? { 'x-api-key': apiKey, Authorization: `Bearer ${apiKey}` }
|
|
@@ -56,7 +74,7 @@ export async function probeModel(baseUrl, apiKey, modelId, timeoutMs) {
|
|
|
56
74
|
const anthropicStartedAt = Date.now();
|
|
57
75
|
const anthropic = await fetchWithTimeout(`${base}/v1/messages`, {
|
|
58
76
|
method: 'POST',
|
|
59
|
-
headers: { 'Content-Type': 'application/json', 'anthropic-version': '2023-06-01', ...authHeaders },
|
|
77
|
+
headers: { 'Content-Type': 'application/json', 'anthropic-version': '2023-06-01', ...authHeaders, ...requestHeaders },
|
|
60
78
|
body: JSON.stringify({ model: modelId, max_tokens: 5, messages: [{ role: 'user', content: 'ok' }] }),
|
|
61
79
|
}, Math.min(5000, remainingMs()));
|
|
62
80
|
const anthropicMs = Date.now() - anthropicStartedAt;
|
|
@@ -74,7 +92,7 @@ export async function probeModel(baseUrl, apiKey, modelId, timeoutMs) {
|
|
|
74
92
|
const openaiStartedAt = Date.now();
|
|
75
93
|
const openai = await fetchWithTimeout(`${base}/v1/chat/completions`, {
|
|
76
94
|
method: 'POST',
|
|
77
|
-
headers: { 'Content-Type': 'application/json', ...authHeaders },
|
|
95
|
+
headers: { 'Content-Type': 'application/json', ...authHeaders, ...requestHeaders },
|
|
78
96
|
body: JSON.stringify({ model: modelId, max_tokens: 5, messages: [{ role: 'user', content: 'ok' }] }),
|
|
79
97
|
}, Math.min(5000, remainingMs()));
|
|
80
98
|
const openaiMs = Date.now() - openaiStartedAt;
|
|
@@ -99,7 +117,7 @@ export async function runModelCheck(input) {
|
|
|
99
117
|
steps.push(step);
|
|
100
118
|
input.onStep?.(step);
|
|
101
119
|
};
|
|
102
|
-
const { baseUrl, apiKey } = resolveGatewayCreds(input.self, input.baseagent);
|
|
120
|
+
const { baseUrl, apiKey, headers } = resolveGatewayCreds(input.self, input.baseagent);
|
|
103
121
|
if (!baseUrl) {
|
|
104
122
|
log({ label: '网关地址', ok: false, detail: '未配置受支持的自定义网关,跳过 API 探测' });
|
|
105
123
|
}
|
|
@@ -107,7 +125,7 @@ export async function runModelCheck(input) {
|
|
|
107
125
|
const startedAt = Date.now();
|
|
108
126
|
const ping = await fetchWithTimeout(`${baseUrl.replace(/\/+$/, '')}/v1/models`, {
|
|
109
127
|
method: 'GET',
|
|
110
|
-
headers: apiKey ? { Authorization: `Bearer ${apiKey}` } : {},
|
|
128
|
+
headers: { ...(apiKey ? { Authorization: `Bearer ${apiKey}` } : {}), ...headers },
|
|
111
129
|
}, 4000);
|
|
112
130
|
const elapsed = Date.now() - startedAt;
|
|
113
131
|
log(ping
|
|
@@ -151,7 +169,7 @@ export async function runModelCheck(input) {
|
|
|
151
169
|
];
|
|
152
170
|
for (let index = 0; index < targets.length; index += 2) {
|
|
153
171
|
const batch = await Promise.all(targets.slice(index, index + 2).map(async (target) => {
|
|
154
|
-
const result = await probeModel(baseUrl, apiKey, target.probe, 10_000);
|
|
172
|
+
const result = await probeModel(baseUrl, apiKey, target.probe, 10_000, headers);
|
|
155
173
|
return { id: target.display, ...result };
|
|
156
174
|
}));
|
|
157
175
|
for (const result of batch) {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export * from './tool-policy.js';
|
|
2
2
|
export * from './ec-command-parser.js';
|
|
3
|
+
export * from './readonly-shell-query.js';
|
|
3
4
|
export * from './approval-gateway.js';
|
|
4
5
|
export * from './execution-sandbox.js';
|
|
5
6
|
// Tool summaries live in utils; keep the historical permission import path compatible.
|