@gea-ai/agent-sdk 0.1.260916-alpha.2 → 0.1.260917-alpha.0
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/agent-channel-author-runtime.d.ts +13 -13
- package/dist/agent-core.wasm +0 -0
- package/dist/agent-worker.d.ts +2 -1
- package/dist/agent-worker.js +57 -66
- package/dist/catalog-language-model.d.ts +17 -0
- package/dist/catalog-language-model.js +231 -0
- package/dist/openai-compatible-cache-control.d.ts +1 -0
- package/dist/openai-compatible-cache-control.js +71 -0
- package/package.json +6 -2
|
@@ -19,19 +19,6 @@ export declare function executeChannelBehavior(input: {
|
|
|
19
19
|
environment: AgentChannelFetchEnvironment;
|
|
20
20
|
signal: AbortSignal;
|
|
21
21
|
}): Promise<{
|
|
22
|
-
sequence: number;
|
|
23
|
-
duplicate: boolean;
|
|
24
|
-
} | {
|
|
25
|
-
state: AgentChannelJson;
|
|
26
|
-
intents: {
|
|
27
|
-
key: string;
|
|
28
|
-
payload: AgentChannelJson;
|
|
29
|
-
eventId: string;
|
|
30
|
-
operationId: string;
|
|
31
|
-
}[];
|
|
32
|
-
cursor: number;
|
|
33
|
-
idempotencyWindowMs?: number | undefined;
|
|
34
|
-
} | {
|
|
35
22
|
status: "sent";
|
|
36
23
|
receipt?: AgentChannelJson | undefined;
|
|
37
24
|
} | {
|
|
@@ -56,6 +43,19 @@ export declare function executeChannelBehavior(input: {
|
|
|
56
43
|
message: string;
|
|
57
44
|
retryable: boolean;
|
|
58
45
|
};
|
|
46
|
+
} | {
|
|
47
|
+
sequence: number;
|
|
48
|
+
duplicate: boolean;
|
|
49
|
+
} | {
|
|
50
|
+
state: AgentChannelJson;
|
|
51
|
+
intents: {
|
|
52
|
+
key: string;
|
|
53
|
+
payload: AgentChannelJson;
|
|
54
|
+
eventId: string;
|
|
55
|
+
operationId: string;
|
|
56
|
+
}[];
|
|
57
|
+
cursor: number;
|
|
58
|
+
idempotencyWindowMs?: number | undefined;
|
|
59
59
|
} | {
|
|
60
60
|
events: {
|
|
61
61
|
id: string;
|
package/dist/agent-core.wasm
CHANGED
|
Binary file
|
package/dist/agent-worker.d.ts
CHANGED
|
@@ -18,6 +18,7 @@ import { type AgentChannelJournalAppend } from "@gea-ai/contract/agent-channel-r
|
|
|
18
18
|
import { type AgentDurableObjectNamespace, type AgentToolApprovalDecision, type AgentToolIdentity, type AgentToolRuntimeSdk, type DefinedAgentPackage } from "./index";
|
|
19
19
|
import { type AgentChannelAddressEnvironment } from "./agent-channel-worker";
|
|
20
20
|
export { handleAgentChannelAddressAlarm, handleAgentChannelAddressRequest, type AgentChannelAddressEnvironment, type AgentChannelAddressStorage, type AgentChannelAddressTransactionStorage, } from "./agent-channel-worker";
|
|
21
|
+
declare const jsonObjectSchema: z.ZodRecord<z.ZodString, z.ZodJSONSchema>;
|
|
21
22
|
export type AgentHostBinding = {
|
|
22
23
|
fetch(path: string, init?: RequestInit): Promise<Response>;
|
|
23
24
|
};
|
|
@@ -191,7 +192,7 @@ export type AgentSessionNamespace = {
|
|
|
191
192
|
};
|
|
192
193
|
idFromName(name: string): unknown;
|
|
193
194
|
};
|
|
194
|
-
export declare function createGeaAI(host: AgentHostBinding, publicModel: string, extraBody?: Record<string, unknown>, client?: AgentModelProxyClient): Promise<LanguageModel>;
|
|
195
|
+
export declare function createGeaAI(host: AgentHostBinding, publicModel: string, extraBody?: Record<string, unknown>, client?: AgentModelProxyClient, requestBody?: z.infer<typeof jsonObjectSchema>): Promise<LanguageModel>;
|
|
195
196
|
export declare function runAgentWorkerRequest(input: {
|
|
196
197
|
interactionPolicy?: AgentInteractionPolicy;
|
|
197
198
|
initialization?: AgentWorkerToolInitialization;
|
package/dist/agent-worker.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { moveOpenAICompatibleCacheControlToMessageContent as moveOpenAiCompatibleCacheControlToContent, createCatalogLanguageModel, } from "./catalog-language-model.js";
|
|
2
|
+
import { mergeLlmJson, llmRuntimeRequestOptionsSchema, } from "@gea-ai/contract/llm-catalog";
|
|
1
3
|
import { agentWorkerAttachmentOutputSchema } from "@gea-ai/contract/agent-api-host";
|
|
2
4
|
import { streamManagedAgentSessionRun } from "./agent-session-stream.js";
|
|
3
5
|
import { agentSessionReadToolOutputSchema, agentSessionReadToolOutputResultSchema, } from "@gea-ai/contract/agent-session";
|
|
@@ -60,12 +62,7 @@ const modelDescriptorSchema = z.union([
|
|
|
60
62
|
z.object({ transport: z.literal(AGENT_MODEL_PROXY_TRANSPORT) }).strict(),
|
|
61
63
|
]);
|
|
62
64
|
const jsonObjectSchema = z.record(z.string(), z.json());
|
|
63
|
-
const modelRequestOptionsSchema =
|
|
64
|
-
.object({
|
|
65
|
-
extraBody: jsonObjectSchema.optional(),
|
|
66
|
-
providerOptions: z.record(z.string(), jsonObjectSchema).optional(),
|
|
67
|
-
})
|
|
68
|
-
.strict();
|
|
65
|
+
const modelRequestOptionsSchema = llmRuntimeRequestOptionsSchema;
|
|
69
66
|
function mergeModelProviderOptions(defaults, overrides) {
|
|
70
67
|
const merged = { ...defaults };
|
|
71
68
|
for (const [provider, options] of Object.entries(overrides ?? {})) {
|
|
@@ -2373,50 +2370,6 @@ function mergeRequestBodyExtra(body, extraBody) {
|
|
|
2373
2370
|
}
|
|
2374
2371
|
return merged;
|
|
2375
2372
|
}
|
|
2376
|
-
function moveOpenAiCompatibleCacheControlToContent(body) {
|
|
2377
|
-
if (!Array.isArray(body.messages))
|
|
2378
|
-
return body;
|
|
2379
|
-
return {
|
|
2380
|
-
...body,
|
|
2381
|
-
messages: body.messages.map((message) => {
|
|
2382
|
-
if (!isJsonObject(message) ||
|
|
2383
|
-
!("cache_control" in message) ||
|
|
2384
|
-
message.cache_control == null) {
|
|
2385
|
-
return message;
|
|
2386
|
-
}
|
|
2387
|
-
const { cache_control: cacheControl, content, ...rest } = message;
|
|
2388
|
-
if (typeof content === "string") {
|
|
2389
|
-
return {
|
|
2390
|
-
...rest,
|
|
2391
|
-
content: [
|
|
2392
|
-
{ cache_control: cacheControl, text: content, type: "text" },
|
|
2393
|
-
],
|
|
2394
|
-
};
|
|
2395
|
-
}
|
|
2396
|
-
if (!Array.isArray(content))
|
|
2397
|
-
return message;
|
|
2398
|
-
if (content.some((part) => isJsonObject(part) && "cache_control" in part)) {
|
|
2399
|
-
return { ...rest, content };
|
|
2400
|
-
}
|
|
2401
|
-
let textPartIndex = -1;
|
|
2402
|
-
for (let index = content.length - 1; index >= 0; index -= 1) {
|
|
2403
|
-
const part = content[index];
|
|
2404
|
-
if (isJsonObject(part) && part.type === "text") {
|
|
2405
|
-
textPartIndex = index;
|
|
2406
|
-
break;
|
|
2407
|
-
}
|
|
2408
|
-
}
|
|
2409
|
-
return textPartIndex < 0
|
|
2410
|
-
? message
|
|
2411
|
-
: {
|
|
2412
|
-
...rest,
|
|
2413
|
-
content: content.map((part, index) => index === textPartIndex && isJsonObject(part)
|
|
2414
|
-
? { ...part, cache_control: cacheControl }
|
|
2415
|
-
: part),
|
|
2416
|
-
};
|
|
2417
|
-
}),
|
|
2418
|
-
};
|
|
2419
|
-
}
|
|
2420
2373
|
function serializeHostedModelCallOptions(options) {
|
|
2421
2374
|
const { abortSignal: _abortSignal, ...serializableOptions } = options;
|
|
2422
2375
|
return serializableOptions;
|
|
@@ -2501,12 +2454,13 @@ function createHostedGeaLanguageModel(input) {
|
|
|
2501
2454
|
};
|
|
2502
2455
|
}
|
|
2503
2456
|
async function createGeaCoreConnection(host, publicModel, requestOptions, signal, maxOutputTokens) {
|
|
2504
|
-
const descriptor = modelDescriptorSchema.parse(await requireHostJson(host, `/model?model=${encodeURIComponent(publicModel)}&transport=agent-core&includeMaxOutputTokens=true`, { signal }));
|
|
2457
|
+
const descriptor = modelDescriptorSchema.parse(await requireHostJson(host, `/model?model=${encodeURIComponent(publicModel)}&transport=agent-core&includeMaxOutputTokens=true&includeCatalogConfig=true`, { signal }));
|
|
2505
2458
|
if ("transport" in descriptor)
|
|
2506
2459
|
throw new Error("Agent Core requires the raw model transport.");
|
|
2507
|
-
const format = descriptor.
|
|
2508
|
-
|
|
2509
|
-
|
|
2460
|
+
const format = descriptor.format ??
|
|
2461
|
+
(descriptor.providerType === "anthropic"
|
|
2462
|
+
? "anthropic-messages"
|
|
2463
|
+
: "openai-completions");
|
|
2510
2464
|
const resolvedMaxOutputTokens = maxOutputTokens ?? descriptor.maxOutputTokens;
|
|
2511
2465
|
const provider = agentCoreProviderConfigSchema.parse({
|
|
2512
2466
|
format,
|
|
@@ -2516,10 +2470,14 @@ async function createGeaCoreConnection(host, publicModel, requestOptions, signal
|
|
|
2516
2470
|
descriptor.includeUsage === false
|
|
2517
2471
|
? { stream_options: { include_usage: false } }
|
|
2518
2472
|
: {}),
|
|
2519
|
-
...
|
|
2520
|
-
|
|
2473
|
+
...mergeLlmJson(requestOptions?.requestBody ??
|
|
2474
|
+
descriptor.requestOptions?.requestBody ??
|
|
2475
|
+
descriptor.requestOptions?.extraBody, requestOptions?.extraBody),
|
|
2521
2476
|
},
|
|
2522
2477
|
generation: {
|
|
2478
|
+
...(descriptor.compat?.maxTokensField
|
|
2479
|
+
? { max_tokens_field: descriptor.compat.maxTokensField }
|
|
2480
|
+
: {}),
|
|
2523
2481
|
...fromAiSdkProviderOptions(format, mergeModelProviderOptions(descriptor.requestOptions?.providerOptions, requestOptions?.providerOptions)),
|
|
2524
2482
|
...(resolvedMaxOutputTokens === undefined
|
|
2525
2483
|
? {}
|
|
@@ -2530,7 +2488,7 @@ async function createGeaCoreConnection(host, publicModel, requestOptions, signal
|
|
|
2530
2488
|
if (typeof init?.body !== "string")
|
|
2531
2489
|
throw new Error("Core provider request must contain JSON text.");
|
|
2532
2490
|
const headers = new Headers(init.headers);
|
|
2533
|
-
return host.fetch(`${HOST_PATH}/model/provider-fetch?model=${encodeURIComponent(publicModel)}`, {
|
|
2491
|
+
return host.fetch(`${HOST_PATH}/model/provider-fetch?model=${encodeURIComponent(publicModel)}&includeCatalogConfig=true`, {
|
|
2534
2492
|
method: "POST",
|
|
2535
2493
|
body: init.body,
|
|
2536
2494
|
signal: init.signal,
|
|
@@ -2545,14 +2503,16 @@ async function createGeaCoreConnection(host, publicModel, requestOptions, signal
|
|
|
2545
2503
|
return {
|
|
2546
2504
|
provider,
|
|
2547
2505
|
fetch,
|
|
2548
|
-
cacheControlProvider: descriptor.
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2506
|
+
cacheControlProvider: descriptor.cacheControl === "off"
|
|
2507
|
+
? undefined
|
|
2508
|
+
: (descriptor.cacheControlProvider ??
|
|
2509
|
+
(descriptor.providerType === "anthropic"
|
|
2510
|
+
? "anthropic"
|
|
2511
|
+
: undefined)),
|
|
2552
2512
|
};
|
|
2553
2513
|
}
|
|
2554
|
-
export async function createGeaAI(host, publicModel, extraBody, client) {
|
|
2555
|
-
const descriptor = modelDescriptorSchema.parse(await requireHostJson(host, `/model?model=${encodeURIComponent(publicModel)}&includeModelId=true&includeMaxOutputTokens=true`));
|
|
2514
|
+
export async function createGeaAI(host, publicModel, extraBody, client, requestBody) {
|
|
2515
|
+
const descriptor = modelDescriptorSchema.parse(await requireHostJson(host, `/model?model=${encodeURIComponent(publicModel)}&includeModelId=true&includeMaxOutputTokens=true&includeCatalogConfig=true`));
|
|
2556
2516
|
if ("transport" in descriptor) {
|
|
2557
2517
|
return createHostedGeaLanguageModel({ client, host, publicModel });
|
|
2558
2518
|
}
|
|
@@ -2562,7 +2522,7 @@ export async function createGeaAI(host, publicModel, extraBody, client) {
|
|
|
2562
2522
|
}
|
|
2563
2523
|
const providerHeaders = new Headers(init.headers);
|
|
2564
2524
|
const anthropicBeta = providerHeaders.get("anthropic-beta");
|
|
2565
|
-
return await host.fetch(`${HOST_PATH}/model/provider-fetch?model=${encodeURIComponent(publicModel)}`, {
|
|
2525
|
+
return await host.fetch(`${HOST_PATH}/model/provider-fetch?model=${encodeURIComponent(publicModel)}&includeCatalogConfig=true`, {
|
|
2566
2526
|
body: init.body,
|
|
2567
2527
|
headers: {
|
|
2568
2528
|
...(anthropicBeta ? { "anthropic-beta": anthropicBeta } : {}),
|
|
@@ -2572,6 +2532,35 @@ export async function createGeaAI(host, publicModel, extraBody, client) {
|
|
|
2572
2532
|
signal: init.signal,
|
|
2573
2533
|
});
|
|
2574
2534
|
};
|
|
2535
|
+
if (descriptor.format) {
|
|
2536
|
+
const model = createCatalogLanguageModel({
|
|
2537
|
+
format: descriptor.format,
|
|
2538
|
+
modelId: descriptor.modelId ?? publicModel,
|
|
2539
|
+
baseURL: "https://gea-ai-binding.invalid/v1",
|
|
2540
|
+
apiKey: "host-managed",
|
|
2541
|
+
auth: "bearer",
|
|
2542
|
+
fetch: providerFetch,
|
|
2543
|
+
includeUsage: descriptor.includeUsage ?? undefined,
|
|
2544
|
+
maxOutputTokens: descriptor.maxOutputTokens,
|
|
2545
|
+
maxTokensField: descriptor.compat?.maxTokensField,
|
|
2546
|
+
requestBody: mergeLlmJson(requestBody ??
|
|
2547
|
+
descriptor.requestOptions?.requestBody ??
|
|
2548
|
+
descriptor.requestOptions?.extraBody, jsonObjectSchema.parse(extraBody ?? {})),
|
|
2549
|
+
});
|
|
2550
|
+
const cache = descriptor.cacheControlProvider;
|
|
2551
|
+
const state = {};
|
|
2552
|
+
return wrapLanguageModel({
|
|
2553
|
+
model,
|
|
2554
|
+
modelId: publicModel,
|
|
2555
|
+
middleware: {
|
|
2556
|
+
transformParams: async ({ params }) => ({
|
|
2557
|
+
...params,
|
|
2558
|
+
prompt: addCacheControlToMessages(params.prompt, cache, state),
|
|
2559
|
+
tools: addCacheControlToToolList(params.tools, cache, state),
|
|
2560
|
+
}),
|
|
2561
|
+
},
|
|
2562
|
+
});
|
|
2563
|
+
}
|
|
2575
2564
|
if (descriptor.providerType === "anthropic") {
|
|
2576
2565
|
if (extraBody && Object.keys(extraBody).length > 0) {
|
|
2577
2566
|
throw new Error("Anthropic models do not support extra request body fields.");
|
|
@@ -3643,7 +3632,7 @@ async function executeAgentWorkerRequest(input, waitUntil, ownComputer, ownSessi
|
|
|
3643
3632
|
: await createGeaAI(host, configuredModel, requestOptions.extraBody, {
|
|
3644
3633
|
kind: "agent-dev",
|
|
3645
3634
|
packageName: input.snapshot.name,
|
|
3646
|
-
});
|
|
3635
|
+
}, requestOptions.requestBody);
|
|
3647
3636
|
const modelMessages = replaceInputFiles(await convertToModelMessages(payload.originalMessages), inputFiles);
|
|
3648
3637
|
// Model file parts can contain URL and byte values that ordinary JSON cannot preserve.
|
|
3649
3638
|
const runtimeContext = decodeAgentModelProxyValue(payload.runtimeContext);
|
|
@@ -3947,7 +3936,9 @@ async function executeAgentWorkerRequest(input, waitUntil, ownComputer, ownSessi
|
|
|
3947
3936
|
let resolved = models.get(modelId);
|
|
3948
3937
|
if (!resolved) {
|
|
3949
3938
|
// TS strategies choose their own model features, independently of Core.
|
|
3950
|
-
resolved = createGeaAI(host, modelId, modelId === configuredModel ? requestOptions.extraBody : undefined, { kind: "agent-dev", packageName: input.snapshot.name }
|
|
3939
|
+
resolved = createGeaAI(host, modelId, modelId === configuredModel ? requestOptions.extraBody : undefined, { kind: "agent-dev", packageName: input.snapshot.name }, modelId === configuredModel
|
|
3940
|
+
? requestOptions.requestBody
|
|
3941
|
+
: undefined);
|
|
3951
3942
|
models.set(modelId, resolved);
|
|
3952
3943
|
}
|
|
3953
3944
|
return resolved;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export { moveOpenAICompatibleCacheControlToMessageContent } from "./openai-compatible-cache-control";
|
|
2
|
+
import { type LlmModelFormat } from "@gea-ai/contract/llm-catalog";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
declare const object: z.ZodRecord<z.ZodString, z.ZodJSONSchema>;
|
|
5
|
+
/** A shared AI SDK adapter for hosted and native Catalog v2 execution. */
|
|
6
|
+
export declare function createCatalogLanguageModel(config: {
|
|
7
|
+
format: LlmModelFormat;
|
|
8
|
+
modelId: string;
|
|
9
|
+
baseURL: string;
|
|
10
|
+
apiKey: string;
|
|
11
|
+
auth: "bearer" | "x-api-key";
|
|
12
|
+
fetch: typeof globalThis.fetch;
|
|
13
|
+
includeUsage?: boolean;
|
|
14
|
+
maxOutputTokens?: number;
|
|
15
|
+
maxTokensField?: "max_tokens" | "max_completion_tokens";
|
|
16
|
+
requestBody?: z.infer<typeof object>;
|
|
17
|
+
}): import("@ai-sdk/provider").LanguageModelV4;
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
import { moveOpenAICompatibleCacheControlToMessageContent } from "./openai-compatible-cache-control.js";
|
|
2
|
+
export { moveOpenAICompatibleCacheControlToMessageContent } from "./openai-compatible-cache-control.js";
|
|
3
|
+
import { createAnthropic } from "@ai-sdk/anthropic";
|
|
4
|
+
import { createOpenAI } from "@ai-sdk/openai";
|
|
5
|
+
import { createOpenAICompatible } from "@ai-sdk/openai-compatible";
|
|
6
|
+
import { wrapLanguageModel } from "ai";
|
|
7
|
+
import { resolveAnthropicModelId } from "@gea-ai/contract/model-identity";
|
|
8
|
+
import { llmRequestBodySchema, mergeLlmJson, } from "@gea-ai/contract/llm-catalog";
|
|
9
|
+
import { z } from "zod";
|
|
10
|
+
const object = z.record(z.string(), z.json());
|
|
11
|
+
const controlsSchema = z.object({
|
|
12
|
+
thinking: z
|
|
13
|
+
.object({
|
|
14
|
+
type: z.string(),
|
|
15
|
+
budget_tokens: z.number().optional(),
|
|
16
|
+
display: z.string().optional(),
|
|
17
|
+
})
|
|
18
|
+
.optional(),
|
|
19
|
+
output_config: z.object({ effort: z.string().optional() }).optional(),
|
|
20
|
+
reasoning: z
|
|
21
|
+
.object({ effort: z.string().optional(), summary: z.string().optional() })
|
|
22
|
+
.optional(),
|
|
23
|
+
reasoning_effort: z.string().optional(),
|
|
24
|
+
temperature: z.number().optional(),
|
|
25
|
+
top_p: z.number().optional(),
|
|
26
|
+
presence_penalty: z.number().optional(),
|
|
27
|
+
frequency_penalty: z.number().optional(),
|
|
28
|
+
seed: z.number().int().optional(),
|
|
29
|
+
store: z.boolean().optional(),
|
|
30
|
+
});
|
|
31
|
+
const usageSchema = z.object({
|
|
32
|
+
input_tokens_details: z
|
|
33
|
+
.object({ cache_write_tokens: z.number().nonnegative().optional() })
|
|
34
|
+
.nullish(),
|
|
35
|
+
prompt_tokens_details: z
|
|
36
|
+
.object({
|
|
37
|
+
cache_creation_input_tokens: z.number().nonnegative().optional(),
|
|
38
|
+
})
|
|
39
|
+
.nullish(),
|
|
40
|
+
});
|
|
41
|
+
const usageFrameSchema = z.object({
|
|
42
|
+
usage: usageSchema.nullish(),
|
|
43
|
+
response: z.object({ usage: usageSchema.nullish() }).optional(),
|
|
44
|
+
});
|
|
45
|
+
/** A shared AI SDK adapter for hosted and native Catalog v2 execution. */
|
|
46
|
+
export function createCatalogLanguageModel(config) {
|
|
47
|
+
const bodyDefaults = llmRequestBodySchema.parse(config.requestBody ?? {});
|
|
48
|
+
const controls = controlsSchema.parse(bodyDefaults);
|
|
49
|
+
const namespace = config.format === "anthropic-messages"
|
|
50
|
+
? "anthropic"
|
|
51
|
+
: config.format === "openai-responses"
|
|
52
|
+
? "openai"
|
|
53
|
+
: "openaiCompatible";
|
|
54
|
+
const providerDefaults = {};
|
|
55
|
+
if (config.format === "anthropic-messages") {
|
|
56
|
+
if (controls.thinking) {
|
|
57
|
+
const { budget_tokens, ...thinking } = controls.thinking;
|
|
58
|
+
providerDefaults.thinking = {
|
|
59
|
+
...thinking,
|
|
60
|
+
...(budget_tokens === undefined ? {} : { budgetTokens: budget_tokens }),
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
if (controls.output_config?.effort)
|
|
64
|
+
providerDefaults.effort = controls.output_config.effort;
|
|
65
|
+
}
|
|
66
|
+
else if (config.format === "openai-responses") {
|
|
67
|
+
providerDefaults.store = controls.store ?? false;
|
|
68
|
+
if (controls.reasoning) {
|
|
69
|
+
providerDefaults.forceReasoning = true;
|
|
70
|
+
if (controls.reasoning.effort)
|
|
71
|
+
providerDefaults.reasoningEffort = controls.reasoning.effort;
|
|
72
|
+
if (controls.reasoning.summary)
|
|
73
|
+
providerDefaults.reasoningSummary = controls.reasoning.summary;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
else if (controls.reasoning_effort)
|
|
77
|
+
providerDefaults.reasoningEffort = controls.reasoning_effort;
|
|
78
|
+
// Mapped controls must not be merged back after SDK serialization: doing so
|
|
79
|
+
// can reintroduce a default thinking budget after an explicit mode change.
|
|
80
|
+
const extensions = { ...bodyDefaults };
|
|
81
|
+
for (const key of [
|
|
82
|
+
"temperature",
|
|
83
|
+
"top_p",
|
|
84
|
+
"presence_penalty",
|
|
85
|
+
"frequency_penalty",
|
|
86
|
+
"seed",
|
|
87
|
+
])
|
|
88
|
+
delete extensions[key];
|
|
89
|
+
if (config.format === "anthropic-messages") {
|
|
90
|
+
if (extensions.thinking) {
|
|
91
|
+
const { type: _type, budget_tokens: _budget, display: _display, ...rest } = object.parse(extensions.thinking);
|
|
92
|
+
if (Object.keys(rest).length)
|
|
93
|
+
extensions.thinking = rest;
|
|
94
|
+
else
|
|
95
|
+
delete extensions.thinking;
|
|
96
|
+
}
|
|
97
|
+
if (extensions.output_config) {
|
|
98
|
+
const { effort: _effort, ...rest } = object.parse(extensions.output_config);
|
|
99
|
+
extensions.output_config = rest;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
else if (config.format === "openai-responses") {
|
|
103
|
+
delete extensions.store;
|
|
104
|
+
if (extensions.reasoning) {
|
|
105
|
+
const { effort: _effort, summary: _summary, ...rest } = object.parse(extensions.reasoning);
|
|
106
|
+
extensions.reasoning = rest;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
else
|
|
110
|
+
delete extensions.reasoning_effort;
|
|
111
|
+
const fetch = async (input, init) => {
|
|
112
|
+
if (typeof init?.body !== "string")
|
|
113
|
+
throw new Error("Catalog provider request must be JSON text.");
|
|
114
|
+
// SDK encoding owns messages, signatures and tools. Merge only parameter defaults.
|
|
115
|
+
const body = mergeLlmJson(extensions, object.parse(JSON.parse(init.body)));
|
|
116
|
+
body.model = config.modelId;
|
|
117
|
+
if (config.format === "openai-completions" &&
|
|
118
|
+
config.maxTokensField === "max_completion_tokens" &&
|
|
119
|
+
body.max_tokens !== undefined) {
|
|
120
|
+
body.max_completion_tokens = body.max_tokens;
|
|
121
|
+
delete body.max_tokens;
|
|
122
|
+
}
|
|
123
|
+
const headers = new Headers(init.headers);
|
|
124
|
+
headers.delete("authorization");
|
|
125
|
+
headers.delete("x-api-key");
|
|
126
|
+
headers.set(config.auth === "bearer" ? "authorization" : "x-api-key", config.auth === "bearer" ? `Bearer ${config.apiKey}` : config.apiKey);
|
|
127
|
+
return config.fetch(input, {
|
|
128
|
+
...init,
|
|
129
|
+
headers,
|
|
130
|
+
body: JSON.stringify(body),
|
|
131
|
+
});
|
|
132
|
+
};
|
|
133
|
+
const connection = { baseURL: config.baseURL, apiKey: config.apiKey, fetch };
|
|
134
|
+
const model = config.format === "anthropic-messages"
|
|
135
|
+
? createAnthropic({
|
|
136
|
+
...connection,
|
|
137
|
+
...(config.auth === "bearer"
|
|
138
|
+
? { apiKey: undefined, authToken: config.apiKey }
|
|
139
|
+
: {}),
|
|
140
|
+
})(resolveAnthropicModelId(config.modelId))
|
|
141
|
+
: config.format === "openai-responses"
|
|
142
|
+
? createOpenAI(connection).responses(config.modelId)
|
|
143
|
+
: createOpenAICompatible({
|
|
144
|
+
...connection,
|
|
145
|
+
name: "openaiCompatible",
|
|
146
|
+
includeUsage: config.includeUsage,
|
|
147
|
+
transformRequestBody: moveOpenAICompatibleCacheControlToMessageContent,
|
|
148
|
+
})(config.modelId);
|
|
149
|
+
function withCacheWrites(usage, raw) {
|
|
150
|
+
const parsed = usageSchema.safeParse(raw);
|
|
151
|
+
const write = parsed.success
|
|
152
|
+
? (parsed.data.input_tokens_details?.cache_write_tokens ??
|
|
153
|
+
parsed.data.prompt_tokens_details?.cache_creation_input_tokens)
|
|
154
|
+
: undefined;
|
|
155
|
+
if (write === undefined)
|
|
156
|
+
return usage;
|
|
157
|
+
return {
|
|
158
|
+
...usage,
|
|
159
|
+
inputTokens: {
|
|
160
|
+
...usage.inputTokens,
|
|
161
|
+
cacheWrite: write,
|
|
162
|
+
noCache: usage.inputTokens.total === undefined
|
|
163
|
+
? undefined
|
|
164
|
+
: Math.max(0, usage.inputTokens.total -
|
|
165
|
+
(usage.inputTokens.cacheRead ?? 0) -
|
|
166
|
+
write),
|
|
167
|
+
},
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
return wrapLanguageModel({
|
|
171
|
+
model,
|
|
172
|
+
modelId: config.modelId,
|
|
173
|
+
middleware: {
|
|
174
|
+
transformParams: async ({ params }) => {
|
|
175
|
+
const overrides = object.parse(params.providerOptions?.[namespace] ?? {});
|
|
176
|
+
const options = { ...providerDefaults, ...overrides };
|
|
177
|
+
if (config.format === "openai-responses" &&
|
|
178
|
+
options.reasoningEffort !== undefined)
|
|
179
|
+
options.forceReasoning ??= true;
|
|
180
|
+
return {
|
|
181
|
+
...params,
|
|
182
|
+
maxOutputTokens: params.maxOutputTokens ?? config.maxOutputTokens,
|
|
183
|
+
temperature: params.temperature ?? controls.temperature,
|
|
184
|
+
topP: params.topP ?? controls.top_p,
|
|
185
|
+
presencePenalty: params.presencePenalty ?? controls.presence_penalty,
|
|
186
|
+
frequencyPenalty: params.frequencyPenalty ?? controls.frequency_penalty,
|
|
187
|
+
seed: params.seed ?? controls.seed,
|
|
188
|
+
providerOptions: { ...params.providerOptions, [namespace]: options },
|
|
189
|
+
};
|
|
190
|
+
},
|
|
191
|
+
wrapGenerate: async ({ doGenerate }) => {
|
|
192
|
+
const result = await doGenerate();
|
|
193
|
+
const raw = usageFrameSchema.safeParse(result.response?.body);
|
|
194
|
+
return {
|
|
195
|
+
...result,
|
|
196
|
+
usage: withCacheWrites(result.usage, raw.success ? raw.data.usage : undefined),
|
|
197
|
+
};
|
|
198
|
+
},
|
|
199
|
+
wrapStream: async ({ model: providerModel, params }) => {
|
|
200
|
+
const result = await providerModel.doStream({
|
|
201
|
+
...params,
|
|
202
|
+
includeRawChunks: true,
|
|
203
|
+
});
|
|
204
|
+
let rawUsage;
|
|
205
|
+
return {
|
|
206
|
+
...result,
|
|
207
|
+
stream: result.stream.pipeThrough(new TransformStream({
|
|
208
|
+
transform(chunk, controller) {
|
|
209
|
+
if (chunk.type === "raw") {
|
|
210
|
+
const frame = usageFrameSchema.safeParse(chunk.rawValue);
|
|
211
|
+
if (frame.success)
|
|
212
|
+
rawUsage =
|
|
213
|
+
frame.data.usage ??
|
|
214
|
+
frame.data.response?.usage ??
|
|
215
|
+
rawUsage;
|
|
216
|
+
if (!params.includeRawChunks)
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
controller.enqueue(chunk.type === "finish"
|
|
220
|
+
? {
|
|
221
|
+
...chunk,
|
|
222
|
+
usage: withCacheWrites(chunk.usage, rawUsage),
|
|
223
|
+
}
|
|
224
|
+
: chunk);
|
|
225
|
+
},
|
|
226
|
+
})),
|
|
227
|
+
};
|
|
228
|
+
},
|
|
229
|
+
},
|
|
230
|
+
});
|
|
231
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function moveOpenAICompatibleCacheControlToMessageContent(body: Record<string, any>): Record<string, any>;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
export function moveOpenAICompatibleCacheControlToMessageContent(body) {
|
|
2
|
+
if (!Array.isArray(body.messages)) {
|
|
3
|
+
return body;
|
|
4
|
+
}
|
|
5
|
+
return {
|
|
6
|
+
...body,
|
|
7
|
+
messages: body.messages.map(moveMessageCacheControlToContent),
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
function moveMessageCacheControlToContent(message) {
|
|
11
|
+
if (!message ||
|
|
12
|
+
typeof message !== "object" ||
|
|
13
|
+
Array.isArray(message) ||
|
|
14
|
+
!("cache_control" in message)) {
|
|
15
|
+
return message;
|
|
16
|
+
}
|
|
17
|
+
const { cache_control: cacheControl, content, ...messageWithoutCacheControl } = message;
|
|
18
|
+
if (cacheControl == null) {
|
|
19
|
+
return message;
|
|
20
|
+
}
|
|
21
|
+
if (typeof content === "string") {
|
|
22
|
+
return {
|
|
23
|
+
...messageWithoutCacheControl,
|
|
24
|
+
content: [
|
|
25
|
+
{
|
|
26
|
+
cache_control: cacheControl,
|
|
27
|
+
text: content,
|
|
28
|
+
type: "text",
|
|
29
|
+
},
|
|
30
|
+
],
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
if (!Array.isArray(content)) {
|
|
34
|
+
return message;
|
|
35
|
+
}
|
|
36
|
+
if (content.some(hasCacheControl)) {
|
|
37
|
+
return {
|
|
38
|
+
...messageWithoutCacheControl,
|
|
39
|
+
content,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
const textPartIndex = findLastTextContentPartIndex(content);
|
|
43
|
+
if (textPartIndex < 0) {
|
|
44
|
+
return message;
|
|
45
|
+
}
|
|
46
|
+
return {
|
|
47
|
+
...messageWithoutCacheControl,
|
|
48
|
+
content: content.map((part, index) => index === textPartIndex
|
|
49
|
+
? { ...part, cache_control: cacheControl }
|
|
50
|
+
: part),
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
function hasCacheControl(value) {
|
|
54
|
+
return (value != null &&
|
|
55
|
+
typeof value === "object" &&
|
|
56
|
+
!Array.isArray(value) &&
|
|
57
|
+
"cache_control" in value);
|
|
58
|
+
}
|
|
59
|
+
function findLastTextContentPartIndex(content) {
|
|
60
|
+
for (let index = content.length - 1; index >= 0; index -= 1) {
|
|
61
|
+
const part = content[index];
|
|
62
|
+
if (part &&
|
|
63
|
+
typeof part === "object" &&
|
|
64
|
+
!Array.isArray(part) &&
|
|
65
|
+
"type" in part &&
|
|
66
|
+
part.type === "text") {
|
|
67
|
+
return index;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return -1;
|
|
71
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gea-ai/agent-sdk",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.260917-alpha.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"homepage": "https://musegea.com/developers",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -88,6 +88,10 @@
|
|
|
88
88
|
"./worker-build-plugins": {
|
|
89
89
|
"types": "./dist/worker-build-plugins.d.ts",
|
|
90
90
|
"import": "./dist/worker-build-plugins.js"
|
|
91
|
+
},
|
|
92
|
+
"./catalog-language-model": {
|
|
93
|
+
"types": "./dist/catalog-language-model.d.ts",
|
|
94
|
+
"import": "./dist/catalog-language-model.js"
|
|
91
95
|
}
|
|
92
96
|
},
|
|
93
97
|
"publishConfig": {
|
|
@@ -100,7 +104,7 @@
|
|
|
100
104
|
"@ai-sdk/otel": "1.0.9",
|
|
101
105
|
"@ai-sdk/provider": "4.0.1",
|
|
102
106
|
"@ai-sdk/provider-utils": "5.0.2",
|
|
103
|
-
"@gea-ai/contract": "0.1.
|
|
107
|
+
"@gea-ai/contract": "0.1.260917-alpha.0",
|
|
104
108
|
"@opentelemetry/api": "1.9.1",
|
|
105
109
|
"@opentelemetry/context-async-hooks": "2.10.0",
|
|
106
110
|
"@opentelemetry/core": "2.10.0",
|