@archships/dim-agent-sdk 0.0.3 → 0.0.5
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/README.md +27 -5
- package/dist/dim-agent-sdk/src/agent-core/agent-types.d.ts +3 -2
- package/dist/dim-agent-sdk/src/agent-core/{Agent.d.ts → agent.d.ts} +2 -2
- package/dist/dim-agent-sdk/src/agent-core/index.d.ts +10 -10
- package/dist/dim-agent-sdk/src/agent-core/{LoopRunner.d.ts → loop-runner.d.ts} +6 -5
- package/dist/dim-agent-sdk/src/agent-core/notifications.d.ts +1 -1
- package/dist/dim-agent-sdk/src/agent-core/session-state.d.ts +3 -2
- package/dist/dim-agent-sdk/src/agent-core/{Session.d.ts → session.d.ts} +48 -9
- package/dist/dim-agent-sdk/src/agent-core/{ToolExecutor.d.ts → tool-executor.d.ts} +2 -2
- package/dist/dim-agent-sdk/src/context/{AutoContextManager.d.ts → auto-context-manager.d.ts} +1 -1
- package/dist/dim-agent-sdk/src/context/index.d.ts +2 -2
- package/dist/dim-agent-sdk/src/contracts/event.d.ts +13 -7
- package/dist/dim-agent-sdk/src/contracts/state.d.ts +32 -1
- package/dist/dim-agent-sdk/src/index.d.ts +7 -6
- package/dist/dim-agent-sdk/src/persistence/index.d.ts +5 -5
- package/dist/dim-agent-sdk/src/persistence/{SnapshotCodec.d.ts → snapshot-codec.d.ts} +2 -1
- package/dist/dim-agent-sdk/src/plugin-host/index.d.ts +2 -2
- package/dist/dim-agent-sdk/src/plugin-host/{PluginHost.d.ts → plugin-host.d.ts} +4 -4
- package/dist/dim-agent-sdk/src/providers/aihubmix/adapter.d.ts +17 -0
- package/dist/dim-agent-sdk/src/providers/aihubmix/driver.d.ts +3 -0
- package/dist/dim-agent-sdk/src/providers/aihubmix/index.d.ts +2 -0
- package/dist/dim-agent-sdk/src/providers/aihubmix-responses/adapter.d.ts +17 -0
- package/dist/dim-agent-sdk/src/providers/aihubmix-responses/driver.d.ts +12 -0
- package/dist/dim-agent-sdk/src/providers/aihubmix-responses/index.d.ts +2 -0
- package/dist/dim-agent-sdk/src/providers/aihubmix-responses/state.d.ts +7 -0
- package/dist/dim-agent-sdk/src/providers/anthropic/adapter.d.ts +15 -4
- package/dist/dim-agent-sdk/src/providers/anthropic/driver.d.ts +3 -0
- package/dist/dim-agent-sdk/src/providers/anthropic/index.d.ts +2 -0
- package/dist/dim-agent-sdk/src/providers/anthropic/state.d.ts +6 -0
- package/dist/dim-agent-sdk/src/providers/core/create-provider-factory.d.ts +39 -0
- package/dist/dim-agent-sdk/src/providers/core/index.d.ts +2 -0
- package/dist/dim-agent-sdk/src/providers/deepseek/adapter.d.ts +11 -0
- package/dist/dim-agent-sdk/src/providers/deepseek/driver.d.ts +3 -0
- package/dist/dim-agent-sdk/src/providers/deepseek/index.d.ts +2 -0
- package/dist/dim-agent-sdk/src/providers/gemini/adapter.d.ts +3 -4
- package/dist/dim-agent-sdk/src/providers/gemini/driver.d.ts +3 -0
- package/dist/dim-agent-sdk/src/providers/gemini/index.d.ts +2 -0
- package/dist/dim-agent-sdk/src/providers/gemini/state.d.ts +5 -0
- package/dist/dim-agent-sdk/src/providers/index.d.ts +22 -8
- package/dist/dim-agent-sdk/src/providers/moonshotai/adapter.d.ts +11 -0
- package/dist/dim-agent-sdk/src/providers/moonshotai/driver.d.ts +3 -0
- package/dist/dim-agent-sdk/src/providers/moonshotai/index.d.ts +2 -0
- package/dist/dim-agent-sdk/src/providers/openai/adapter.d.ts +3 -4
- package/dist/dim-agent-sdk/src/providers/openai/driver.d.ts +3 -0
- package/dist/dim-agent-sdk/src/providers/openai/index.d.ts +2 -0
- package/dist/dim-agent-sdk/src/providers/openai-responses/adapter.d.ts +3 -4
- package/dist/dim-agent-sdk/src/providers/openai-responses/driver.d.ts +3 -0
- package/dist/dim-agent-sdk/src/providers/openai-responses/index.d.ts +2 -0
- package/dist/dim-agent-sdk/src/providers/openai-responses/state.d.ts +7 -0
- package/dist/dim-agent-sdk/src/providers/shared/ai-sdk-driver.d.ts +7 -0
- package/dist/dim-agent-sdk/src/providers/shared/auth-warning.d.ts +6 -0
- package/dist/dim-agent-sdk/src/providers/shared/fetch.d.ts +8 -0
- package/dist/dim-agent-sdk/src/providers/shared/http-error.d.ts +10 -0
- package/dist/dim-agent-sdk/src/providers/shared/prompt.d.ts +14 -0
- package/dist/dim-agent-sdk/src/providers/shared/reasoning.d.ts +30 -7
- package/dist/dim-agent-sdk/src/providers/shared/responses-state.d.ts +11 -0
- package/dist/dim-agent-sdk/src/providers/shared/usage.d.ts +4 -2
- package/dist/dim-agent-sdk/src/providers/xai/adapter.d.ts +11 -0
- package/dist/dim-agent-sdk/src/providers/xai/driver.d.ts +3 -0
- package/dist/dim-agent-sdk/src/providers/xai/index.d.ts +2 -0
- package/dist/dim-agent-sdk/src/providers/xai-responses/adapter.d.ts +11 -0
- package/dist/dim-agent-sdk/src/providers/xai-responses/driver.d.ts +3 -0
- package/dist/dim-agent-sdk/src/providers/xai-responses/index.d.ts +2 -0
- package/dist/dim-agent-sdk/src/providers/xai-responses/state.d.ts +7 -0
- package/dist/dim-agent-sdk/src/providers/zenmux/adapter.d.ts +13 -0
- package/dist/dim-agent-sdk/src/providers/zenmux/driver.d.ts +3 -0
- package/dist/dim-agent-sdk/src/providers/zenmux/index.d.ts +2 -0
- package/dist/dim-agent-sdk/src/services/index.d.ts +6 -6
- package/dist/dim-agent-sdk/src/tools/builtins/{EditTool.d.ts → edit-tool.d.ts} +1 -1
- package/dist/dim-agent-sdk/src/tools/builtins/{ExecTool.d.ts → exec-tool.d.ts} +1 -1
- package/dist/dim-agent-sdk/src/tools/builtins/index.d.ts +4 -4
- package/dist/dim-agent-sdk/src/tools/builtins/{ReadTool.d.ts → read-tool.d.ts} +1 -1
- package/dist/dim-agent-sdk/src/tools/builtins/{WriteTool.d.ts → write-tool.d.ts} +1 -1
- package/dist/dim-agent-sdk/src/tools/index.d.ts +2 -2
- package/dist/dim-plugin-api/src/index.d.ts +18 -1
- package/dist/{index.js → src/index.js} +4422 -3627
- package/dist/src/providers/aihubmix/index.js +636 -0
- package/dist/src/providers/aihubmix-responses/index.js +759 -0
- package/dist/src/providers/anthropic/index.js +743 -0
- package/dist/src/providers/core/index.js +92 -0
- package/dist/src/providers/deepseek/index.js +639 -0
- package/dist/src/providers/gemini/index.js +756 -0
- package/dist/src/providers/moonshotai/index.js +639 -0
- package/dist/src/providers/openai/index.js +499 -0
- package/dist/src/providers/openai-responses/index.js +727 -0
- package/dist/src/providers/xai/index.js +639 -0
- package/dist/src/providers/xai-responses/index.js +728 -0
- package/dist/src/providers/zenmux/index.js +642 -0
- package/package.json +74 -5
- package/dist/dim-agent-sdk/src/providers/anthropic/mapper.d.ts +0 -28
- package/dist/dim-agent-sdk/src/providers/gemini/mapper.d.ts +0 -30
- package/dist/dim-agent-sdk/src/providers/openai/mapper.d.ts +0 -15
- package/dist/dim-agent-sdk/src/providers/openai-responses/mapper.d.ts +0 -40
- /package/dist/dim-agent-sdk/src/agent-core/{createModel.d.ts → create-model.d.ts} +0 -0
- /package/dist/dim-agent-sdk/src/agent-core/{MessageFactory.d.ts → message-factory.d.ts} +0 -0
- /package/dist/dim-agent-sdk/src/agent-core/{ModelTurnCollector.d.ts → model-turn-collector.d.ts} +0 -0
- /package/dist/dim-agent-sdk/src/agent-core/{TerminationPolicy.d.ts → termination-policy.d.ts} +0 -0
- /package/dist/dim-agent-sdk/src/persistence/{FileStateStore.d.ts → file-state-store.d.ts} +0 -0
- /package/dist/dim-agent-sdk/src/persistence/{InMemoryStateStore.d.ts → in-memory-state-store.d.ts} +0 -0
- /package/dist/dim-agent-sdk/src/plugin-host/{HookPipeline.d.ts → hook-pipeline.d.ts} +0 -0
- /package/dist/dim-agent-sdk/src/services/{ExecGateway.d.ts → exec-gateway.d.ts} +0 -0
- /package/dist/dim-agent-sdk/src/services/{FileSystemGateway.d.ts → file-system-gateway.d.ts} +0 -0
- /package/dist/dim-agent-sdk/src/services/{GitGateway.d.ts → git-gateway.d.ts} +0 -0
- /package/dist/dim-agent-sdk/src/services/{ModelGateway.d.ts → model-gateway.d.ts} +0 -0
- /package/dist/dim-agent-sdk/src/services/{NetworkGateway.d.ts → network-gateway.d.ts} +0 -0
- /package/dist/dim-agent-sdk/src/services/{PermissionGateway.d.ts → permission-gateway.d.ts} +0 -0
- /package/dist/dim-agent-sdk/src/tools/{BaseTool.d.ts → base-tool.d.ts} +0 -0
- /package/dist/dim-agent-sdk/src/tools/{ToolRegistry.d.ts → tool-registry.d.ts} +0 -0
|
@@ -0,0 +1,499 @@
|
|
|
1
|
+
// src/providers/core/create-provider-factory.ts
|
|
2
|
+
function createProviderFactory(definition) {
|
|
3
|
+
return function createConfiguredAdapter(options) {
|
|
4
|
+
const provider = options.provider ?? definition.defaultProvider;
|
|
5
|
+
const defaultModel = {
|
|
6
|
+
provider,
|
|
7
|
+
modelId: options.defaultModel
|
|
8
|
+
};
|
|
9
|
+
return {
|
|
10
|
+
provider,
|
|
11
|
+
defaultModel,
|
|
12
|
+
async* stream(request) {
|
|
13
|
+
const requestId = request.requestId ?? crypto.randomUUID();
|
|
14
|
+
const model = request.model ?? defaultModel;
|
|
15
|
+
yield { type: "response_start", requestId, model };
|
|
16
|
+
const context = {
|
|
17
|
+
options,
|
|
18
|
+
provider,
|
|
19
|
+
defaultModel,
|
|
20
|
+
request: {
|
|
21
|
+
...request,
|
|
22
|
+
model
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
let result;
|
|
26
|
+
try {
|
|
27
|
+
result = await definition.driver.generate(context);
|
|
28
|
+
} catch (error) {
|
|
29
|
+
const payload = definition.driver.normalizeError ? await definition.driver.normalizeError(error, context) : createFallbackErrorPayload(provider, error);
|
|
30
|
+
yield {
|
|
31
|
+
type: "error",
|
|
32
|
+
requestId,
|
|
33
|
+
error: payload,
|
|
34
|
+
terminal: true
|
|
35
|
+
};
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
for (const segment of result.content) {
|
|
39
|
+
if (segment.type === "text") {
|
|
40
|
+
if (segment.text.length > 0)
|
|
41
|
+
yield { type: "text_delta", requestId, delta: segment.text };
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
if (segment.type === "thinking") {
|
|
45
|
+
if (segment.text.length > 0)
|
|
46
|
+
yield { type: "thinking_delta", requestId, delta: segment.text };
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
yield {
|
|
50
|
+
type: "tool_call_start",
|
|
51
|
+
requestId,
|
|
52
|
+
callId: segment.callId,
|
|
53
|
+
toolName: segment.toolName
|
|
54
|
+
};
|
|
55
|
+
yield {
|
|
56
|
+
type: "tool_call_args_delta",
|
|
57
|
+
requestId,
|
|
58
|
+
callId: segment.callId,
|
|
59
|
+
delta: segment.argsText
|
|
60
|
+
};
|
|
61
|
+
yield {
|
|
62
|
+
type: "tool_call_end",
|
|
63
|
+
requestId,
|
|
64
|
+
callId: segment.callId
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
yield {
|
|
68
|
+
type: "response_end",
|
|
69
|
+
requestId,
|
|
70
|
+
stopReason: result.stopReason,
|
|
71
|
+
usage: result.usage,
|
|
72
|
+
assistantMetadata: result.assistantMetadata
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
function createFallbackErrorPayload(provider, error) {
|
|
79
|
+
if (error instanceof Error) {
|
|
80
|
+
return {
|
|
81
|
+
code: `${provider}_request_error`,
|
|
82
|
+
message: error.message
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
return {
|
|
86
|
+
code: `${provider}_request_error`,
|
|
87
|
+
message: String(error)
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// src/providers/openai/driver.ts
|
|
92
|
+
import { APICallError } from "@ai-sdk/provider";
|
|
93
|
+
import { createOpenAI } from "@ai-sdk/openai";
|
|
94
|
+
|
|
95
|
+
// src/providers/shared/usage.ts
|
|
96
|
+
function normalizeLanguageModelUsage(raw) {
|
|
97
|
+
if (!raw)
|
|
98
|
+
return;
|
|
99
|
+
const promptTokens = raw.inputTokens.total ?? 0;
|
|
100
|
+
const completionTokens = raw.outputTokens.total ?? 0;
|
|
101
|
+
const totalTokens = promptTokens + completionTokens;
|
|
102
|
+
if (promptTokens === 0 && completionTokens === 0 && totalTokens === 0)
|
|
103
|
+
return;
|
|
104
|
+
return {
|
|
105
|
+
promptTokens,
|
|
106
|
+
completionTokens,
|
|
107
|
+
totalTokens
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
function mapLanguageModelFinishReason(reason) {
|
|
111
|
+
const raw = reason.raw?.toLowerCase();
|
|
112
|
+
if (raw === "cancelled" || raw === "canceled")
|
|
113
|
+
return "cancelled";
|
|
114
|
+
switch (reason.unified) {
|
|
115
|
+
case "tool-calls":
|
|
116
|
+
return "tool_call";
|
|
117
|
+
case "length":
|
|
118
|
+
return "length";
|
|
119
|
+
case "content-filter":
|
|
120
|
+
case "error":
|
|
121
|
+
return "error";
|
|
122
|
+
case "other":
|
|
123
|
+
return raw === "cancelled" || raw === "canceled" ? "cancelled" : "final";
|
|
124
|
+
case "stop":
|
|
125
|
+
default:
|
|
126
|
+
return "final";
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// src/providers/shared/ai-sdk-driver.ts
|
|
131
|
+
async function generateWithAiSdk(input) {
|
|
132
|
+
const result = await input.model.doGenerate(input.callOptions);
|
|
133
|
+
const content = [];
|
|
134
|
+
for (const part of result.content) {
|
|
135
|
+
if (part.type === "text") {
|
|
136
|
+
if (part.text.length > 0)
|
|
137
|
+
content.push({ type: "text", text: part.text });
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
if (part.type === "reasoning") {
|
|
141
|
+
if (part.text.length > 0)
|
|
142
|
+
content.push({ type: "thinking", text: part.text });
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
if (part.type === "tool-call") {
|
|
146
|
+
content.push({
|
|
147
|
+
type: "tool_call",
|
|
148
|
+
callId: part.toolCallId,
|
|
149
|
+
toolName: part.toolName,
|
|
150
|
+
argsText: part.input
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return {
|
|
155
|
+
content,
|
|
156
|
+
stopReason: mapLanguageModelFinishReason(result.finishReason),
|
|
157
|
+
usage: normalizeLanguageModelUsage(result.usage),
|
|
158
|
+
assistantMetadata: input.createAssistantMetadata?.(result)
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// src/providers/shared/auth-warning.ts
|
|
163
|
+
var warnedProviders = new Set;
|
|
164
|
+
function warnIfPlaceholderApiKey(input) {
|
|
165
|
+
if (!input.shouldWarn)
|
|
166
|
+
return;
|
|
167
|
+
if (false)
|
|
168
|
+
;
|
|
169
|
+
if (warnedProviders.has(input.provider))
|
|
170
|
+
return;
|
|
171
|
+
warnedProviders.add(input.provider);
|
|
172
|
+
const suffix = input.hint ? ` ${input.hint}` : "";
|
|
173
|
+
console.warn(`[dim-agent-sdk] ${input.provider} is using a placeholder API key because no apiKey or provider-native auth configuration was provided. ` + `If you rely on external authentication, ensure your custom fetch or provider-native headers add real credentials before the request is sent upstream.${suffix}`);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// src/providers/shared/http-error.ts
|
|
177
|
+
import { STATUS_CODES } from "node:http";
|
|
178
|
+
var MAX_TEXT_CHARS = 4000;
|
|
179
|
+
var MAX_JSON_DEPTH = 4;
|
|
180
|
+
var MAX_JSON_ARRAY_ITEMS = 20;
|
|
181
|
+
var MAX_JSON_OBJECT_KEYS = 40;
|
|
182
|
+
var TRUNCATED_SUFFIX = "...[truncated]";
|
|
183
|
+
function createApiCallErrorPayload(input) {
|
|
184
|
+
const responseBody = input.error.responseBody ? parseErrorBody(input.error.responseBody) : limitJsonValue(input.error.data);
|
|
185
|
+
return {
|
|
186
|
+
code: input.code,
|
|
187
|
+
message: `${input.provider} request failed${input.error.statusCode ? ` with status ${input.error.statusCode}` : ""}`,
|
|
188
|
+
status: input.error.statusCode,
|
|
189
|
+
retryable: input.error.isRetryable,
|
|
190
|
+
details: {
|
|
191
|
+
provider: input.provider,
|
|
192
|
+
endpoint: input.error.url,
|
|
193
|
+
...input.error.statusCode ? { statusText: STATUS_CODES[input.error.statusCode] ?? undefined } : {},
|
|
194
|
+
...responseBody === undefined ? {} : { responseBody }
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
function createRequestErrorPayload(input) {
|
|
199
|
+
if (input.error instanceof Error) {
|
|
200
|
+
return {
|
|
201
|
+
code: input.code,
|
|
202
|
+
message: input.error.message
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
return {
|
|
206
|
+
code: input.code,
|
|
207
|
+
message: String(input.error)
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
function parseErrorBody(value) {
|
|
211
|
+
const normalized = value.trim();
|
|
212
|
+
if (!normalized)
|
|
213
|
+
return;
|
|
214
|
+
try {
|
|
215
|
+
return limitJsonValue(JSON.parse(normalized));
|
|
216
|
+
} catch {
|
|
217
|
+
return truncateText(normalized);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
function limitJsonValue(value, depth = 0) {
|
|
221
|
+
if (value === undefined)
|
|
222
|
+
return;
|
|
223
|
+
if (value === null || typeof value === "boolean" || typeof value === "number")
|
|
224
|
+
return value;
|
|
225
|
+
if (typeof value === "string")
|
|
226
|
+
return truncateText(value);
|
|
227
|
+
if (Array.isArray(value))
|
|
228
|
+
return value.slice(0, MAX_JSON_ARRAY_ITEMS).map((item) => limitJsonValue(item, depth + 1));
|
|
229
|
+
if (typeof value === "object") {
|
|
230
|
+
if (depth >= MAX_JSON_DEPTH)
|
|
231
|
+
return truncateText(JSON.stringify(value));
|
|
232
|
+
const limited = {};
|
|
233
|
+
for (const [key, child] of Object.entries(value).slice(0, MAX_JSON_OBJECT_KEYS))
|
|
234
|
+
limited[key] = limitJsonValue(child, depth + 1);
|
|
235
|
+
return limited;
|
|
236
|
+
}
|
|
237
|
+
return truncateText(String(value));
|
|
238
|
+
}
|
|
239
|
+
function truncateText(value) {
|
|
240
|
+
if (value.length <= MAX_TEXT_CHARS)
|
|
241
|
+
return value;
|
|
242
|
+
return `${value.slice(0, MAX_TEXT_CHARS)}${TRUNCATED_SUFFIX}`;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// src/providers/shared/fetch.ts
|
|
246
|
+
function createProviderFetch(input) {
|
|
247
|
+
const fetchImpl = input.fetch ?? globalThis.fetch;
|
|
248
|
+
if (!input.stripWhen || !input.stripHeaders || input.stripHeaders.length === 0)
|
|
249
|
+
return fetchImpl;
|
|
250
|
+
const headersToStrip = new Set(input.stripHeaders.map((header) => header.toLowerCase()));
|
|
251
|
+
const wrappedFetch = Object.assign((resource, init) => {
|
|
252
|
+
if (typeof resource === "string" || resource instanceof URL) {
|
|
253
|
+
const headers = new Headers(init?.headers);
|
|
254
|
+
for (const header of headersToStrip)
|
|
255
|
+
headers.delete(header);
|
|
256
|
+
return fetchImpl(resource, { ...init, headers });
|
|
257
|
+
}
|
|
258
|
+
const request = new Request(resource, init);
|
|
259
|
+
for (const header of headersToStrip)
|
|
260
|
+
request.headers.delete(header);
|
|
261
|
+
return fetchImpl(request);
|
|
262
|
+
}, {
|
|
263
|
+
preconnect: typeof fetchImpl.preconnect === "function" ? fetchImpl.preconnect.bind(fetchImpl) : (_url, _options) => {}
|
|
264
|
+
});
|
|
265
|
+
return wrappedFetch;
|
|
266
|
+
}
|
|
267
|
+
function hasHeader(headers, target) {
|
|
268
|
+
if (!headers)
|
|
269
|
+
return false;
|
|
270
|
+
const normalized = target.toLowerCase();
|
|
271
|
+
return Object.keys(headers).some((key) => key.toLowerCase() === normalized);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// src/utils/guards.ts
|
|
275
|
+
function isRecord(value) {
|
|
276
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
277
|
+
}
|
|
278
|
+
function isStringArray(value) {
|
|
279
|
+
return Array.isArray(value) && value.every((item) => typeof item === "string");
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// src/contracts/content-normalize.ts
|
|
283
|
+
function isTextContent(value) {
|
|
284
|
+
return isRecord(value) && value.type === "text" && typeof value.text === "string" && (value.annotations === undefined || isRecord(value.annotations)) && (value._meta === undefined || isRecord(value._meta));
|
|
285
|
+
}
|
|
286
|
+
function isImageContent(value) {
|
|
287
|
+
return isRecord(value) && value.type === "image" && typeof value.data === "string" && typeof value.mimeType === "string" && (value.annotations === undefined || isRecord(value.annotations)) && (value._meta === undefined || isRecord(value._meta));
|
|
288
|
+
}
|
|
289
|
+
function isContentBlock(value) {
|
|
290
|
+
return isTextContent(value) || isImageContent(value);
|
|
291
|
+
}
|
|
292
|
+
function normalizeContent(input) {
|
|
293
|
+
if (typeof input === "string") {
|
|
294
|
+
return [{ type: "text", text: input }];
|
|
295
|
+
}
|
|
296
|
+
if (Array.isArray(input)) {
|
|
297
|
+
const blocks = input.filter((item) => item != null);
|
|
298
|
+
if (!blocks.every(isContentBlock))
|
|
299
|
+
throw new TypeError("Content array must contain only text or image blocks");
|
|
300
|
+
return blocks.map((block) => ({ ...block }));
|
|
301
|
+
}
|
|
302
|
+
if (!isContentBlock(input))
|
|
303
|
+
throw new TypeError("Content must be a string, content block, or content block array");
|
|
304
|
+
return [{ ...input }];
|
|
305
|
+
}
|
|
306
|
+
function contentToText(content) {
|
|
307
|
+
return content.filter((block) => block.type === "text").map((block) => block.text).join("");
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// src/utils/json.ts
|
|
311
|
+
function isJsonSafeValue(value) {
|
|
312
|
+
if (value === null)
|
|
313
|
+
return true;
|
|
314
|
+
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean")
|
|
315
|
+
return true;
|
|
316
|
+
if (Array.isArray(value))
|
|
317
|
+
return value.every(isJsonSafeValue);
|
|
318
|
+
if (isRecord(value))
|
|
319
|
+
return Object.values(value).every(isJsonSafeValue);
|
|
320
|
+
return false;
|
|
321
|
+
}
|
|
322
|
+
function assertJsonSafeObject(value, label) {
|
|
323
|
+
if (!isRecord(value) || !isJsonSafeValue(value))
|
|
324
|
+
throw new TypeError(`${label} must be a JSON-safe object`);
|
|
325
|
+
}
|
|
326
|
+
function parseJsonObject(value, label) {
|
|
327
|
+
let parsed;
|
|
328
|
+
try {
|
|
329
|
+
parsed = JSON.parse(value);
|
|
330
|
+
} catch (error) {
|
|
331
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
332
|
+
throw new Error(`${label} must be valid JSON: ${message}`);
|
|
333
|
+
}
|
|
334
|
+
if (!isRecord(parsed))
|
|
335
|
+
throw new Error(`${label} must decode to a JSON object`);
|
|
336
|
+
return parsed;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
// src/providers/shared/prompt.ts
|
|
340
|
+
function mapToolDefinitionsToLanguageModelTools(tools) {
|
|
341
|
+
if (!tools || tools.length === 0)
|
|
342
|
+
return;
|
|
343
|
+
return tools.map((tool) => ({
|
|
344
|
+
type: "function",
|
|
345
|
+
name: tool.name,
|
|
346
|
+
description: tool.description,
|
|
347
|
+
inputSchema: tool.inputSchema
|
|
348
|
+
}));
|
|
349
|
+
}
|
|
350
|
+
function messagesToLanguageModelPrompt(messages, options = {}) {
|
|
351
|
+
const prompt = [];
|
|
352
|
+
const systemContent = messages.filter((message) => message.role === "system").map((message) => contentToText(message.content)).filter(Boolean).join(`
|
|
353
|
+
|
|
354
|
+
`);
|
|
355
|
+
if (systemContent)
|
|
356
|
+
prompt.push({ role: "system", content: systemContent });
|
|
357
|
+
for (const message of messages) {
|
|
358
|
+
if (message.role === "system")
|
|
359
|
+
continue;
|
|
360
|
+
if (message.role === "tool") {
|
|
361
|
+
prompt.push(toolMessageToPrompt(message));
|
|
362
|
+
continue;
|
|
363
|
+
}
|
|
364
|
+
if (message.role === "assistant") {
|
|
365
|
+
const content = [
|
|
366
|
+
...options.assistantPrefixParts?.(message) ?? [],
|
|
367
|
+
...contentBlocksToPromptParts(message.content),
|
|
368
|
+
...toolCallsToPromptParts(message.toolCalls)
|
|
369
|
+
];
|
|
370
|
+
if (content.length > 0)
|
|
371
|
+
prompt.push({ role: "assistant", content });
|
|
372
|
+
continue;
|
|
373
|
+
}
|
|
374
|
+
prompt.push({
|
|
375
|
+
role: "user",
|
|
376
|
+
content: contentBlocksToPromptParts(message.content)
|
|
377
|
+
});
|
|
378
|
+
}
|
|
379
|
+
return prompt;
|
|
380
|
+
}
|
|
381
|
+
function contentBlocksToPromptParts(content) {
|
|
382
|
+
return content.map((block) => {
|
|
383
|
+
if (block.type === "text")
|
|
384
|
+
return { type: "text", text: block.text };
|
|
385
|
+
return {
|
|
386
|
+
type: "file",
|
|
387
|
+
data: block.data,
|
|
388
|
+
mediaType: block.mimeType
|
|
389
|
+
};
|
|
390
|
+
});
|
|
391
|
+
}
|
|
392
|
+
function toolCallsToPromptParts(toolCalls) {
|
|
393
|
+
if (!toolCalls || toolCalls.length === 0)
|
|
394
|
+
return [];
|
|
395
|
+
return toolCalls.map((toolCall) => ({
|
|
396
|
+
type: "tool-call",
|
|
397
|
+
toolCallId: toolCall.id,
|
|
398
|
+
toolName: toolCall.function.name,
|
|
399
|
+
input: toolCall.function.arguments
|
|
400
|
+
}));
|
|
401
|
+
}
|
|
402
|
+
function toolMessageToPrompt(message) {
|
|
403
|
+
return {
|
|
404
|
+
role: "tool",
|
|
405
|
+
content: [{
|
|
406
|
+
type: "tool-result",
|
|
407
|
+
toolCallId: message.toolCallId,
|
|
408
|
+
toolName: message.toolName,
|
|
409
|
+
output: toolMessageToOutput(message)
|
|
410
|
+
}]
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
function toolMessageToOutput(message) {
|
|
414
|
+
if (message.structuredContent) {
|
|
415
|
+
assertJsonSafeObject(message.structuredContent, "Tool structuredContent");
|
|
416
|
+
return {
|
|
417
|
+
type: "json",
|
|
418
|
+
value: message.structuredContent
|
|
419
|
+
};
|
|
420
|
+
}
|
|
421
|
+
const text = contentToText(message.content);
|
|
422
|
+
if (message.isError === true) {
|
|
423
|
+
return {
|
|
424
|
+
type: "json",
|
|
425
|
+
value: {
|
|
426
|
+
content: text,
|
|
427
|
+
isError: true
|
|
428
|
+
}
|
|
429
|
+
};
|
|
430
|
+
}
|
|
431
|
+
return {
|
|
432
|
+
type: "text",
|
|
433
|
+
value: text
|
|
434
|
+
};
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
// src/providers/openai/driver.ts
|
|
438
|
+
var DEFAULT_BASE_URL = "https://api.openai.com/v1";
|
|
439
|
+
var PLACEHOLDER_API_KEY = "dim-placeholder-key";
|
|
440
|
+
var openAIDriver = {
|
|
441
|
+
async generate(context) {
|
|
442
|
+
const model = createProvider(context.options).chat(context.request.model.modelId);
|
|
443
|
+
const callOptions = {
|
|
444
|
+
prompt: messagesToLanguageModelPrompt(context.request.messages),
|
|
445
|
+
tools: mapToolDefinitionsToLanguageModelTools(context.request.tools),
|
|
446
|
+
maxOutputTokens: context.request.maxOutputTokens,
|
|
447
|
+
temperature: context.request.temperature,
|
|
448
|
+
topP: context.request.topP,
|
|
449
|
+
stopSequences: context.request.stop,
|
|
450
|
+
abortSignal: context.request.signal
|
|
451
|
+
};
|
|
452
|
+
return generateWithAiSdk({
|
|
453
|
+
model,
|
|
454
|
+
callOptions
|
|
455
|
+
});
|
|
456
|
+
},
|
|
457
|
+
normalizeError(error) {
|
|
458
|
+
if (APICallError.isInstance(error)) {
|
|
459
|
+
return createApiCallErrorPayload({
|
|
460
|
+
code: "openai_http_error",
|
|
461
|
+
provider: "OpenAI-compatible",
|
|
462
|
+
error
|
|
463
|
+
});
|
|
464
|
+
}
|
|
465
|
+
return createRequestErrorPayload({
|
|
466
|
+
code: "openai_request_error",
|
|
467
|
+
error
|
|
468
|
+
});
|
|
469
|
+
}
|
|
470
|
+
};
|
|
471
|
+
function createProvider(options) {
|
|
472
|
+
const stripAuthorization = !options.apiKey && !hasHeader(options.headers, "authorization");
|
|
473
|
+
warnIfPlaceholderApiKey({
|
|
474
|
+
provider: "OpenAI-compatible",
|
|
475
|
+
shouldWarn: stripAuthorization
|
|
476
|
+
});
|
|
477
|
+
return createOpenAI({
|
|
478
|
+
apiKey: options.apiKey ?? PLACEHOLDER_API_KEY,
|
|
479
|
+
baseURL: normalizeBaseUrl(options.baseUrl),
|
|
480
|
+
headers: options.headers,
|
|
481
|
+
fetch: createProviderFetch({
|
|
482
|
+
fetch: options.fetch,
|
|
483
|
+
stripHeaders: ["authorization"],
|
|
484
|
+
stripWhen: stripAuthorization
|
|
485
|
+
})
|
|
486
|
+
});
|
|
487
|
+
}
|
|
488
|
+
function normalizeBaseUrl(baseUrl) {
|
|
489
|
+
return (baseUrl ?? DEFAULT_BASE_URL).replace(/\/$/, "");
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
// src/providers/openai/adapter.ts
|
|
493
|
+
var createOpenAIAdapter = createProviderFactory({
|
|
494
|
+
defaultProvider: "openai-compatible",
|
|
495
|
+
driver: openAIDriver
|
|
496
|
+
});
|
|
497
|
+
export {
|
|
498
|
+
createOpenAIAdapter
|
|
499
|
+
};
|