@mcoda/agents 0.1.40 → 0.1.42
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.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AgentService.d.ts","sourceRoot":"","sources":["../../src/AgentService/AgentService.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,KAAK,EACL,iBAAiB,EACjB,WAAW,EACX,mBAAmB,EAKpB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAY7C,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;
|
|
1
|
+
{"version":3,"file":"AgentService.d.ts","sourceRoot":"","sources":["../../src/AgentService/AgentService.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,KAAK,EACL,iBAAiB,EACjB,WAAW,EACX,mBAAmB,EAKpB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAY7C,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAsNhG,UAAU,mBAAmB;IAC3B,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC,sBAAsB,CAAC,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;IAChD,0BAA0B,CAAC,EAAE,MAAM,CAAC;CACrC;AAED,qBAAa,YAAY;IAErB,OAAO,CAAC,IAAI;IACZ,OAAO,CAAC,OAAO;gBADP,IAAI,EAAE,gBAAgB,EACtB,OAAO,GAAE,mBAAwB;WAG9B,MAAM,IAAI,OAAO,CAAC,YAAY,CAAC;IAKtC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAItB,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC;IAUhD,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,GAAG,SAAS,CAAC;IAIrE,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAInD,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC;YAIpD,kBAAkB;YAMlB,kBAAkB;IA6BhC,OAAO,CAAC,kBAAkB;IA0CpB,UAAU,CAAC,KAAK,EAAE,KAAK,EAAE,eAAe,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IA4C/E,OAAO,CAAC,KAAK;YAIC,OAAO;YASP,UAAU;IAQxB,OAAO,CAAC,6BAA6B;YAOvB,mBAAmB;YAgCnB,uBAAuB;YAiBvB,gBAAgB;IAM9B,OAAO,CAAC,MAAM;IAId,OAAO,CAAC,qBAAqB;IAI7B,OAAO,CAAC,8BAA8B;IAStC,OAAO,CAAC,iBAAiB;YAOX,oBAAoB;YA6BpB,oBAAoB;YA6CpB,sBAAsB;YAkBtB,mBAAmB;YAUnB,4BAA4B;IAkCpC,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAmBlD,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,gBAAgB,CAAC;IA6H9E,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,cAAc,CAAC,gBAAgB,CAAC,CAAC;YAwP5F,mBAAmB;YAkBnB,uBAAuB;YAwBvB,mBAAmB;CAYlC"}
|
|
@@ -56,16 +56,27 @@ const WINDOW_RESET_FALLBACK_MS = {
|
|
|
56
56
|
weekly: 7 * 24 * 60 * 60 * 1000,
|
|
57
57
|
other: 60 * 60 * 1000,
|
|
58
58
|
};
|
|
59
|
-
const
|
|
59
|
+
const getManagedMswarmKind = (agent) => {
|
|
60
60
|
const config = agent.config;
|
|
61
61
|
if (!config || typeof config !== "object" || Array.isArray(config)) {
|
|
62
|
-
return
|
|
62
|
+
return undefined;
|
|
63
|
+
}
|
|
64
|
+
const record = config;
|
|
65
|
+
const cloud = record.mswarmCloud;
|
|
66
|
+
if (cloud &&
|
|
67
|
+
typeof cloud === "object" &&
|
|
68
|
+
!Array.isArray(cloud) &&
|
|
69
|
+
cloud.managed === true) {
|
|
70
|
+
return "cloud";
|
|
71
|
+
}
|
|
72
|
+
const selfHosted = record.mswarmSelfHosted;
|
|
73
|
+
if (selfHosted &&
|
|
74
|
+
typeof selfHosted === "object" &&
|
|
75
|
+
!Array.isArray(selfHosted) &&
|
|
76
|
+
selfHosted.managed === true) {
|
|
77
|
+
return "self-hosted";
|
|
63
78
|
}
|
|
64
|
-
|
|
65
|
-
return Boolean(managed &&
|
|
66
|
-
typeof managed === "object" &&
|
|
67
|
-
!Array.isArray(managed) &&
|
|
68
|
-
managed.managed === true);
|
|
79
|
+
return undefined;
|
|
69
80
|
};
|
|
70
81
|
const isIoEnabled = () => {
|
|
71
82
|
const raw = process.env[IO_ENV];
|
|
@@ -277,9 +288,13 @@ export class AgentService {
|
|
|
277
288
|
if (adapterType.endsWith("-api")) {
|
|
278
289
|
if (hasSecret)
|
|
279
290
|
return adapterType;
|
|
280
|
-
|
|
291
|
+
const managedMswarmKind = adapterType === "openai-api" ? getManagedMswarmKind(agent) : undefined;
|
|
292
|
+
if (managedMswarmKind) {
|
|
281
293
|
const label = agent.slug ?? agent.id;
|
|
282
|
-
|
|
294
|
+
const syncCommand = managedMswarmKind === "self-hosted"
|
|
295
|
+
? "mcoda self-hosted agent sync"
|
|
296
|
+
: "mcoda cloud agent sync";
|
|
297
|
+
throw new Error(`AUTH_REQUIRED: Managed mswarm ${managedMswarmKind} agent ${label} is missing the synced API key; run \`mcoda config set mswarm-api-key <KEY>\` and \`${syncCommand}\`.`);
|
|
283
298
|
}
|
|
284
299
|
if (adapterType === "codex-api" || adapterType === "openai-api") {
|
|
285
300
|
// Default to the codex CLI when API creds are missing.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OpenAiAdapter.d.ts","sourceRoot":"","sources":["../../../src/adapters/openai/OpenAiAdapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"OpenAiAdapter.d.ts","sourceRoot":"","sources":["../../../src/adapters/openai/OpenAiAdapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAiKtG,KAAK,YAAY,GAAG,aAAa,GAAG;IAClC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACrC,CAAC;AAEF,qBAAa,aAAc,YAAW,YAAY;IAMpC,OAAO,CAAC,MAAM;IAL1B,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,OAAO,CAAqC;IACpD,OAAO,CAAC,WAAW,CAAqB;IACxC,OAAO,CAAC,SAAS,CAAsC;gBAEnC,MAAM,EAAE,YAAY;IAUlC,eAAe,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAIpC,WAAW,IAAI,OAAO,CAAC,WAAW,CAAC;IA6GnC,MAAM,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAwC5D,YAAY,CAAC,OAAO,EAAE,iBAAiB,GAAG,cAAc,CAAC,gBAAgB,EAAE,IAAI,EAAE,OAAO,CAAC;IAwFhG,OAAO,CAAC,YAAY;IAMpB,OAAO,CAAC,aAAa;IAIrB,OAAO,CAAC,WAAW;IAOnB,OAAO,CAAC,YAAY;IASpB,OAAO,CAAC,YAAY;IASpB,OAAO,CAAC,SAAS;IAoBjB,OAAO,CAAC,oBAAoB;CAU7B"}
|
|
@@ -1,4 +1,13 @@
|
|
|
1
|
+
import { parseUsageLimitError } from "../../AgentService/UsageLimitParser.js";
|
|
1
2
|
const DEFAULT_BASE_URL = "https://api.openai.com/v1";
|
|
3
|
+
const MAX_RESPONSE_DETAIL_CHARS = 500;
|
|
4
|
+
const RATE_LIMIT_HEADER_NAMES = [
|
|
5
|
+
"retry-after",
|
|
6
|
+
"x-ratelimit-reset-after",
|
|
7
|
+
"x-ratelimit-reset",
|
|
8
|
+
"x-ratelimit-reset-at",
|
|
9
|
+
"x-ratelimit-remaining",
|
|
10
|
+
];
|
|
2
11
|
const asString = (value) => (typeof value === "string" ? value : undefined);
|
|
3
12
|
const resolveString = (value) => {
|
|
4
13
|
const raw = asString(value)?.trim();
|
|
@@ -11,6 +20,37 @@ const normalizeBaseUrl = (value) => {
|
|
|
11
20
|
return undefined;
|
|
12
21
|
return str.endsWith("/") ? str.slice(0, -1) : str;
|
|
13
22
|
};
|
|
23
|
+
const buildRateLimitProbeMessage = (response, responseText) => {
|
|
24
|
+
const parts = [`openai_probe http ${response.status}`];
|
|
25
|
+
const retryAfter = response.headers.get("retry-after")?.trim();
|
|
26
|
+
if (retryAfter) {
|
|
27
|
+
const retryAfterSeconds = Number.parseInt(retryAfter, 10);
|
|
28
|
+
parts.push(Number.isFinite(retryAfterSeconds) && retryAfterSeconds > 0
|
|
29
|
+
? `Retry after ${retryAfterSeconds} seconds`
|
|
30
|
+
: `Retry after ${retryAfter}`);
|
|
31
|
+
}
|
|
32
|
+
for (const headerName of RATE_LIMIT_HEADER_NAMES) {
|
|
33
|
+
if (headerName === "retry-after")
|
|
34
|
+
continue;
|
|
35
|
+
const headerValue = response.headers.get(headerName)?.trim();
|
|
36
|
+
if (headerValue) {
|
|
37
|
+
parts.push(`${headerName}: ${headerValue}`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
const trimmedResponse = responseText.trim();
|
|
41
|
+
if (trimmedResponse) {
|
|
42
|
+
parts.push(trimmedResponse);
|
|
43
|
+
}
|
|
44
|
+
return parts.join(". ");
|
|
45
|
+
};
|
|
46
|
+
const resolveRetryAfterMs = (resetAt, nowMs) => {
|
|
47
|
+
if (!resetAt)
|
|
48
|
+
return undefined;
|
|
49
|
+
const timestampMs = Date.parse(resetAt);
|
|
50
|
+
if (!Number.isFinite(timestampMs))
|
|
51
|
+
return undefined;
|
|
52
|
+
return Math.max(0, timestampMs - nowMs);
|
|
53
|
+
};
|
|
14
54
|
const resolveBaseUrl = (config) => {
|
|
15
55
|
const anyConfig = config;
|
|
16
56
|
const agentConfig = config.agent?.config;
|
|
@@ -148,12 +188,38 @@ export class OpenAiAdapter {
|
|
|
148
188
|
body: JSON.stringify(this.buildHealthCheckBody(model)),
|
|
149
189
|
});
|
|
150
190
|
const responseText = await response.text().catch(() => "");
|
|
151
|
-
const
|
|
191
|
+
const checkedAtMs = Date.now();
|
|
192
|
+
const lastCheckedAt = new Date(checkedAtMs).toISOString();
|
|
193
|
+
const latencyMs = checkedAtMs - startedAt;
|
|
152
194
|
if (!response.ok) {
|
|
195
|
+
if (response.status === 429) {
|
|
196
|
+
const parsedLimit = parseUsageLimitError(new Error(buildRateLimitProbeMessage(response, responseText)), checkedAtMs);
|
|
197
|
+
return {
|
|
198
|
+
agentId: this.config.agent.id,
|
|
199
|
+
status: "healthy",
|
|
200
|
+
lastCheckedAt,
|
|
201
|
+
latencyMs,
|
|
202
|
+
details: {
|
|
203
|
+
adapter: "openai-api",
|
|
204
|
+
source: "openai_probe",
|
|
205
|
+
model,
|
|
206
|
+
baseUrl: url,
|
|
207
|
+
reason: "rate_limited",
|
|
208
|
+
transient: true,
|
|
209
|
+
rateLimited: true,
|
|
210
|
+
httpStatus: response.status,
|
|
211
|
+
response: responseText.slice(0, MAX_RESPONSE_DETAIL_CHARS),
|
|
212
|
+
resetAt: parsedLimit?.resetAt,
|
|
213
|
+
resetAtSource: parsedLimit?.resetAtSource,
|
|
214
|
+
retryAfterMs: resolveRetryAfterMs(parsedLimit?.resetAt, checkedAtMs),
|
|
215
|
+
windowTypes: parsedLimit?.windowTypes,
|
|
216
|
+
},
|
|
217
|
+
};
|
|
218
|
+
}
|
|
153
219
|
return {
|
|
154
220
|
agentId: this.config.agent.id,
|
|
155
|
-
status:
|
|
156
|
-
lastCheckedAt
|
|
221
|
+
status: "unreachable",
|
|
222
|
+
lastCheckedAt,
|
|
157
223
|
latencyMs,
|
|
158
224
|
details: {
|
|
159
225
|
adapter: "openai-api",
|
|
@@ -162,14 +228,14 @@ export class OpenAiAdapter {
|
|
|
162
228
|
baseUrl: url,
|
|
163
229
|
reason: "http_error",
|
|
164
230
|
httpStatus: response.status,
|
|
165
|
-
response: responseText.slice(0,
|
|
231
|
+
response: responseText.slice(0, MAX_RESPONSE_DETAIL_CHARS),
|
|
166
232
|
},
|
|
167
233
|
};
|
|
168
234
|
}
|
|
169
235
|
return {
|
|
170
236
|
agentId: this.config.agent.id,
|
|
171
237
|
status: "healthy",
|
|
172
|
-
lastCheckedAt
|
|
238
|
+
lastCheckedAt,
|
|
173
239
|
latencyMs,
|
|
174
240
|
details: {
|
|
175
241
|
adapter: "openai-api",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mcoda/agents",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.42",
|
|
4
4
|
"description": "Agent registry and capabilities for mcoda.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -30,8 +30,8 @@
|
|
|
30
30
|
"access": "public"
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@mcoda/shared": "0.1.
|
|
34
|
-
"@mcoda/db": "0.1.
|
|
33
|
+
"@mcoda/shared": "0.1.42",
|
|
34
|
+
"@mcoda/db": "0.1.42"
|
|
35
35
|
},
|
|
36
36
|
"scripts": {
|
|
37
37
|
"build": "tsc -p tsconfig.json",
|