@mcoda/agents 0.1.37 → 0.1.38
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/dist/adapters/openai/OpenAiAdapter.d.ts +20 -1
- package/dist/adapters/openai/OpenAiAdapter.d.ts.map +1 -1
- package/dist/adapters/openai/OpenAiAdapter.js +287 -14
- package/dist/adapters/zhipu/ZhipuApiAdapter.d.ts +1 -1
- package/dist/adapters/zhipu/ZhipuApiAdapter.d.ts.map +1 -1
- package/dist/adapters/zhipu/ZhipuApiAdapter.js +18 -3
- package/package.json +3 -3
|
@@ -1,11 +1,30 @@
|
|
|
1
1
|
import { AgentHealth } from "@mcoda/shared";
|
|
2
2
|
import { AdapterConfig, AgentAdapter, InvocationRequest, InvocationResult } from "../AdapterTypes.js";
|
|
3
|
+
type OpenAiConfig = AdapterConfig & {
|
|
4
|
+
baseUrl?: string;
|
|
5
|
+
endpoint?: string;
|
|
6
|
+
apiBaseUrl?: string;
|
|
7
|
+
headers?: Record<string, string>;
|
|
8
|
+
temperature?: number;
|
|
9
|
+
extraBody?: Record<string, unknown>;
|
|
10
|
+
};
|
|
3
11
|
export declare class OpenAiAdapter implements AgentAdapter {
|
|
4
12
|
private config;
|
|
5
|
-
|
|
13
|
+
private baseUrl;
|
|
14
|
+
private headers;
|
|
15
|
+
private temperature;
|
|
16
|
+
private extraBody;
|
|
17
|
+
constructor(config: OpenAiConfig);
|
|
6
18
|
getCapabilities(): Promise<string[]>;
|
|
7
19
|
healthCheck(): Promise<AgentHealth>;
|
|
8
20
|
invoke(request: InvocationRequest): Promise<InvocationResult>;
|
|
9
21
|
invokeStream(request: InvocationRequest): AsyncGenerator<InvocationResult, void, unknown>;
|
|
22
|
+
private assertConfig;
|
|
23
|
+
private ensureBaseUrl;
|
|
24
|
+
private ensureModel;
|
|
25
|
+
private ensureApiKey;
|
|
26
|
+
private buildHeaders;
|
|
27
|
+
private buildBody;
|
|
10
28
|
}
|
|
29
|
+
export {};
|
|
11
30
|
//# sourceMappingURL=OpenAiAdapter.d.ts.map
|
|
@@ -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;AAwHtG,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;IAkBnC,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;CAmBlB"}
|
|
@@ -1,6 +1,123 @@
|
|
|
1
|
+
const DEFAULT_BASE_URL = "https://api.openai.com/v1";
|
|
2
|
+
const asString = (value) => (typeof value === "string" ? value : undefined);
|
|
3
|
+
const resolveString = (value) => {
|
|
4
|
+
const raw = asString(value)?.trim();
|
|
5
|
+
return raw ? raw : undefined;
|
|
6
|
+
};
|
|
7
|
+
const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
8
|
+
const normalizeBaseUrl = (value) => {
|
|
9
|
+
const str = resolveString(value);
|
|
10
|
+
if (!str)
|
|
11
|
+
return undefined;
|
|
12
|
+
return str.endsWith("/") ? str.slice(0, -1) : str;
|
|
13
|
+
};
|
|
14
|
+
const resolveBaseUrl = (config) => {
|
|
15
|
+
const anyConfig = config;
|
|
16
|
+
const agentConfig = config.agent?.config;
|
|
17
|
+
return (normalizeBaseUrl(anyConfig.baseUrl) ??
|
|
18
|
+
normalizeBaseUrl(anyConfig.endpoint) ??
|
|
19
|
+
normalizeBaseUrl(anyConfig.apiBaseUrl) ??
|
|
20
|
+
normalizeBaseUrl(agentConfig?.baseUrl) ??
|
|
21
|
+
normalizeBaseUrl(agentConfig?.endpoint) ??
|
|
22
|
+
normalizeBaseUrl(agentConfig?.apiBaseUrl) ??
|
|
23
|
+
DEFAULT_BASE_URL);
|
|
24
|
+
};
|
|
25
|
+
const extractUsage = (usage) => {
|
|
26
|
+
if (!isRecord(usage))
|
|
27
|
+
return undefined;
|
|
28
|
+
const tokensPrompt = typeof usage.prompt_tokens === "number"
|
|
29
|
+
? usage.prompt_tokens
|
|
30
|
+
: typeof usage.promptTokens === "number"
|
|
31
|
+
? usage.promptTokens
|
|
32
|
+
: undefined;
|
|
33
|
+
const tokensCompletion = typeof usage.completion_tokens === "number"
|
|
34
|
+
? usage.completion_tokens
|
|
35
|
+
: typeof usage.completionTokens === "number"
|
|
36
|
+
? usage.completionTokens
|
|
37
|
+
: undefined;
|
|
38
|
+
let tokensTotal = typeof usage.total_tokens === "number"
|
|
39
|
+
? usage.total_tokens
|
|
40
|
+
: typeof usage.totalTokens === "number"
|
|
41
|
+
? usage.totalTokens
|
|
42
|
+
: undefined;
|
|
43
|
+
if (tokensTotal === undefined && typeof tokensPrompt === "number" && typeof tokensCompletion === "number") {
|
|
44
|
+
tokensTotal = tokensPrompt + tokensCompletion;
|
|
45
|
+
}
|
|
46
|
+
if (tokensPrompt === undefined && tokensCompletion === undefined && tokensTotal === undefined) {
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
49
|
+
return { tokensPrompt, tokensCompletion, tokensTotal };
|
|
50
|
+
};
|
|
51
|
+
const collectContentText = (value) => {
|
|
52
|
+
const direct = asString(value);
|
|
53
|
+
if (direct !== undefined)
|
|
54
|
+
return [direct];
|
|
55
|
+
if (Array.isArray(value))
|
|
56
|
+
return value.flatMap((entry) => collectContentText(entry));
|
|
57
|
+
if (!isRecord(value))
|
|
58
|
+
return [];
|
|
59
|
+
const partType = resolveString(value.type)?.toLowerCase();
|
|
60
|
+
if (partType?.startsWith("reasoning"))
|
|
61
|
+
return [];
|
|
62
|
+
if (asString(value.text) !== undefined)
|
|
63
|
+
return [value.text];
|
|
64
|
+
if (asString(value.output_text) !== undefined)
|
|
65
|
+
return [value.output_text];
|
|
66
|
+
if (asString(value.input_text) !== undefined)
|
|
67
|
+
return [value.input_text];
|
|
68
|
+
if ("content" in value)
|
|
69
|
+
return collectContentText(value.content);
|
|
70
|
+
return [];
|
|
71
|
+
};
|
|
72
|
+
const collectReasoningText = (value) => {
|
|
73
|
+
const direct = asString(value);
|
|
74
|
+
if (direct !== undefined)
|
|
75
|
+
return [direct];
|
|
76
|
+
if (Array.isArray(value))
|
|
77
|
+
return value.flatMap((entry) => collectReasoningText(entry));
|
|
78
|
+
if (!isRecord(value))
|
|
79
|
+
return [];
|
|
80
|
+
const partType = resolveString(value.type)?.toLowerCase();
|
|
81
|
+
if (partType?.startsWith("reasoning")) {
|
|
82
|
+
if (asString(value.text) !== undefined)
|
|
83
|
+
return [value.text];
|
|
84
|
+
if ("content" in value)
|
|
85
|
+
return collectReasoningText(value.content);
|
|
86
|
+
}
|
|
87
|
+
const reasoningFields = [value.reasoning_content, value.reasoning_text, value.summary, value.reasoning];
|
|
88
|
+
const segments = reasoningFields.flatMap((entry) => collectReasoningText(entry));
|
|
89
|
+
if (segments.length > 0)
|
|
90
|
+
return segments;
|
|
91
|
+
return [];
|
|
92
|
+
};
|
|
93
|
+
const collapseText = (segments) => {
|
|
94
|
+
const joined = segments.join("");
|
|
95
|
+
const trimmed = joined.trim();
|
|
96
|
+
return trimmed ? trimmed : undefined;
|
|
97
|
+
};
|
|
98
|
+
const extractResponseText = (data) => {
|
|
99
|
+
const payload = isRecord(data) ? data : {};
|
|
100
|
+
const choices = Array.isArray(payload.choices) ? payload.choices : [];
|
|
101
|
+
const choice = choices[0];
|
|
102
|
+
const message = isRecord(choice) && (isRecord(choice.message) ? choice.message : isRecord(choice.delta) ? choice.delta : {})
|
|
103
|
+
? (isRecord(choice.message) ? choice.message : choice.delta)
|
|
104
|
+
: {};
|
|
105
|
+
const content = collapseText(collectContentText(message.content ?? message));
|
|
106
|
+
const reasoning = collapseText(collectReasoningText(message.reasoning ?? message));
|
|
107
|
+
const fallback = resolveString(payload.output_text) ??
|
|
108
|
+
collapseText(collectContentText(payload.output ?? payload.response ?? payload.data));
|
|
109
|
+
return { output: content ?? reasoning ?? fallback, reasoning };
|
|
110
|
+
};
|
|
1
111
|
export class OpenAiAdapter {
|
|
2
112
|
constructor(config) {
|
|
3
113
|
this.config = config;
|
|
114
|
+
this.baseUrl = resolveBaseUrl(config);
|
|
115
|
+
this.headers = isRecord(config.headers) ? config.headers : undefined;
|
|
116
|
+
this.temperature = typeof config.temperature === "number" ? config.temperature : undefined;
|
|
117
|
+
this.extraBody = isRecord(config.extraBody)
|
|
118
|
+
? config.extraBody
|
|
119
|
+
: undefined;
|
|
120
|
+
this.assertConfig();
|
|
4
121
|
}
|
|
5
122
|
async getCapabilities() {
|
|
6
123
|
return this.config.capabilities;
|
|
@@ -19,33 +136,189 @@ export class OpenAiAdapter {
|
|
|
19
136
|
status: "healthy",
|
|
20
137
|
lastCheckedAt: new Date().toISOString(),
|
|
21
138
|
latencyMs: 0,
|
|
22
|
-
details: { adapter: "openai-api", model: this.config.model },
|
|
139
|
+
details: { adapter: "openai-api", model: this.config.model, baseUrl: this.baseUrl },
|
|
23
140
|
};
|
|
24
141
|
}
|
|
25
142
|
async invoke(request) {
|
|
26
|
-
const
|
|
143
|
+
const url = this.ensureBaseUrl();
|
|
144
|
+
const model = this.ensureModel();
|
|
145
|
+
const apiKey = this.ensureApiKey();
|
|
146
|
+
const resp = await fetch(`${url}/chat/completions`, {
|
|
147
|
+
method: "POST",
|
|
148
|
+
headers: this.buildHeaders(apiKey, false),
|
|
149
|
+
body: JSON.stringify(this.buildBody(request.input, model, false)),
|
|
150
|
+
});
|
|
151
|
+
if (!resp.ok) {
|
|
152
|
+
const text = await resp.text().catch(() => "");
|
|
153
|
+
throw new Error(`OpenAI chat completions failed (${resp.status}): ${text}`);
|
|
154
|
+
}
|
|
155
|
+
const data = await resp.json().catch(() => ({}));
|
|
156
|
+
const usage = extractUsage(isRecord(data) ? data.usage : undefined);
|
|
157
|
+
const { output, reasoning } = extractResponseText(data);
|
|
27
158
|
return {
|
|
28
|
-
output:
|
|
159
|
+
output: (output ?? JSON.stringify(data)).trim(),
|
|
29
160
|
adapter: this.config.adapter ?? "openai-api",
|
|
30
|
-
model
|
|
161
|
+
model,
|
|
31
162
|
metadata: {
|
|
32
|
-
mode:
|
|
163
|
+
mode: "api",
|
|
33
164
|
capabilities: this.config.capabilities,
|
|
34
165
|
prompts: this.config.prompts,
|
|
35
|
-
authMode,
|
|
166
|
+
authMode: "api",
|
|
36
167
|
adapterType: this.config.adapter ?? "openai-api",
|
|
168
|
+
baseUrl: url,
|
|
169
|
+
usage: isRecord(data) ? data.usage : undefined,
|
|
170
|
+
tokensPrompt: usage?.tokensPrompt,
|
|
171
|
+
tokensCompletion: usage?.tokensCompletion,
|
|
172
|
+
tokensTotal: usage?.tokensTotal,
|
|
173
|
+
tokens_prompt: usage?.tokensPrompt,
|
|
174
|
+
tokens_completion: usage?.tokensCompletion,
|
|
175
|
+
tokens_total: usage?.tokensTotal,
|
|
176
|
+
reasoning,
|
|
37
177
|
},
|
|
38
178
|
};
|
|
39
179
|
}
|
|
40
180
|
async *invokeStream(request) {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
181
|
+
const url = this.ensureBaseUrl();
|
|
182
|
+
const model = this.ensureModel();
|
|
183
|
+
const apiKey = this.ensureApiKey();
|
|
184
|
+
const resp = await fetch(`${url}/chat/completions`, {
|
|
185
|
+
method: "POST",
|
|
186
|
+
headers: this.buildHeaders(apiKey, true),
|
|
187
|
+
body: JSON.stringify(this.buildBody(request.input, model, true)),
|
|
188
|
+
});
|
|
189
|
+
if (!resp.ok || !resp.body) {
|
|
190
|
+
const text = !resp.ok ? await resp.text().catch(() => "") : "";
|
|
191
|
+
throw new Error(`OpenAI chat completions (stream) failed (${resp.status}): ${text}`);
|
|
192
|
+
}
|
|
193
|
+
const reader = resp.body.getReader();
|
|
194
|
+
const decoder = new TextDecoder();
|
|
195
|
+
let buffer = "";
|
|
196
|
+
let latestUsage;
|
|
197
|
+
const buildChunk = (payload) => {
|
|
198
|
+
const data = JSON.parse(payload);
|
|
199
|
+
const usage = extractUsage(isRecord(data) ? data.usage : undefined);
|
|
200
|
+
if (usage)
|
|
201
|
+
latestUsage = usage;
|
|
202
|
+
const { output, reasoning } = extractResponseText(data);
|
|
203
|
+
if (!output && !usage)
|
|
204
|
+
return null;
|
|
205
|
+
return {
|
|
206
|
+
output: output ?? "",
|
|
207
|
+
adapter: this.config.adapter ?? "openai-api",
|
|
208
|
+
model,
|
|
209
|
+
metadata: {
|
|
210
|
+
mode: "api",
|
|
211
|
+
authMode: "api",
|
|
212
|
+
adapterType: this.config.adapter ?? "openai-api",
|
|
213
|
+
baseUrl: url,
|
|
214
|
+
capabilities: this.config.capabilities,
|
|
215
|
+
prompts: this.config.prompts,
|
|
216
|
+
streaming: true,
|
|
217
|
+
usage: isRecord(data) ? data.usage : undefined,
|
|
218
|
+
tokensPrompt: latestUsage?.tokensPrompt,
|
|
219
|
+
tokensCompletion: latestUsage?.tokensCompletion,
|
|
220
|
+
tokensTotal: latestUsage?.tokensTotal,
|
|
221
|
+
tokens_prompt: latestUsage?.tokensPrompt,
|
|
222
|
+
tokens_completion: latestUsage?.tokensCompletion,
|
|
223
|
+
tokens_total: latestUsage?.tokensTotal,
|
|
224
|
+
reasoning,
|
|
225
|
+
raw: payload,
|
|
226
|
+
},
|
|
227
|
+
};
|
|
228
|
+
};
|
|
229
|
+
while (true) {
|
|
230
|
+
const { value, done } = await reader.read();
|
|
231
|
+
if (done)
|
|
232
|
+
break;
|
|
233
|
+
buffer += decoder.decode(value, { stream: true });
|
|
234
|
+
let idx;
|
|
235
|
+
while ((idx = buffer.indexOf("\n")) !== -1) {
|
|
236
|
+
const line = buffer.slice(0, idx).trim();
|
|
237
|
+
buffer = buffer.slice(idx + 1);
|
|
238
|
+
if (!line || !line.startsWith("data:"))
|
|
239
|
+
continue;
|
|
240
|
+
const payload = line.slice(5).trim();
|
|
241
|
+
if (!payload)
|
|
242
|
+
continue;
|
|
243
|
+
if (payload === "[DONE]")
|
|
244
|
+
return;
|
|
245
|
+
try {
|
|
246
|
+
const chunk = buildChunk(payload);
|
|
247
|
+
if (chunk)
|
|
248
|
+
yield chunk;
|
|
249
|
+
}
|
|
250
|
+
catch {
|
|
251
|
+
// Ignore malformed SSE lines and continue streaming.
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
const tail = buffer.trim();
|
|
256
|
+
if (!tail)
|
|
257
|
+
return;
|
|
258
|
+
const lines = tail.split(/\r?\n/).filter((line) => line.trim().length > 0);
|
|
259
|
+
for (const line of lines) {
|
|
260
|
+
const trimmed = line.trim();
|
|
261
|
+
if (!trimmed.startsWith("data:"))
|
|
262
|
+
continue;
|
|
263
|
+
const payload = trimmed.slice(5).trim();
|
|
264
|
+
if (!payload || payload === "[DONE]")
|
|
265
|
+
continue;
|
|
266
|
+
try {
|
|
267
|
+
const chunk = buildChunk(payload);
|
|
268
|
+
if (chunk)
|
|
269
|
+
yield chunk;
|
|
270
|
+
}
|
|
271
|
+
catch {
|
|
272
|
+
// Ignore malformed SSE lines and continue streaming.
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
assertConfig() {
|
|
277
|
+
if (!/^https?:\/\//i.test(this.baseUrl)) {
|
|
278
|
+
throw new Error("OpenAI baseUrl must start with http:// or https://");
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
ensureBaseUrl() {
|
|
282
|
+
return this.baseUrl;
|
|
283
|
+
}
|
|
284
|
+
ensureModel() {
|
|
285
|
+
if (!this.config.model) {
|
|
286
|
+
throw new Error("OpenAI model is not configured for this agent");
|
|
287
|
+
}
|
|
288
|
+
return this.config.model;
|
|
289
|
+
}
|
|
290
|
+
ensureApiKey() {
|
|
291
|
+
if (!this.config.apiKey) {
|
|
292
|
+
throw new Error(`AUTH_REQUIRED: OpenAI API key missing; run \`mcoda agent auth set ${this.config.agent.slug ?? this.config.agent.id}\``);
|
|
293
|
+
}
|
|
294
|
+
return this.config.apiKey;
|
|
295
|
+
}
|
|
296
|
+
buildHeaders(apiKey, streaming) {
|
|
297
|
+
return {
|
|
298
|
+
Authorization: `Bearer ${apiKey}`,
|
|
299
|
+
"Content-Type": "application/json",
|
|
300
|
+
Accept: streaming ? "text/event-stream" : "application/json",
|
|
301
|
+
...(this.headers ?? {}),
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
buildBody(input, model, stream) {
|
|
305
|
+
const body = {
|
|
306
|
+
model,
|
|
307
|
+
messages: [{ role: "user", content: input }],
|
|
308
|
+
stream,
|
|
49
309
|
};
|
|
310
|
+
if (typeof this.temperature === "number") {
|
|
311
|
+
body.temperature = this.temperature;
|
|
312
|
+
}
|
|
313
|
+
if (this.extraBody) {
|
|
314
|
+
for (const [key, value] of Object.entries(this.extraBody)) {
|
|
315
|
+
if (body[key] === undefined)
|
|
316
|
+
body[key] = value;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
if (stream && body.stream_options === undefined) {
|
|
320
|
+
body.stream_options = { include_usage: true };
|
|
321
|
+
}
|
|
322
|
+
return body;
|
|
50
323
|
}
|
|
51
324
|
}
|
|
@@ -4,7 +4,7 @@ type ZhipuConfig = AdapterConfig & {
|
|
|
4
4
|
baseUrl?: string;
|
|
5
5
|
headers?: Record<string, string>;
|
|
6
6
|
temperature?: number;
|
|
7
|
-
thinking?: boolean
|
|
7
|
+
thinking?: boolean | Record<string, unknown>;
|
|
8
8
|
extraBody?: Record<string, unknown>;
|
|
9
9
|
};
|
|
10
10
|
export declare class ZhipuApiAdapter implements AgentAdapter {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ZhipuApiAdapter.d.ts","sourceRoot":"","sources":["../../../src/adapters/zhipu/ZhipuApiAdapter.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":"ZhipuApiAdapter.d.ts","sourceRoot":"","sources":["../../../src/adapters/zhipu/ZhipuApiAdapter.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;AA0DtG,KAAK,WAAW,GAAG,aAAa,GAAG;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC7C,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACrC,CAAC;AAEF,qBAAa,eAAgB,YAAW,YAAY;IAOtC,OAAO,CAAC,MAAM;IAN1B,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,OAAO,CAAqC;IACpD,OAAO,CAAC,WAAW,CAAqB;IACxC,OAAO,CAAC,QAAQ,CAAsC;IACtD,OAAO,CAAC,SAAS,CAAsC;gBAEnC,MAAM,EAAE,WAAW;IASjC,eAAe,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAIpC,WAAW,IAAI,OAAO,CAAC,WAAW,CAAC;IAkBnC,MAAM,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,gBAAgB,CAAC;IA2C5D,YAAY,CAAC,OAAO,EAAE,iBAAiB,GAAG,cAAc,CAAC,gBAAgB,EAAE,IAAI,EAAE,OAAO,CAAC;IA2FhG,OAAO,CAAC,YAAY;IAMpB,OAAO,CAAC,aAAa;IAIrB,OAAO,CAAC,WAAW;IAOnB,OAAO,CAAC,YAAY;IAOpB,OAAO,CAAC,YAAY;IASpB,OAAO,CAAC,SAAS;CAgBlB"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const DEFAULT_BASE_URL = "https://open.bigmodel.cn/api/paas/v4";
|
|
2
|
+
const DEFAULT_CODING_BASE_URL = "https://open.bigmodel.cn/api/coding/paas/v4";
|
|
2
3
|
const DEFAULT_TEMPERATURE = 0.1;
|
|
3
4
|
const normalizeBaseUrl = (value) => {
|
|
4
5
|
if (!value)
|
|
@@ -9,6 +10,20 @@ const normalizeBaseUrl = (value) => {
|
|
|
9
10
|
return str.endsWith("/") ? str.slice(0, -1) : str;
|
|
10
11
|
};
|
|
11
12
|
const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
13
|
+
const usesCodingBaseUrl = (model) => {
|
|
14
|
+
if (!model)
|
|
15
|
+
return false;
|
|
16
|
+
const normalized = model.trim().toLowerCase();
|
|
17
|
+
return normalized === "glm-4.7" || normalized.startsWith("glm-4.7-");
|
|
18
|
+
};
|
|
19
|
+
const defaultBaseUrlForModel = (model) => usesCodingBaseUrl(model) ? DEFAULT_CODING_BASE_URL : DEFAULT_BASE_URL;
|
|
20
|
+
const normalizeThinking = (value) => {
|
|
21
|
+
if (value === true)
|
|
22
|
+
return { type: "enabled" };
|
|
23
|
+
if (value === false)
|
|
24
|
+
return { type: "disabled" };
|
|
25
|
+
return isRecord(value) && Object.keys(value).length > 0 ? value : undefined;
|
|
26
|
+
};
|
|
12
27
|
const extractUsage = (usage) => {
|
|
13
28
|
if (!usage || typeof usage !== "object")
|
|
14
29
|
return undefined;
|
|
@@ -37,10 +52,10 @@ const extractUsage = (usage) => {
|
|
|
37
52
|
export class ZhipuApiAdapter {
|
|
38
53
|
constructor(config) {
|
|
39
54
|
this.config = config;
|
|
40
|
-
this.baseUrl = normalizeBaseUrl(config.baseUrl) ??
|
|
55
|
+
this.baseUrl = normalizeBaseUrl(config.baseUrl) ?? defaultBaseUrlForModel(config.model);
|
|
41
56
|
this.headers = isRecord(config.headers) ? config.headers : undefined;
|
|
42
57
|
this.temperature = typeof config.temperature === "number" ? config.temperature : undefined;
|
|
43
|
-
this.thinking =
|
|
58
|
+
this.thinking = normalizeThinking(config.thinking);
|
|
44
59
|
this.extraBody = isRecord(config.extraBody) ? config.extraBody : undefined;
|
|
45
60
|
this.assertConfig();
|
|
46
61
|
}
|
|
@@ -242,7 +257,7 @@ export class ZhipuApiAdapter {
|
|
|
242
257
|
const temperature = this.temperature ?? DEFAULT_TEMPERATURE;
|
|
243
258
|
if (typeof temperature === "number")
|
|
244
259
|
body.temperature = temperature;
|
|
245
|
-
if (
|
|
260
|
+
if (this.thinking)
|
|
246
261
|
body.thinking = this.thinking;
|
|
247
262
|
if (this.extraBody) {
|
|
248
263
|
for (const [key, value] of Object.entries(this.extraBody)) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mcoda/agents",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.38",
|
|
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.38",
|
|
34
|
+
"@mcoda/db": "0.1.38"
|
|
35
35
|
},
|
|
36
36
|
"scripts": {
|
|
37
37
|
"build": "tsc -p tsconfig.json",
|