veryfront 0.1.372 → 0.1.374
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/esm/deno.d.ts +11 -0
- package/esm/deno.js +13 -1
- package/esm/src/agent/index.d.ts +2 -0
- package/esm/src/agent/index.d.ts.map +1 -1
- package/esm/src/agent/index.js +2 -0
- package/esm/src/agent/project-context.d.ts +8 -0
- package/esm/src/agent/project-context.d.ts.map +1 -0
- package/esm/src/agent/project-context.js +40 -0
- package/esm/src/agent/project-steering-mutation.d.ts +23 -0
- package/esm/src/agent/project-steering-mutation.d.ts.map +1 -0
- package/esm/src/agent/project-steering-mutation.js +72 -0
- package/esm/src/embedding/resolve.d.ts.map +1 -1
- package/esm/src/embedding/resolve.js +11 -2
- package/esm/src/embedding/veryfront-cloud/provider.d.ts.map +1 -1
- package/esm/src/embedding/veryfront-cloud/provider.js +18 -8
- package/esm/src/provider/model-registry.d.ts.map +1 -1
- package/esm/src/provider/model-registry.js +11 -2
- package/esm/src/provider/runtime-loader.d.ts +6 -11
- package/esm/src/provider/runtime-loader.d.ts.map +1 -1
- package/esm/src/provider/runtime-loader.js +7 -512
- package/esm/src/provider/shared/index.d.ts +2 -2
- package/esm/src/provider/shared/index.d.ts.map +1 -1
- package/esm/src/provider/shared/index.js +1 -1
- package/esm/src/provider/veryfront-cloud/provider.d.ts.map +1 -1
- package/esm/src/provider/veryfront-cloud/provider.js +14 -11
- package/esm/src/utils/version-constant.d.ts +1 -1
- package/esm/src/utils/version-constant.js +1 -1
- package/package.json +1 -1
- package/src/deno.js +13 -1
- package/src/deps/esm.sh/@types/react-dom@19.2.3/client.d.ts +1 -1
- package/src/deps/esm.sh/@types/{react@19.2.3 → react@19.2.14}/global.d.ts +1 -0
- package/src/deps/esm.sh/@types/{react@19.2.3 → react@19.2.14}/index.d.ts +93 -24
- package/src/deps/esm.sh/react-dom@19.2.4/client.d.ts +1 -1
- package/src/src/agent/index.ts +15 -0
- package/src/src/agent/project-context.ts +63 -0
- package/src/src/agent/project-steering-mutation.ts +126 -0
- package/src/src/embedding/resolve.ts +14 -2
- package/src/src/embedding/veryfront-cloud/provider.ts +22 -8
- package/src/src/provider/model-registry.ts +14 -2
- package/src/src/provider/runtime-loader.ts +8 -672
- package/src/src/provider/shared/index.ts +4 -0
- package/src/src/provider/veryfront-cloud/provider.ts +16 -11
- package/src/src/utils/version-constant.ts +1 -1
|
@@ -1,27 +1,11 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
getGoogleStreamGenerateContentUrl,
|
|
7
|
-
} from "./runtime-loader/provider-endpoints.js";
|
|
8
|
-
import {
|
|
9
|
-
extractGoogleEmbedding,
|
|
10
|
-
extractGoogleUsageTokens,
|
|
11
|
-
isNumberArray,
|
|
12
|
-
} from "./runtime-loader/provider-embedding-responses.js";
|
|
13
|
-
import {
|
|
14
|
-
normalizeAnthropicFinishReason,
|
|
15
|
-
normalizeGoogleFinishReason,
|
|
16
|
-
} from "./runtime-loader/provider-finish-reasons.js";
|
|
17
|
-
import {
|
|
18
|
-
createAnthropicRequestInit,
|
|
19
|
-
createGoogleRequestInit,
|
|
20
|
-
} from "./runtime-loader/provider-request-init.js";
|
|
1
|
+
import type { ModelRuntime } from "./types.js";
|
|
2
|
+
import { getAnthropicMessagesUrl } from "./runtime-loader/provider-endpoints.js";
|
|
3
|
+
import { isNumberArray } from "./runtime-loader/provider-embedding-responses.js";
|
|
4
|
+
import { normalizeAnthropicFinishReason } from "./runtime-loader/provider-finish-reasons.js";
|
|
5
|
+
import { createAnthropicRequestInit } from "./runtime-loader/provider-request-init.js";
|
|
21
6
|
import { parseSseChunk } from "./runtime-loader/provider-sse.js";
|
|
22
7
|
import {
|
|
23
8
|
extractAnthropicUsage,
|
|
24
|
-
extractGoogleUsage,
|
|
25
9
|
mergeUsage,
|
|
26
10
|
type RuntimeUsage,
|
|
27
11
|
} from "./runtime-loader/provider-usage.js";
|
|
@@ -51,10 +35,12 @@ export {
|
|
|
51
35
|
isNumberArray,
|
|
52
36
|
mergeUsage,
|
|
53
37
|
parseRetryAfterMs,
|
|
38
|
+
parseSseChunk,
|
|
54
39
|
readRecord,
|
|
55
40
|
requestJson,
|
|
56
41
|
requestStream,
|
|
57
42
|
};
|
|
43
|
+
export type { RuntimeUsage };
|
|
58
44
|
|
|
59
45
|
export interface AnthropicRuntimeConfig {
|
|
60
46
|
apiKey?: string;
|
|
@@ -64,13 +50,6 @@ export interface AnthropicRuntimeConfig {
|
|
|
64
50
|
fetch?: typeof globalThis.fetch;
|
|
65
51
|
}
|
|
66
52
|
|
|
67
|
-
export interface GoogleRuntimeConfig {
|
|
68
|
-
apiKey: string;
|
|
69
|
-
baseURL?: string;
|
|
70
|
-
name?: string;
|
|
71
|
-
fetch?: typeof globalThis.fetch;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
53
|
export type RuntimePromptMessage =
|
|
75
54
|
| { role: "system"; content: string }
|
|
76
55
|
| { role: "user"; content: Array<{ type: "text"; text: string }> }
|
|
@@ -282,29 +261,6 @@ type OpenAICompatibleLanguageOptions = {
|
|
|
282
261
|
* specify for the target feature.
|
|
283
262
|
*/
|
|
284
263
|
anthropicContainer?: unknown;
|
|
285
|
-
/**
|
|
286
|
-
* Google-specific. Reference to a previously-created Gemini cached
|
|
287
|
-
* content resource (created via the separate caches API) to attach
|
|
288
|
-
* to this request. Resource name format:
|
|
289
|
-
* `cachedContents/<id>`. See https://ai.google.dev/gemini-api/docs/caching.
|
|
290
|
-
*
|
|
291
|
-
* Cache creation itself is out of scope for the runtime — callers
|
|
292
|
-
* use the Gemini REST API or SDK to create the cache, then pass the
|
|
293
|
-
* resource name here on each subsequent generate call to attach the
|
|
294
|
-
* cached prefix and avoid re-paying for it.
|
|
295
|
-
*/
|
|
296
|
-
googleCachedContent?: string;
|
|
297
|
-
/**
|
|
298
|
-
* Google-specific. Per-request safety filter configuration for
|
|
299
|
-
* Gemini. Each entry pairs a HARM_CATEGORY_* with a threshold
|
|
300
|
-
* (BLOCK_NONE / BLOCK_LOW_AND_ABOVE / BLOCK_MEDIUM_AND_ABOVE /
|
|
301
|
-
* BLOCK_ONLY_HIGH). Forwarded verbatim as the `safetySettings`
|
|
302
|
-
* field. See https://ai.google.dev/gemini-api/docs/safety-settings.
|
|
303
|
-
*/
|
|
304
|
-
googleSafetySettings?: Array<{
|
|
305
|
-
category: string;
|
|
306
|
-
threshold: string;
|
|
307
|
-
}>;
|
|
308
264
|
/**
|
|
309
265
|
* Anthropic-specific. Native MCP server definitions to pass directly
|
|
310
266
|
* on the Messages API request body. Lets callers register MCP servers
|
|
@@ -398,23 +354,6 @@ type AnthropicStreamToolCallState = {
|
|
|
398
354
|
type AnthropicStreamReasoningState = {
|
|
399
355
|
id: string;
|
|
400
356
|
};
|
|
401
|
-
type GoogleCompatibleContent = {
|
|
402
|
-
role: "user" | "model";
|
|
403
|
-
parts: Array<Record<string, unknown>>;
|
|
404
|
-
};
|
|
405
|
-
type GoogleCompatibleRequest = {
|
|
406
|
-
contents: GoogleCompatibleContent[];
|
|
407
|
-
systemInstruction?: {
|
|
408
|
-
parts: Array<{ text: string }>;
|
|
409
|
-
};
|
|
410
|
-
tools?: Array<Record<string, unknown>>;
|
|
411
|
-
toolConfig?: {
|
|
412
|
-
functionCallingConfig: Record<string, unknown>;
|
|
413
|
-
};
|
|
414
|
-
generationConfig?: Record<string, unknown>;
|
|
415
|
-
[key: string]: unknown;
|
|
416
|
-
};
|
|
417
|
-
|
|
418
357
|
/**
|
|
419
358
|
* Structured warning emitted when a provider runtime drops or rewrites a
|
|
420
359
|
* caller-provided option. Mirrors the AI ecosystem convention (Vercel AI
|
|
@@ -1454,120 +1393,7 @@ async function* streamAnthropicCompatibleParts(
|
|
|
1454
1393
|
};
|
|
1455
1394
|
}
|
|
1456
1395
|
|
|
1457
|
-
function
|
|
1458
|
-
prompt: RuntimePromptMessage[],
|
|
1459
|
-
): {
|
|
1460
|
-
systemInstruction?: { parts: Array<{ text: string }> };
|
|
1461
|
-
contents: GoogleCompatibleContent[];
|
|
1462
|
-
} {
|
|
1463
|
-
const systemParts: string[] = [];
|
|
1464
|
-
const contents: GoogleCompatibleContent[] = [];
|
|
1465
|
-
|
|
1466
|
-
for (const message of prompt) {
|
|
1467
|
-
switch (message.role) {
|
|
1468
|
-
case "system":
|
|
1469
|
-
if (message.content.length > 0) {
|
|
1470
|
-
systemParts.push(message.content);
|
|
1471
|
-
}
|
|
1472
|
-
break;
|
|
1473
|
-
case "user":
|
|
1474
|
-
contents.push({
|
|
1475
|
-
role: "user",
|
|
1476
|
-
parts: [{ text: readTextParts(message.content) }],
|
|
1477
|
-
});
|
|
1478
|
-
break;
|
|
1479
|
-
case "assistant": {
|
|
1480
|
-
// Anthropic-only `reasoning` parts have no Gemini equivalent
|
|
1481
|
-
// and are dropped on replay.
|
|
1482
|
-
const parts: Array<Record<string, unknown>> = [];
|
|
1483
|
-
for (const part of message.content) {
|
|
1484
|
-
if (part.type === "text") {
|
|
1485
|
-
parts.push({ text: part.text });
|
|
1486
|
-
continue;
|
|
1487
|
-
}
|
|
1488
|
-
if (part.type === "reasoning") {
|
|
1489
|
-
continue;
|
|
1490
|
-
}
|
|
1491
|
-
parts.push({
|
|
1492
|
-
functionCall: {
|
|
1493
|
-
id: part.toolCallId,
|
|
1494
|
-
name: part.toolName,
|
|
1495
|
-
args: part.input,
|
|
1496
|
-
},
|
|
1497
|
-
});
|
|
1498
|
-
}
|
|
1499
|
-
contents.push({ role: "model", parts });
|
|
1500
|
-
break;
|
|
1501
|
-
}
|
|
1502
|
-
case "tool":
|
|
1503
|
-
contents.push({
|
|
1504
|
-
role: "user",
|
|
1505
|
-
parts: message.content.map((part) => ({
|
|
1506
|
-
functionResponse: {
|
|
1507
|
-
id: part.toolCallId,
|
|
1508
|
-
name: part.toolName,
|
|
1509
|
-
response: {
|
|
1510
|
-
result: part.output.value,
|
|
1511
|
-
},
|
|
1512
|
-
},
|
|
1513
|
-
})),
|
|
1514
|
-
});
|
|
1515
|
-
break;
|
|
1516
|
-
}
|
|
1517
|
-
}
|
|
1518
|
-
|
|
1519
|
-
return {
|
|
1520
|
-
...(systemParts.length > 0
|
|
1521
|
-
? { systemInstruction: { parts: systemParts.map((text) => ({ text })) } }
|
|
1522
|
-
: {}),
|
|
1523
|
-
contents,
|
|
1524
|
-
};
|
|
1525
|
-
}
|
|
1526
|
-
|
|
1527
|
-
function toGoogleTools(
|
|
1528
|
-
tools: RuntimeToolDefinition[] | undefined,
|
|
1529
|
-
): Array<Record<string, unknown>> | undefined {
|
|
1530
|
-
if (!tools) {
|
|
1531
|
-
return undefined;
|
|
1532
|
-
}
|
|
1533
|
-
|
|
1534
|
-
const functionDeclarations: Array<Record<string, unknown>> = [];
|
|
1535
|
-
const providerEntries: Array<Record<string, unknown>> = [];
|
|
1536
|
-
|
|
1537
|
-
for (const tool of tools) {
|
|
1538
|
-
if (tool.type === "function") {
|
|
1539
|
-
functionDeclarations.push({
|
|
1540
|
-
name: tool.name,
|
|
1541
|
-
...(typeof tool.description === "string" ? { description: tool.description } : {}),
|
|
1542
|
-
parameters: unwrapToolInputSchema(tool.inputSchema),
|
|
1543
|
-
});
|
|
1544
|
-
continue;
|
|
1545
|
-
}
|
|
1546
|
-
|
|
1547
|
-
// Gemini provider tools — code_execution, google_search,
|
|
1548
|
-
// google_search_retrieval — each lives in its own tools[] entry
|
|
1549
|
-
// with a single key keyed by the camelCase tool name and an
|
|
1550
|
-
// optional config payload (caller-provided tool.args).
|
|
1551
|
-
if (!tool.id.startsWith("google.")) {
|
|
1552
|
-
continue;
|
|
1553
|
-
}
|
|
1554
|
-
const providerType = tool.id.slice("google.".length);
|
|
1555
|
-
if (providerType.length === 0) {
|
|
1556
|
-
continue;
|
|
1557
|
-
}
|
|
1558
|
-
const camelKey = providerType.replace(/_([a-z])/g, (_, ch) => ch.toUpperCase());
|
|
1559
|
-
providerEntries.push({ [camelKey]: tool.args ?? {} });
|
|
1560
|
-
}
|
|
1561
|
-
|
|
1562
|
-
const result: Array<Record<string, unknown>> = [];
|
|
1563
|
-
if (functionDeclarations.length > 0) {
|
|
1564
|
-
result.push({ functionDeclarations });
|
|
1565
|
-
}
|
|
1566
|
-
result.push(...providerEntries);
|
|
1567
|
-
return result.length > 0 ? result : undefined;
|
|
1568
|
-
}
|
|
1569
|
-
|
|
1570
|
-
function unwrapToolInputSchema(inputSchema: unknown): unknown {
|
|
1396
|
+
export function unwrapToolInputSchema(inputSchema: unknown): unknown {
|
|
1571
1397
|
if (typeof inputSchema !== "object" || inputSchema === null || Array.isArray(inputSchema)) {
|
|
1572
1398
|
return inputSchema;
|
|
1573
1399
|
}
|
|
@@ -1576,375 +1402,6 @@ function unwrapToolInputSchema(inputSchema: unknown): unknown {
|
|
|
1576
1402
|
return candidate ?? inputSchema;
|
|
1577
1403
|
}
|
|
1578
1404
|
|
|
1579
|
-
function normalizeGoogleToolChoice(toolChoice: unknown):
|
|
1580
|
-
| GoogleCompatibleRequest["toolConfig"]
|
|
1581
|
-
| undefined {
|
|
1582
|
-
if (toolChoice === undefined) {
|
|
1583
|
-
return undefined;
|
|
1584
|
-
}
|
|
1585
|
-
|
|
1586
|
-
if (typeof toolChoice === "string") {
|
|
1587
|
-
switch (toolChoice) {
|
|
1588
|
-
case "none":
|
|
1589
|
-
return { functionCallingConfig: { mode: "NONE" } };
|
|
1590
|
-
case "any":
|
|
1591
|
-
case "required":
|
|
1592
|
-
return { functionCallingConfig: { mode: "ANY" } };
|
|
1593
|
-
default:
|
|
1594
|
-
return { functionCallingConfig: { mode: "AUTO" } };
|
|
1595
|
-
}
|
|
1596
|
-
}
|
|
1597
|
-
|
|
1598
|
-
const record = readRecord(toolChoice);
|
|
1599
|
-
if (!record) return undefined;
|
|
1600
|
-
|
|
1601
|
-
// Single-tool restriction: { type: "tool", name } — pin to one
|
|
1602
|
-
// function via mode: ANY + allowedFunctionNames: [name].
|
|
1603
|
-
if (record.type === "tool" && typeof record.name === "string") {
|
|
1604
|
-
return {
|
|
1605
|
-
functionCallingConfig: {
|
|
1606
|
-
mode: "ANY",
|
|
1607
|
-
allowedFunctionNames: [record.name],
|
|
1608
|
-
},
|
|
1609
|
-
};
|
|
1610
|
-
}
|
|
1611
|
-
|
|
1612
|
-
// Multi-tool restriction: { type: "tools", names: string[] } — pin
|
|
1613
|
-
// to a subset via mode: ANY + the full allowedFunctionNames array.
|
|
1614
|
-
if (record.type === "tools" && Array.isArray(record.names)) {
|
|
1615
|
-
const names = record.names.filter((n): n is string => typeof n === "string");
|
|
1616
|
-
if (names.length > 0) {
|
|
1617
|
-
return {
|
|
1618
|
-
functionCallingConfig: {
|
|
1619
|
-
mode: "ANY",
|
|
1620
|
-
allowedFunctionNames: names,
|
|
1621
|
-
},
|
|
1622
|
-
};
|
|
1623
|
-
}
|
|
1624
|
-
}
|
|
1625
|
-
|
|
1626
|
-
// Explicit mode forms: { type: "auto" | "none" | "any" }.
|
|
1627
|
-
if (record.type === "auto") {
|
|
1628
|
-
return { functionCallingConfig: { mode: "AUTO" } };
|
|
1629
|
-
}
|
|
1630
|
-
if (record.type === "none") {
|
|
1631
|
-
return { functionCallingConfig: { mode: "NONE" } };
|
|
1632
|
-
}
|
|
1633
|
-
if (record.type === "any" || record.type === "required") {
|
|
1634
|
-
return { functionCallingConfig: { mode: "ANY" } };
|
|
1635
|
-
}
|
|
1636
|
-
|
|
1637
|
-
return undefined;
|
|
1638
|
-
}
|
|
1639
|
-
|
|
1640
|
-
/**
|
|
1641
|
-
* Map the unified reasoning option to Gemini's thinkingConfig. Gemini 2.5+
|
|
1642
|
-
* accepts `includeThoughts: true` to stream back `thought` parts, and
|
|
1643
|
-
* `thinkingBudget: N` to cap the thinking token count. The effort levels
|
|
1644
|
-
* here follow Google's own guidance (low ~= 512, medium ~= 2048,
|
|
1645
|
-
* high ~= 8192, max = -1 means "dynamic/no cap").
|
|
1646
|
-
*/
|
|
1647
|
-
function resolveGoogleThinkingConfig(
|
|
1648
|
-
option: ProviderReasoningOption | undefined,
|
|
1649
|
-
): Record<string, unknown> | undefined {
|
|
1650
|
-
if (!option || option.enabled !== true) {
|
|
1651
|
-
return undefined;
|
|
1652
|
-
}
|
|
1653
|
-
const config: Record<string, unknown> = { includeThoughts: true };
|
|
1654
|
-
if (typeof option.budgetTokens === "number") {
|
|
1655
|
-
config.thinkingBudget = option.budgetTokens;
|
|
1656
|
-
return config;
|
|
1657
|
-
}
|
|
1658
|
-
switch (option.effort) {
|
|
1659
|
-
case "low":
|
|
1660
|
-
config.thinkingBudget = 512;
|
|
1661
|
-
break;
|
|
1662
|
-
case "high":
|
|
1663
|
-
config.thinkingBudget = 8192;
|
|
1664
|
-
break;
|
|
1665
|
-
case "max":
|
|
1666
|
-
config.thinkingBudget = -1;
|
|
1667
|
-
break;
|
|
1668
|
-
case "medium":
|
|
1669
|
-
default:
|
|
1670
|
-
config.thinkingBudget = 2048;
|
|
1671
|
-
break;
|
|
1672
|
-
}
|
|
1673
|
-
return config;
|
|
1674
|
-
}
|
|
1675
|
-
|
|
1676
|
-
function buildGoogleGenerationConfig(
|
|
1677
|
-
options: OpenAICompatibleLanguageOptions,
|
|
1678
|
-
): Record<string, unknown> | undefined {
|
|
1679
|
-
const thinkingConfig = resolveGoogleThinkingConfig(options.reasoning);
|
|
1680
|
-
const config: Record<string, unknown> = {
|
|
1681
|
-
...(options.maxOutputTokens !== undefined ? { maxOutputTokens: options.maxOutputTokens } : {}),
|
|
1682
|
-
...(options.temperature !== undefined ? { temperature: options.temperature } : {}),
|
|
1683
|
-
...(options.topP !== undefined ? { topP: options.topP } : {}),
|
|
1684
|
-
...(options.topK !== undefined ? { topK: options.topK } : {}),
|
|
1685
|
-
...(options.stopSequences && options.stopSequences.length > 0
|
|
1686
|
-
? { stopSequences: options.stopSequences }
|
|
1687
|
-
: {}),
|
|
1688
|
-
...(options.seed !== undefined ? { seed: options.seed } : {}),
|
|
1689
|
-
...(thinkingConfig ? { thinkingConfig } : {}),
|
|
1690
|
-
};
|
|
1691
|
-
|
|
1692
|
-
return Object.keys(config).length > 0 ? config : undefined;
|
|
1693
|
-
}
|
|
1694
|
-
|
|
1695
|
-
function buildGoogleGenerateContentRequest(
|
|
1696
|
-
providerName: string,
|
|
1697
|
-
options: OpenAICompatibleLanguageOptions,
|
|
1698
|
-
warnings: WarningCollector,
|
|
1699
|
-
): GoogleCompatibleRequest {
|
|
1700
|
-
// Google generate-content surface doesn't accept presence/frequency
|
|
1701
|
-
// penalties on most current models. Emit warnings and let the request
|
|
1702
|
-
// through without them.
|
|
1703
|
-
if (options.presencePenalty !== undefined) {
|
|
1704
|
-
warnings.push({
|
|
1705
|
-
type: "unsupported-setting",
|
|
1706
|
-
provider: "google",
|
|
1707
|
-
setting: "presencePenalty",
|
|
1708
|
-
details: "Gemini generateContent does not accept presencePenalty; the value was dropped.",
|
|
1709
|
-
});
|
|
1710
|
-
}
|
|
1711
|
-
if (options.frequencyPenalty !== undefined) {
|
|
1712
|
-
warnings.push({
|
|
1713
|
-
type: "unsupported-setting",
|
|
1714
|
-
provider: "google",
|
|
1715
|
-
setting: "frequencyPenalty",
|
|
1716
|
-
details: "Gemini generateContent does not accept frequencyPenalty; the value was dropped.",
|
|
1717
|
-
});
|
|
1718
|
-
}
|
|
1719
|
-
if (options.responseFormat && options.responseFormat.type !== "text") {
|
|
1720
|
-
warnings.push({
|
|
1721
|
-
type: "unsupported-setting",
|
|
1722
|
-
provider: "google",
|
|
1723
|
-
setting: "responseFormat",
|
|
1724
|
-
details:
|
|
1725
|
-
"Gemini uses generationConfig.responseMimeType + responseSchema for structured outputs, which is a separate surface and not yet wired through this option.",
|
|
1726
|
-
});
|
|
1727
|
-
}
|
|
1728
|
-
|
|
1729
|
-
const { systemInstruction, contents } = toGoogleContents(options.prompt);
|
|
1730
|
-
const generationConfig = buildGoogleGenerationConfig(options);
|
|
1731
|
-
// requestLabels wins over userId-derived labels: when callers explicitly
|
|
1732
|
-
// provide a label map, that's the source of truth. Otherwise fall back
|
|
1733
|
-
// to {user_id} derived from the unified userId option.
|
|
1734
|
-
const labels = options.requestLabels && Object.keys(options.requestLabels).length > 0
|
|
1735
|
-
? options.requestLabels
|
|
1736
|
-
: typeof options.userId === "string" && options.userId.length > 0
|
|
1737
|
-
? { user_id: options.userId }
|
|
1738
|
-
: undefined;
|
|
1739
|
-
const body: GoogleCompatibleRequest = {
|
|
1740
|
-
contents,
|
|
1741
|
-
...(systemInstruction ? { systemInstruction } : {}),
|
|
1742
|
-
...(toGoogleTools(options.tools) ? { tools: toGoogleTools(options.tools) } : {}),
|
|
1743
|
-
...(normalizeGoogleToolChoice(options.toolChoice)
|
|
1744
|
-
? { toolConfig: normalizeGoogleToolChoice(options.toolChoice) }
|
|
1745
|
-
: {}),
|
|
1746
|
-
...(generationConfig ? { generationConfig } : {}),
|
|
1747
|
-
...(labels ? { labels } : {}),
|
|
1748
|
-
...(typeof options.googleCachedContent === "string" && options.googleCachedContent.length > 0
|
|
1749
|
-
? { cachedContent: options.googleCachedContent }
|
|
1750
|
-
: {}),
|
|
1751
|
-
...(options.googleSafetySettings && options.googleSafetySettings.length > 0
|
|
1752
|
-
? { safetySettings: options.googleSafetySettings }
|
|
1753
|
-
: {}),
|
|
1754
|
-
};
|
|
1755
|
-
|
|
1756
|
-
Object.assign(body, readProviderOptions(options.providerOptions, "google", providerName));
|
|
1757
|
-
return body;
|
|
1758
|
-
}
|
|
1759
|
-
|
|
1760
|
-
function extractFirstGoogleCandidate(payload: unknown): Record<string, unknown> | undefined {
|
|
1761
|
-
const record = readRecord(payload);
|
|
1762
|
-
const candidates = record?.candidates;
|
|
1763
|
-
if (!Array.isArray(candidates) || candidates.length === 0) {
|
|
1764
|
-
return undefined;
|
|
1765
|
-
}
|
|
1766
|
-
|
|
1767
|
-
return readRecord(candidates[0]);
|
|
1768
|
-
}
|
|
1769
|
-
|
|
1770
|
-
function extractGoogleCandidateParts(payload: unknown): Array<Record<string, unknown>> {
|
|
1771
|
-
const candidate = extractFirstGoogleCandidate(payload);
|
|
1772
|
-
const content = readRecord(candidate?.content);
|
|
1773
|
-
const parts = content?.parts;
|
|
1774
|
-
if (!Array.isArray(parts)) {
|
|
1775
|
-
return [];
|
|
1776
|
-
}
|
|
1777
|
-
|
|
1778
|
-
return parts.flatMap((part) => {
|
|
1779
|
-
const record = readRecord(part);
|
|
1780
|
-
return record ? [record] : [];
|
|
1781
|
-
});
|
|
1782
|
-
}
|
|
1783
|
-
|
|
1784
|
-
function buildGoogleGenerateResult(payload: unknown): {
|
|
1785
|
-
content: Array<
|
|
1786
|
-
| { type: "text"; text: string }
|
|
1787
|
-
| { type: "tool-call"; toolCallId: string; toolName: string; input: string }
|
|
1788
|
-
>;
|
|
1789
|
-
finishReason?: string | { unified: string; raw: string } | null;
|
|
1790
|
-
usage?: RuntimeUsage;
|
|
1791
|
-
groundingMetadata?: Record<string, unknown>;
|
|
1792
|
-
} {
|
|
1793
|
-
const parts = extractGoogleCandidateParts(payload);
|
|
1794
|
-
const content: Array<
|
|
1795
|
-
| { type: "text"; text: string }
|
|
1796
|
-
| { type: "tool-call"; toolCallId: string; toolName: string; input: string }
|
|
1797
|
-
> = [];
|
|
1798
|
-
|
|
1799
|
-
for (const [index, part] of parts.entries()) {
|
|
1800
|
-
if (typeof part.text === "string" && part.text.length > 0) {
|
|
1801
|
-
content.push({ type: "text", text: part.text });
|
|
1802
|
-
continue;
|
|
1803
|
-
}
|
|
1804
|
-
|
|
1805
|
-
const functionCall = readRecord(part.functionCall);
|
|
1806
|
-
if (typeof functionCall?.name === "string") {
|
|
1807
|
-
content.push({
|
|
1808
|
-
type: "tool-call",
|
|
1809
|
-
toolCallId: typeof functionCall.id === "string" ? functionCall.id : `tool-${index}`,
|
|
1810
|
-
toolName: functionCall.name,
|
|
1811
|
-
input: stringifyJsonValue(functionCall.args ?? {}),
|
|
1812
|
-
});
|
|
1813
|
-
}
|
|
1814
|
-
}
|
|
1815
|
-
|
|
1816
|
-
// Gemini grounding (google_search / google_search_retrieval) returns
|
|
1817
|
-
// a per-candidate groundingMetadata object with web search queries,
|
|
1818
|
-
// grounding chunks, and citation indices into the response text.
|
|
1819
|
-
// Pass it through opaquely so callers can render footnotes / source
|
|
1820
|
-
// chips / "Search results" UI without parsing the wire shape.
|
|
1821
|
-
const candidate = extractFirstGoogleCandidate(payload);
|
|
1822
|
-
const groundingMetadata = readRecord(candidate?.groundingMetadata);
|
|
1823
|
-
|
|
1824
|
-
return {
|
|
1825
|
-
content,
|
|
1826
|
-
finishReason: normalizeGoogleFinishReason(candidate?.finishReason),
|
|
1827
|
-
usage: extractGoogleUsage(payload),
|
|
1828
|
-
...(groundingMetadata ? { groundingMetadata } : {}),
|
|
1829
|
-
};
|
|
1830
|
-
}
|
|
1831
|
-
|
|
1832
|
-
async function* streamGoogleCompatibleParts(
|
|
1833
|
-
stream: ReadableStream<Uint8Array>,
|
|
1834
|
-
): AsyncIterable<unknown> {
|
|
1835
|
-
const decoder = new TextDecoder();
|
|
1836
|
-
let buffer = "";
|
|
1837
|
-
const seenToolCalls = new Set<string>();
|
|
1838
|
-
let reasoningId: string | null = null;
|
|
1839
|
-
let reasoningIndex = 0;
|
|
1840
|
-
let finishReason: string | { unified: string; raw: string } | null = null;
|
|
1841
|
-
let usage: RuntimeUsage | undefined;
|
|
1842
|
-
|
|
1843
|
-
for await (const chunk of stream) {
|
|
1844
|
-
buffer += decoder.decode(chunk, { stream: true });
|
|
1845
|
-
const parsed = parseSseChunk(buffer);
|
|
1846
|
-
buffer = parsed.remainder;
|
|
1847
|
-
|
|
1848
|
-
for (const event of parsed.events) {
|
|
1849
|
-
if (event === "[DONE]") {
|
|
1850
|
-
continue;
|
|
1851
|
-
}
|
|
1852
|
-
|
|
1853
|
-
usage = extractGoogleUsage(event) ?? usage;
|
|
1854
|
-
const candidate = extractFirstGoogleCandidate(event);
|
|
1855
|
-
const normalizedFinishReason = normalizeGoogleFinishReason(candidate?.finishReason);
|
|
1856
|
-
if (normalizedFinishReason) {
|
|
1857
|
-
finishReason = normalizedFinishReason;
|
|
1858
|
-
}
|
|
1859
|
-
|
|
1860
|
-
for (const [index, part] of extractGoogleCandidateParts(event).entries()) {
|
|
1861
|
-
const isThought = part.thought === true;
|
|
1862
|
-
if (isThought && typeof part.text === "string" && part.text.length > 0) {
|
|
1863
|
-
if (!reasoningId) {
|
|
1864
|
-
reasoningId = `reasoning-${reasoningIndex++}`;
|
|
1865
|
-
yield {
|
|
1866
|
-
type: "reasoning-start",
|
|
1867
|
-
id: reasoningId,
|
|
1868
|
-
};
|
|
1869
|
-
}
|
|
1870
|
-
|
|
1871
|
-
yield {
|
|
1872
|
-
type: "reasoning-delta",
|
|
1873
|
-
id: reasoningId,
|
|
1874
|
-
delta: part.text,
|
|
1875
|
-
};
|
|
1876
|
-
continue;
|
|
1877
|
-
}
|
|
1878
|
-
|
|
1879
|
-
if (reasoningId) {
|
|
1880
|
-
yield {
|
|
1881
|
-
type: "reasoning-end",
|
|
1882
|
-
id: reasoningId,
|
|
1883
|
-
};
|
|
1884
|
-
reasoningId = null;
|
|
1885
|
-
}
|
|
1886
|
-
|
|
1887
|
-
if (typeof part.text === "string" && part.text.length > 0) {
|
|
1888
|
-
yield { type: "text-delta", delta: part.text };
|
|
1889
|
-
continue;
|
|
1890
|
-
}
|
|
1891
|
-
|
|
1892
|
-
const functionCall = readRecord(part.functionCall);
|
|
1893
|
-
if (typeof functionCall?.name !== "string") {
|
|
1894
|
-
continue;
|
|
1895
|
-
}
|
|
1896
|
-
|
|
1897
|
-
const toolCallId = typeof functionCall.id === "string" ? functionCall.id : `tool-${index}`;
|
|
1898
|
-
if (seenToolCalls.has(toolCallId)) {
|
|
1899
|
-
continue;
|
|
1900
|
-
}
|
|
1901
|
-
|
|
1902
|
-
const serializedInput = stringifyJsonValue(functionCall.args ?? {});
|
|
1903
|
-
seenToolCalls.add(toolCallId);
|
|
1904
|
-
yield {
|
|
1905
|
-
type: "tool-input-start",
|
|
1906
|
-
id: toolCallId,
|
|
1907
|
-
toolName: functionCall.name,
|
|
1908
|
-
};
|
|
1909
|
-
yield {
|
|
1910
|
-
type: "tool-input-delta",
|
|
1911
|
-
id: toolCallId,
|
|
1912
|
-
delta: serializedInput,
|
|
1913
|
-
};
|
|
1914
|
-
yield {
|
|
1915
|
-
type: "tool-call",
|
|
1916
|
-
toolCallId,
|
|
1917
|
-
toolName: functionCall.name,
|
|
1918
|
-
input: serializedInput,
|
|
1919
|
-
};
|
|
1920
|
-
}
|
|
1921
|
-
}
|
|
1922
|
-
}
|
|
1923
|
-
|
|
1924
|
-
if (buffer.trim().length > 0) {
|
|
1925
|
-
const parsed = parseSseChunk(`${buffer}\n\n`);
|
|
1926
|
-
for (const event of parsed.events) {
|
|
1927
|
-
if (event === "[DONE]") {
|
|
1928
|
-
continue;
|
|
1929
|
-
}
|
|
1930
|
-
usage = extractGoogleUsage(event) ?? usage;
|
|
1931
|
-
}
|
|
1932
|
-
}
|
|
1933
|
-
|
|
1934
|
-
if (reasoningId) {
|
|
1935
|
-
yield {
|
|
1936
|
-
type: "reasoning-end",
|
|
1937
|
-
id: reasoningId,
|
|
1938
|
-
};
|
|
1939
|
-
}
|
|
1940
|
-
|
|
1941
|
-
yield {
|
|
1942
|
-
type: "finish",
|
|
1943
|
-
finishReason,
|
|
1944
|
-
...(usage ? { usage } : {}),
|
|
1945
|
-
};
|
|
1946
|
-
}
|
|
1947
|
-
|
|
1948
1405
|
export function createAnthropicModelRuntime(
|
|
1949
1406
|
config: AnthropicRuntimeConfig,
|
|
1950
1407
|
modelId: string,
|
|
@@ -2022,124 +1479,3 @@ export function createAnthropicModelRuntime(
|
|
|
2022
1479
|
},
|
|
2023
1480
|
};
|
|
2024
1481
|
}
|
|
2025
|
-
|
|
2026
|
-
export function createGoogleModelRuntime(
|
|
2027
|
-
config: GoogleRuntimeConfig,
|
|
2028
|
-
modelId: string,
|
|
2029
|
-
): ModelRuntime {
|
|
2030
|
-
const fetchImpl = config.fetch ?? globalThis.fetch;
|
|
2031
|
-
return {
|
|
2032
|
-
provider: config.name ?? "google",
|
|
2033
|
-
modelId,
|
|
2034
|
-
specificationVersion: "v3",
|
|
2035
|
-
supportedUrls: {},
|
|
2036
|
-
doGenerate(optionsForRuntime: unknown) {
|
|
2037
|
-
const options = optionsForRuntime as OpenAICompatibleLanguageOptions;
|
|
2038
|
-
const url = getGoogleGenerateContentUrl(config.baseURL, modelId);
|
|
2039
|
-
const warnings = createWarningCollector();
|
|
2040
|
-
const body = buildGoogleGenerateContentRequest(
|
|
2041
|
-
config.name ?? "google",
|
|
2042
|
-
options,
|
|
2043
|
-
warnings,
|
|
2044
|
-
);
|
|
2045
|
-
return requestJson({
|
|
2046
|
-
url,
|
|
2047
|
-
fetchImpl,
|
|
2048
|
-
providerLabel: config.name ?? "google",
|
|
2049
|
-
providerKind: "google",
|
|
2050
|
-
init: createGoogleRequestInit({
|
|
2051
|
-
apiKey: config.apiKey,
|
|
2052
|
-
extraHeaders: options.headers,
|
|
2053
|
-
body: JSON.stringify(body),
|
|
2054
|
-
signal: options.abortSignal,
|
|
2055
|
-
}),
|
|
2056
|
-
}).then((payload) => {
|
|
2057
|
-
const drained = warnings.drain();
|
|
2058
|
-
return {
|
|
2059
|
-
...buildGoogleGenerateResult(payload),
|
|
2060
|
-
...(drained.length > 0 ? { warnings: drained } : {}),
|
|
2061
|
-
};
|
|
2062
|
-
});
|
|
2063
|
-
},
|
|
2064
|
-
doStream(optionsForRuntime: unknown) {
|
|
2065
|
-
const options = optionsForRuntime as OpenAICompatibleLanguageOptions;
|
|
2066
|
-
const url = getGoogleStreamGenerateContentUrl(config.baseURL, modelId);
|
|
2067
|
-
const warnings = createWarningCollector();
|
|
2068
|
-
const body = buildGoogleGenerateContentRequest(
|
|
2069
|
-
config.name ?? "google",
|
|
2070
|
-
options,
|
|
2071
|
-
warnings,
|
|
2072
|
-
);
|
|
2073
|
-
return requestStream({
|
|
2074
|
-
url,
|
|
2075
|
-
fetchImpl,
|
|
2076
|
-
providerLabel: config.name ?? "google",
|
|
2077
|
-
providerKind: "google",
|
|
2078
|
-
init: createGoogleRequestInit({
|
|
2079
|
-
apiKey: config.apiKey,
|
|
2080
|
-
extraHeaders: options.headers,
|
|
2081
|
-
body: JSON.stringify(body),
|
|
2082
|
-
signal: options.abortSignal,
|
|
2083
|
-
}),
|
|
2084
|
-
}).then((responseStream) => {
|
|
2085
|
-
const drained = warnings.drain();
|
|
2086
|
-
return {
|
|
2087
|
-
stream: ReadableStream.from(
|
|
2088
|
-
withToolInputStatusTransitions(streamGoogleCompatibleParts(responseStream)),
|
|
2089
|
-
),
|
|
2090
|
-
...(drained.length > 0 ? { warnings: drained } : {}),
|
|
2091
|
-
};
|
|
2092
|
-
});
|
|
2093
|
-
},
|
|
2094
|
-
};
|
|
2095
|
-
}
|
|
2096
|
-
|
|
2097
|
-
export function createGoogleEmbeddingRuntime(
|
|
2098
|
-
config: GoogleRuntimeConfig,
|
|
2099
|
-
modelId: string,
|
|
2100
|
-
): EmbeddingRuntime {
|
|
2101
|
-
const fetchImpl = config.fetch ?? globalThis.fetch;
|
|
2102
|
-
return {
|
|
2103
|
-
provider: config.name ?? "google",
|
|
2104
|
-
modelId,
|
|
2105
|
-
supportsParallelCalls: true,
|
|
2106
|
-
doEmbed({ values, abortSignal }) {
|
|
2107
|
-
if (values.length === 0) {
|
|
2108
|
-
return Promise.resolve({
|
|
2109
|
-
embeddings: [],
|
|
2110
|
-
warnings: [],
|
|
2111
|
-
rawResponse: { embeddings: [] },
|
|
2112
|
-
});
|
|
2113
|
-
}
|
|
2114
|
-
|
|
2115
|
-
const url = getGoogleEmbeddingUrl(config.baseURL, modelId);
|
|
2116
|
-
return Promise.all(values.map((value) =>
|
|
2117
|
-
requestJson({
|
|
2118
|
-
url,
|
|
2119
|
-
fetchImpl,
|
|
2120
|
-
providerLabel: config.name ?? "google",
|
|
2121
|
-
providerKind: "google",
|
|
2122
|
-
init: createGoogleRequestInit({
|
|
2123
|
-
apiKey: config.apiKey,
|
|
2124
|
-
body: JSON.stringify({
|
|
2125
|
-
content: {
|
|
2126
|
-
parts: [{ text: value }],
|
|
2127
|
-
},
|
|
2128
|
-
}),
|
|
2129
|
-
signal: abortSignal,
|
|
2130
|
-
}),
|
|
2131
|
-
})
|
|
2132
|
-
)).then((payloads) => ({
|
|
2133
|
-
embeddings: payloads.map(extractGoogleEmbedding),
|
|
2134
|
-
usage: {
|
|
2135
|
-
tokens: payloads.reduce<number>(
|
|
2136
|
-
(total, payload) => total + (extractGoogleUsageTokens(payload) ?? 0),
|
|
2137
|
-
0,
|
|
2138
|
-
),
|
|
2139
|
-
},
|
|
2140
|
-
rawResponse: payloads,
|
|
2141
|
-
warnings: [],
|
|
2142
|
-
}));
|
|
2143
|
-
},
|
|
2144
|
-
};
|
|
2145
|
-
}
|