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.
Files changed (43) hide show
  1. package/esm/deno.d.ts +11 -0
  2. package/esm/deno.js +13 -1
  3. package/esm/src/agent/index.d.ts +2 -0
  4. package/esm/src/agent/index.d.ts.map +1 -1
  5. package/esm/src/agent/index.js +2 -0
  6. package/esm/src/agent/project-context.d.ts +8 -0
  7. package/esm/src/agent/project-context.d.ts.map +1 -0
  8. package/esm/src/agent/project-context.js +40 -0
  9. package/esm/src/agent/project-steering-mutation.d.ts +23 -0
  10. package/esm/src/agent/project-steering-mutation.d.ts.map +1 -0
  11. package/esm/src/agent/project-steering-mutation.js +72 -0
  12. package/esm/src/embedding/resolve.d.ts.map +1 -1
  13. package/esm/src/embedding/resolve.js +11 -2
  14. package/esm/src/embedding/veryfront-cloud/provider.d.ts.map +1 -1
  15. package/esm/src/embedding/veryfront-cloud/provider.js +18 -8
  16. package/esm/src/provider/model-registry.d.ts.map +1 -1
  17. package/esm/src/provider/model-registry.js +11 -2
  18. package/esm/src/provider/runtime-loader.d.ts +6 -11
  19. package/esm/src/provider/runtime-loader.d.ts.map +1 -1
  20. package/esm/src/provider/runtime-loader.js +7 -512
  21. package/esm/src/provider/shared/index.d.ts +2 -2
  22. package/esm/src/provider/shared/index.d.ts.map +1 -1
  23. package/esm/src/provider/shared/index.js +1 -1
  24. package/esm/src/provider/veryfront-cloud/provider.d.ts.map +1 -1
  25. package/esm/src/provider/veryfront-cloud/provider.js +14 -11
  26. package/esm/src/utils/version-constant.d.ts +1 -1
  27. package/esm/src/utils/version-constant.js +1 -1
  28. package/package.json +1 -1
  29. package/src/deno.js +13 -1
  30. package/src/deps/esm.sh/@types/react-dom@19.2.3/client.d.ts +1 -1
  31. package/src/deps/esm.sh/@types/{react@19.2.3 → react@19.2.14}/global.d.ts +1 -0
  32. package/src/deps/esm.sh/@types/{react@19.2.3 → react@19.2.14}/index.d.ts +93 -24
  33. package/src/deps/esm.sh/react-dom@19.2.4/client.d.ts +1 -1
  34. package/src/src/agent/index.ts +15 -0
  35. package/src/src/agent/project-context.ts +63 -0
  36. package/src/src/agent/project-steering-mutation.ts +126 -0
  37. package/src/src/embedding/resolve.ts +14 -2
  38. package/src/src/embedding/veryfront-cloud/provider.ts +22 -8
  39. package/src/src/provider/model-registry.ts +14 -2
  40. package/src/src/provider/runtime-loader.ts +8 -672
  41. package/src/src/provider/shared/index.ts +4 -0
  42. package/src/src/provider/veryfront-cloud/provider.ts +16 -11
  43. package/src/src/utils/version-constant.ts +1 -1
@@ -1,27 +1,11 @@
1
- import type { EmbeddingRuntime, ModelRuntime } from "./types.js";
2
- import {
3
- getAnthropicMessagesUrl,
4
- getGoogleEmbeddingUrl,
5
- getGoogleGenerateContentUrl,
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 toGoogleContents(
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
- }