@modular-prompt/driver 0.11.15 → 0.13.1
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 +25 -0
- package/dist/anthropic/anthropic-driver.d.ts +38 -8
- package/dist/anthropic/anthropic-driver.d.ts.map +1 -1
- package/dist/anthropic/anthropic-driver.js +180 -164
- package/dist/anthropic/anthropic-driver.js.map +1 -1
- package/dist/cache-controller.d.ts +28 -0
- package/dist/cache-controller.d.ts.map +1 -0
- package/dist/cache-controller.js +2 -0
- package/dist/cache-controller.js.map +1 -0
- package/dist/cache-utils.d.ts +20 -0
- package/dist/cache-utils.d.ts.map +1 -0
- package/dist/cache-utils.js +71 -0
- package/dist/cache-utils.js.map +1 -0
- package/dist/content-utils.d.ts +9 -0
- package/dist/content-utils.d.ts.map +1 -1
- package/dist/content-utils.js +47 -0
- package/dist/content-utils.js.map +1 -1
- package/dist/driver-registry/config-based-factory.d.ts.map +1 -1
- package/dist/driver-registry/config-based-factory.js +7 -0
- package/dist/driver-registry/config-based-factory.js.map +1 -1
- package/dist/driver-registry/factory-helper.d.ts.map +1 -1
- package/dist/driver-registry/factory-helper.js +7 -4
- package/dist/driver-registry/factory-helper.js.map +1 -1
- package/dist/driver-registry/types.d.ts +6 -0
- package/dist/driver-registry/types.d.ts.map +1 -1
- package/dist/formatter/converter.js +1 -1
- package/dist/formatter/converter.js.map +1 -1
- package/dist/google-genai/element-converter.d.ts +11 -0
- package/dist/google-genai/element-converter.d.ts.map +1 -0
- package/dist/google-genai/element-converter.js +126 -0
- package/dist/google-genai/element-converter.js.map +1 -0
- package/dist/google-genai/google-genai-cache-controller.d.ts +24 -0
- package/dist/google-genai/google-genai-cache-controller.d.ts.map +1 -0
- package/dist/google-genai/google-genai-cache-controller.js +127 -0
- package/dist/google-genai/google-genai-cache-controller.js.map +1 -0
- package/dist/google-genai/google-genai-driver.d.ts +5 -29
- package/dist/google-genai/google-genai-driver.d.ts.map +1 -1
- package/dist/google-genai/google-genai-driver.js +92 -255
- package/dist/google-genai/google-genai-driver.js.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/mlx-ml/mlx-cache-controller.d.ts +66 -0
- package/dist/mlx-ml/mlx-cache-controller.d.ts.map +1 -0
- package/dist/mlx-ml/mlx-cache-controller.js +600 -0
- package/dist/mlx-ml/mlx-cache-controller.js.map +1 -0
- package/dist/mlx-ml/mlx-driver.d.ts +13 -8
- package/dist/mlx-ml/mlx-driver.d.ts.map +1 -1
- package/dist/mlx-ml/mlx-driver.js +202 -143
- package/dist/mlx-ml/mlx-driver.js.map +1 -1
- package/dist/mlx-ml/mlx-message-utils.d.ts +9 -0
- package/dist/mlx-ml/mlx-message-utils.d.ts.map +1 -0
- package/dist/mlx-ml/mlx-message-utils.js +71 -0
- package/dist/mlx-ml/mlx-message-utils.js.map +1 -0
- package/dist/mlx-ml/process/harmony-parser.d.ts +3 -0
- package/dist/mlx-ml/process/harmony-parser.d.ts.map +1 -0
- package/dist/mlx-ml/process/harmony-parser.js +175 -0
- package/dist/mlx-ml/process/harmony-parser.js.map +1 -0
- package/dist/mlx-ml/process/index.d.ts +7 -3
- package/dist/mlx-ml/process/index.d.ts.map +1 -1
- package/dist/mlx-ml/process/index.js +22 -7
- package/dist/mlx-ml/process/index.js.map +1 -1
- package/dist/mlx-ml/process/model-handlers.d.ts +11 -58
- package/dist/mlx-ml/process/model-handlers.d.ts.map +1 -1
- package/dist/mlx-ml/process/model-handlers.js +29 -11
- package/dist/mlx-ml/process/model-handlers.js.map +1 -1
- package/dist/mlx-ml/process/model-specific.d.ts +7 -0
- package/dist/mlx-ml/process/model-specific.d.ts.map +1 -1
- package/dist/mlx-ml/process/model-specific.js +3 -0
- package/dist/mlx-ml/process/model-specific.js.map +1 -1
- package/dist/mlx-ml/process/parameter-validator.d.ts.map +1 -1
- package/dist/mlx-ml/process/parameter-validator.js +10 -3
- package/dist/mlx-ml/process/parameter-validator.js.map +1 -1
- package/dist/mlx-ml/process/process-communication.d.ts +3 -0
- package/dist/mlx-ml/process/process-communication.d.ts.map +1 -1
- package/dist/mlx-ml/process/process-communication.js +13 -0
- package/dist/mlx-ml/process/process-communication.js.map +1 -1
- package/dist/mlx-ml/process/queue.d.ts +5 -2
- package/dist/mlx-ml/process/queue.d.ts.map +1 -1
- package/dist/mlx-ml/process/queue.js +103 -15
- package/dist/mlx-ml/process/queue.js.map +1 -1
- package/dist/mlx-ml/process/response-processor.d.ts +18 -0
- package/dist/mlx-ml/process/response-processor.d.ts.map +1 -0
- package/dist/mlx-ml/process/response-processor.js +24 -0
- package/dist/mlx-ml/process/response-processor.js.map +1 -0
- package/dist/mlx-ml/process/types.d.ts +51 -4
- package/dist/mlx-ml/process/types.d.ts.map +1 -1
- package/dist/mlx-ml/tool-call-parser.d.ts.map +1 -1
- package/dist/mlx-ml/tool-call-parser.js +44 -68
- package/dist/mlx-ml/tool-call-parser.js.map +1 -1
- package/dist/mlx-ml/types.d.ts +1 -0
- package/dist/mlx-ml/types.d.ts.map +1 -1
- package/dist/openai/openai-driver.d.ts +0 -2
- package/dist/openai/openai-driver.d.ts.map +1 -1
- package/dist/openai/openai-driver.js.map +1 -1
- package/dist/types.d.ts +9 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +7 -4
- package/src/mlx-ml/python/__main__.py +41 -425
- package/src/mlx-ml/python/backends/__init__.py +3 -0
- package/src/mlx-ml/python/backends/base.py +84 -0
- package/src/mlx-ml/python/backends/mlx_lm.py +202 -0
- package/src/mlx-ml/python/backends/mlx_vlm.py +99 -0
- package/src/mlx-ml/python/examples/example_basic.py +93 -0
- package/src/mlx-ml/python/examples/example_tool_call.py +165 -0
- package/src/mlx-ml/python/handlers/__init__.py +6 -0
- package/src/mlx-ml/python/handlers/cache.py +81 -0
- package/src/mlx-ml/python/handlers/capabilities.py +6 -0
- package/src/mlx-ml/python/handlers/chat.py +221 -0
- package/src/mlx-ml/python/handlers/completion.py +36 -0
- package/src/mlx-ml/python/handlers/format_test.py +70 -0
- package/src/mlx-ml/python/handlers/tokenize.py +63 -0
- package/src/mlx-ml/python/pyproject.toml +15 -5
- package/src/mlx-ml/python/server.py +126 -0
- package/src/mlx-ml/python/tests/__init__.py +0 -0
- package/src/mlx-ml/python/utils/__init__.py +0 -0
- package/src/mlx-ml/python/utils/prompt_builder.py +54 -0
- package/src/mlx-ml/python/{token_utils.py → utils/token_utils.py} +13 -5
- package/src/mlx-ml/python/uv.lock +299 -57
- /package/src/mlx-ml/python/{chat_template_constraints.py → utils/chat_template_constraints.py} +0 -0
- /package/src/mlx-ml/python/{vlm_utils.py → utils/vlm_utils.py} +0 -0
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { elementToPart, elementToContent, convertTools, mergeToolResultContents } from './element-converter.js';
|
|
3
|
+
function parseTtlSeconds(ttl) {
|
|
4
|
+
const match = ttl.match(/^(\d+)s$/);
|
|
5
|
+
if (!match) {
|
|
6
|
+
throw new Error(`Invalid TTL format "${ttl}": expected "<digits>s" (e.g. "3600s")`);
|
|
7
|
+
}
|
|
8
|
+
return Number(match[1]);
|
|
9
|
+
}
|
|
10
|
+
export class GoogleGenAICacheController {
|
|
11
|
+
client;
|
|
12
|
+
config;
|
|
13
|
+
managedCaches = new Set();
|
|
14
|
+
cacheByHash = new Map();
|
|
15
|
+
inflightRequests = new Map();
|
|
16
|
+
ttlSeconds;
|
|
17
|
+
normalizedTtl;
|
|
18
|
+
constructor(client, config) {
|
|
19
|
+
this.client = client;
|
|
20
|
+
this.config = config;
|
|
21
|
+
this.ttlSeconds = parseTtlSeconds(this.config?.ttl || '3600s');
|
|
22
|
+
this.normalizedTtl = `${this.ttlSeconds}s`;
|
|
23
|
+
}
|
|
24
|
+
computeCacheKey(params) {
|
|
25
|
+
const payload = { model: params.model };
|
|
26
|
+
if (params.instructions && params.instructions.length > 0) {
|
|
27
|
+
payload.systemInstruction = params.instructions.map(el => elementToPart(el));
|
|
28
|
+
}
|
|
29
|
+
if (params.data && params.data.length > 0) {
|
|
30
|
+
payload.contents = params.data.map(el => elementToContent(el));
|
|
31
|
+
}
|
|
32
|
+
if (params.tools && params.tools.length > 0) {
|
|
33
|
+
payload.tools = convertTools(params.tools);
|
|
34
|
+
}
|
|
35
|
+
return createHash('sha256').update(JSON.stringify(payload)).digest('hex');
|
|
36
|
+
}
|
|
37
|
+
sweepExpired() {
|
|
38
|
+
const now = Date.now();
|
|
39
|
+
for (const [key, entry] of this.cacheByHash) {
|
|
40
|
+
if ((now - entry.createdAt) / 1000 >= this.ttlSeconds) {
|
|
41
|
+
this.cacheByHash.delete(key);
|
|
42
|
+
this.managedCaches.delete(entry.handle.ref);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
recordQuery() {
|
|
47
|
+
// no-op: GoogleGenAI cache controller does not track query stats
|
|
48
|
+
}
|
|
49
|
+
async prepare(params) {
|
|
50
|
+
this.sweepExpired();
|
|
51
|
+
const cacheKey = this.computeCacheKey(params);
|
|
52
|
+
const existing = this.cacheByHash.get(cacheKey);
|
|
53
|
+
if (existing) {
|
|
54
|
+
return existing.handle;
|
|
55
|
+
}
|
|
56
|
+
const inflight = this.inflightRequests.get(cacheKey);
|
|
57
|
+
if (inflight) {
|
|
58
|
+
return inflight;
|
|
59
|
+
}
|
|
60
|
+
const promise = this.createCache(params, cacheKey);
|
|
61
|
+
this.inflightRequests.set(cacheKey, promise);
|
|
62
|
+
try {
|
|
63
|
+
return await promise;
|
|
64
|
+
}
|
|
65
|
+
finally {
|
|
66
|
+
this.inflightRequests.delete(cacheKey);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
async createCache(params, cacheKey) {
|
|
70
|
+
const cacheConfig = {
|
|
71
|
+
ttl: this.normalizedTtl,
|
|
72
|
+
displayName: this.config?.displayName,
|
|
73
|
+
};
|
|
74
|
+
if (params.instructions && params.instructions.length > 0) {
|
|
75
|
+
cacheConfig.systemInstruction = params.instructions.map(el => elementToPart(el));
|
|
76
|
+
}
|
|
77
|
+
if (params.data && params.data.length > 0) {
|
|
78
|
+
cacheConfig.contents = mergeToolResultContents(params.data.map(el => elementToContent(el)));
|
|
79
|
+
}
|
|
80
|
+
if (params.tools && params.tools.length > 0) {
|
|
81
|
+
cacheConfig.tools = convertTools(params.tools);
|
|
82
|
+
}
|
|
83
|
+
Object.keys(cacheConfig).forEach(key => {
|
|
84
|
+
if (cacheConfig[key] === undefined) {
|
|
85
|
+
delete cacheConfig[key];
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
const cache = await this.client.caches.create({
|
|
89
|
+
model: params.model,
|
|
90
|
+
config: cacheConfig,
|
|
91
|
+
});
|
|
92
|
+
if (!cache.name) {
|
|
93
|
+
throw new Error('GoogleGenAI caches.create() returned a cache without a name');
|
|
94
|
+
}
|
|
95
|
+
const ref = cache.name;
|
|
96
|
+
this.managedCaches.add(ref);
|
|
97
|
+
const handle = {
|
|
98
|
+
ref,
|
|
99
|
+
includes: {
|
|
100
|
+
instructions: (params.instructions?.length ?? 0) > 0,
|
|
101
|
+
dataElementCount: params.data?.length ?? 0,
|
|
102
|
+
tools: (params.tools?.length ?? 0) > 0,
|
|
103
|
+
},
|
|
104
|
+
};
|
|
105
|
+
this.cacheByHash.set(cacheKey, { handle, createdAt: Date.now() });
|
|
106
|
+
return handle;
|
|
107
|
+
}
|
|
108
|
+
async invalidate(handle) {
|
|
109
|
+
await this.client.caches.delete({ name: handle.ref });
|
|
110
|
+
this.managedCaches.delete(handle.ref);
|
|
111
|
+
for (const [key, entry] of this.cacheByHash) {
|
|
112
|
+
if (entry.handle.ref === handle.ref) {
|
|
113
|
+
this.cacheByHash.delete(key);
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
async close() {
|
|
119
|
+
await Promise.allSettled([...this.inflightRequests.values()]);
|
|
120
|
+
this.inflightRequests.clear();
|
|
121
|
+
const deletions = [...this.managedCaches].map(name => this.client.caches.delete({ name }).catch(() => { }));
|
|
122
|
+
await Promise.all(deletions);
|
|
123
|
+
this.managedCaches.clear();
|
|
124
|
+
this.cacheByHash.clear();
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=google-genai-cache-controller.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"google-genai-cache-controller.js","sourceRoot":"","sources":["../../src/google-genai/google-genai-cache-controller.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { CompiledPrompt } from '@modular-prompt/core';
|
|
2
2
|
import type { AIDriver, QueryOptions, QueryResult, StreamResult } from '../types.js';
|
|
3
|
+
import type { PromptCacheController } from '../cache-controller.js';
|
|
3
4
|
/**
|
|
4
5
|
* GoogleGenAI driver configuration
|
|
5
6
|
*/
|
|
@@ -8,6 +9,7 @@ export interface GoogleGenAIDriverConfig {
|
|
|
8
9
|
model?: string;
|
|
9
10
|
temperature?: number;
|
|
10
11
|
defaultOptions?: Partial<GoogleGenAIQueryOptions>;
|
|
12
|
+
cacheController?: PromptCacheController;
|
|
11
13
|
}
|
|
12
14
|
/**
|
|
13
15
|
* GoogleGenAI-specific query options
|
|
@@ -33,40 +35,14 @@ export declare class GoogleGenAIDriver implements AIDriver {
|
|
|
33
35
|
private defaultTemperature;
|
|
34
36
|
private _defaultOptions;
|
|
35
37
|
private queryLogger;
|
|
38
|
+
private cacheController?;
|
|
36
39
|
get defaultOptions(): Partial<GoogleGenAIQueryOptions>;
|
|
37
40
|
set defaultOptions(value: Partial<GoogleGenAIQueryOptions>);
|
|
38
41
|
constructor(config?: GoogleGenAIDriverConfig);
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
* Used for systemInstruction and simple data
|
|
42
|
-
*/
|
|
43
|
-
private elementToPart;
|
|
44
|
-
/**
|
|
45
|
-
* Convert kind+value to GoogleGenAI functionResponse
|
|
46
|
-
*/
|
|
47
|
-
private toFunctionResponsePayload;
|
|
48
|
-
/**
|
|
49
|
-
* Convert Element to Content (structure-preserving conversion)
|
|
50
|
-
* Used for conversation history where role matters
|
|
51
|
-
*/
|
|
52
|
-
private elementToContent;
|
|
53
|
-
/**
|
|
54
|
-
* Convert ChatMessage to GoogleGenAI Content format
|
|
55
|
-
*/
|
|
42
|
+
private buildPromptPayload;
|
|
43
|
+
private buildGenerationConfig;
|
|
56
44
|
private chatMessageToContent;
|
|
57
|
-
/**
|
|
58
|
-
* Merge consecutive tool result Contents into a single user message.
|
|
59
|
-
* Gemini API requires multiple functionResponses in one user message.
|
|
60
|
-
*/
|
|
61
|
-
private mergeToolResultContents;
|
|
62
|
-
/**
|
|
63
|
-
* Convert JSON Schema to GoogleGenAI Schema format
|
|
64
|
-
*/
|
|
65
45
|
private convertJsonSchema;
|
|
66
|
-
/**
|
|
67
|
-
* Convert ToolDefinition[] to GoogleGenAI tools format
|
|
68
|
-
*/
|
|
69
|
-
private convertTools;
|
|
70
46
|
/**
|
|
71
47
|
* Convert ToolChoice to GoogleGenAI FunctionCallingConfig
|
|
72
48
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"google-genai-driver.d.ts","sourceRoot":"","sources":["../../src/google-genai/google-genai-driver.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,
|
|
1
|
+
{"version":3,"file":"google-genai-driver.d.ts","sourceRoot":"","sources":["../../src/google-genai/google-genai-driver.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,WAAW,EAAE,YAAY,EAAqC,MAAM,aAAa,CAAC;AAIxH,OAAO,KAAK,EAAE,qBAAqB,EAAe,MAAM,wBAAwB,CAAC;AAIjF;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,OAAO,CAAC,uBAAuB,CAAC,CAAC;IAClD,eAAe,CAAC,EAAE,qBAAqB,CAAC;CACzC;AAED;;GAEG;AACH,MAAM,WAAW,uBAAwB,SAAQ,YAAY;IAC3D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,cAAc,CAAC,EAAE;QACf,aAAa,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;KAC3C,CAAC;CACH;AAmBD;;GAEG;AACH,qBAAa,iBAAkB,YAAW,QAAQ;IAChD,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,kBAAkB,CAAS;IACnC,OAAO,CAAC,eAAe,CAAmC;IAC1D,OAAO,CAAC,WAAW,CAAkC;IACrD,OAAO,CAAC,eAAe,CAAC,CAAwB;IAEhD,IAAI,cAAc,IAAI,OAAO,CAAC,uBAAuB,CAAC,CAErD;IAED,IAAI,cAAc,CAAC,KAAK,EAAE,OAAO,CAAC,uBAAuB,CAAC,EAEzD;gBAEW,MAAM,GAAE,uBAA4B;YAclC,kBAAkB;IAkDhC,OAAO,CAAC,qBAAqB;IAoD7B,OAAO,CAAC,oBAAoB;IAmC5B,OAAO,CAAC,iBAAiB;IAKzB;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAiBzB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAoBxB;;OAEG;IACG,KAAK,CACT,MAAM,EAAE,cAAc,EACtB,OAAO,GAAE,uBAA4B,GACpC,OAAO,CAAC,WAAW,CAAC;IAsEvB;;OAEG;IACG,WAAW,CACf,MAAM,EAAE,cAAc,EACtB,OAAO,CAAC,EAAE,uBAAuB,GAChC,OAAO,CAAC,YAAY,CAAC;IA2HxB;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAG7B"}
|
|
@@ -2,6 +2,8 @@ import { GoogleGenAI, FunctionCallingConfigMode } from '@google/genai';
|
|
|
2
2
|
import { hasToolCalls, isToolResult } from '../types.js';
|
|
3
3
|
import { contentToString } from '../content-utils.js';
|
|
4
4
|
import { QueryLogger } from '../query-logger.js';
|
|
5
|
+
import { partitionPrompt } from '../cache-utils.js';
|
|
6
|
+
import { elementToPart, elementToContent, toFunctionResponsePayload, convertTools, mergeToolResultContents } from './element-converter.js';
|
|
5
7
|
/**
|
|
6
8
|
* Map finish reasons from GoogleGenAI to our format
|
|
7
9
|
*/
|
|
@@ -27,6 +29,7 @@ export class GoogleGenAIDriver {
|
|
|
27
29
|
defaultTemperature;
|
|
28
30
|
_defaultOptions;
|
|
29
31
|
queryLogger = new QueryLogger('GoogleGenAI');
|
|
32
|
+
cacheController;
|
|
30
33
|
get defaultOptions() {
|
|
31
34
|
return this._defaultOptions;
|
|
32
35
|
}
|
|
@@ -42,212 +45,126 @@ export class GoogleGenAIDriver {
|
|
|
42
45
|
this.defaultModel = config.model || 'gemma-3-27b';
|
|
43
46
|
this.defaultTemperature = config.temperature ?? 0.7;
|
|
44
47
|
this._defaultOptions = config.defaultOptions || {};
|
|
48
|
+
this.cacheController = config.cacheController;
|
|
45
49
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
const chunkContent = contentToString(element.content);
|
|
74
|
-
const chunkHeader = element.index !== undefined && element.total !== undefined
|
|
75
|
-
? `[Chunk ${element.index + 1}/${element.total} of ${element.partOf}]`
|
|
76
|
-
: `[Chunk of ${element.partOf}]`;
|
|
77
|
-
return { text: `${chunkHeader}\n${chunkContent}` };
|
|
78
|
-
}
|
|
79
|
-
case 'section':
|
|
80
|
-
case 'subsection': {
|
|
81
|
-
// Section/SubSection elements should be compiled before reaching here
|
|
82
|
-
// If they do reach here, flatten their items recursively
|
|
83
|
-
const flattenItems = (items) => {
|
|
84
|
-
return items.map(item => {
|
|
85
|
-
if (typeof item === 'string')
|
|
86
|
-
return item;
|
|
87
|
-
if (typeof item === 'function')
|
|
88
|
-
return ''; // DynamicContent should be resolved before this point
|
|
89
|
-
return this.elementToPart(item).text || '';
|
|
90
|
-
}).filter(Boolean).join('\n');
|
|
91
|
-
};
|
|
92
|
-
return { text: flattenItems(element.items) };
|
|
50
|
+
async buildPromptPayload(prompt, mergedOptions, model) {
|
|
51
|
+
if (this.cacheController) {
|
|
52
|
+
const partition = partitionPrompt(prompt);
|
|
53
|
+
const hasCacheableContent = partition.cacheable.instructions.length > 0 ||
|
|
54
|
+
partition.cacheable.data.length > 0 ||
|
|
55
|
+
(mergedOptions.tools && mergedOptions.tools.length > 0);
|
|
56
|
+
if (hasCacheableContent) {
|
|
57
|
+
const handle = await this.cacheController.prepare({
|
|
58
|
+
model,
|
|
59
|
+
instructions: partition.cacheable.instructions,
|
|
60
|
+
data: partition.cacheable.data,
|
|
61
|
+
tools: mergedOptions.tools,
|
|
62
|
+
});
|
|
63
|
+
const instructionsForRequest = handle.includes.instructions
|
|
64
|
+
? partition.volatile.instructions
|
|
65
|
+
: [...partition.cacheable.instructions, ...partition.volatile.instructions];
|
|
66
|
+
const uncachedInstructionParts = instructionsForRequest.length > 0
|
|
67
|
+
? instructionsForRequest.map(el => elementToPart(el))
|
|
68
|
+
: undefined;
|
|
69
|
+
const dataForRequest = handle.includes.dataElementCount >= partition.cacheable.data.length
|
|
70
|
+
? partition.volatile.data
|
|
71
|
+
: [...partition.cacheable.data, ...partition.volatile.data];
|
|
72
|
+
const volatileElements = [...dataForRequest, ...partition.volatile.output];
|
|
73
|
+
const contents = volatileElements.length > 0
|
|
74
|
+
? mergeToolResultContents(volatileElements.map(el => elementToContent(el)))
|
|
75
|
+
: [{ parts: [{ text: 'Please process according to the instructions.' }] }];
|
|
76
|
+
return { systemInstructionParts: uncachedInstructionParts, contents, cacheHandle: handle };
|
|
93
77
|
}
|
|
94
|
-
case 'json':
|
|
95
|
-
return { text: typeof element.content === 'string' ? element.content : JSON.stringify(element.content, null, 2) };
|
|
96
|
-
default:
|
|
97
|
-
return { text: JSON.stringify(element) };
|
|
98
78
|
}
|
|
79
|
+
const systemInstructionParts = prompt.instructions?.map(el => elementToPart(el));
|
|
80
|
+
const allDataElements = [...(prompt.data || []), ...(prompt.output || [])];
|
|
81
|
+
const contents = allDataElements.length > 0
|
|
82
|
+
? mergeToolResultContents(allDataElements.map(el => elementToContent(el)))
|
|
83
|
+
: [{ parts: [{ text: 'Please process according to the instructions.' }] }];
|
|
84
|
+
return { systemInstructionParts, contents, cacheHandle: null };
|
|
99
85
|
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
86
|
+
buildGenerationConfig(mergedOptions, cacheHandle, systemInstructionParts, prompt) {
|
|
87
|
+
const config = {
|
|
88
|
+
temperature: mergedOptions.temperature ?? this.defaultTemperature,
|
|
89
|
+
maxOutputTokens: mergedOptions.maxTokens,
|
|
90
|
+
topP: mergedOptions.topP,
|
|
91
|
+
topK: mergedOptions.topK,
|
|
92
|
+
candidateCount: mergedOptions.candidateCount,
|
|
93
|
+
stopSequences: mergedOptions.stopSequences,
|
|
94
|
+
thinkingConfig: mergedOptions.thinkingConfig ??
|
|
95
|
+
(mergedOptions.mode === 'thinking' ? { thinkingLevel: 'HIGH' } : undefined),
|
|
96
|
+
};
|
|
97
|
+
if (cacheHandle) {
|
|
98
|
+
config.cachedContent = cacheHandle.ref;
|
|
99
|
+
if (!cacheHandle.includes.tools && mergedOptions.tools && mergedOptions.tools.length > 0) {
|
|
100
|
+
config.tools = convertTools(mergedOptions.tools);
|
|
101
|
+
}
|
|
106
102
|
}
|
|
107
|
-
else
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
return value;
|
|
103
|
+
else {
|
|
104
|
+
if (mergedOptions.tools && mergedOptions.tools.length > 0) {
|
|
105
|
+
config.tools = convertTools(mergedOptions.tools);
|
|
111
106
|
}
|
|
112
|
-
return { output: value };
|
|
113
107
|
}
|
|
114
|
-
|
|
115
|
-
|
|
108
|
+
if (systemInstructionParts && systemInstructionParts.length > 0) {
|
|
109
|
+
config.systemInstruction = systemInstructionParts;
|
|
116
110
|
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
* Used for conversation history where role matters
|
|
121
|
-
*/
|
|
122
|
-
elementToContent(element) {
|
|
123
|
-
if (typeof element === 'string') {
|
|
124
|
-
return { parts: [{ text: element }] };
|
|
111
|
+
if (prompt.metadata?.outputSchema) {
|
|
112
|
+
config.responseMimeType = 'application/json';
|
|
113
|
+
config.responseSchema = this.convertJsonSchema(prompt.metadata.outputSchema);
|
|
125
114
|
}
|
|
126
|
-
if (
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
return {
|
|
131
|
-
role: 'user',
|
|
132
|
-
parts: [{
|
|
133
|
-
functionResponse: {
|
|
134
|
-
name: toolResultEl.name,
|
|
135
|
-
response: this.toFunctionResponsePayload(toolResultEl.kind, toolResultEl.value)
|
|
136
|
-
}
|
|
137
|
-
}]
|
|
138
|
-
};
|
|
139
|
-
}
|
|
140
|
-
else if ('toolCalls' in element && element.toolCalls) {
|
|
141
|
-
const parts = [];
|
|
142
|
-
const content = contentToString(element.content);
|
|
143
|
-
if (content)
|
|
144
|
-
parts.push({ text: content });
|
|
145
|
-
for (const tc of element.toolCalls) {
|
|
146
|
-
parts.push({ functionCall: { name: tc.name, args: tc.arguments } });
|
|
147
|
-
}
|
|
148
|
-
return { role: 'model', parts };
|
|
149
|
-
}
|
|
150
|
-
else {
|
|
151
|
-
// Role conversion:
|
|
152
|
-
// - assistant → model
|
|
153
|
-
// - system → user (Gemini API doesn't support system role in contents)
|
|
154
|
-
// - user → user
|
|
155
|
-
const role = element.role === 'assistant' ? 'model' : 'user';
|
|
156
|
-
const messageContent = contentToString(element.content);
|
|
157
|
-
return {
|
|
158
|
-
role,
|
|
159
|
-
parts: [{ text: messageContent }]
|
|
160
|
-
};
|
|
161
|
-
}
|
|
115
|
+
if (mergedOptions.toolChoice) {
|
|
116
|
+
config.toolConfig = {
|
|
117
|
+
functionCallingConfig: this.convertToolChoice(mergedOptions.toolChoice),
|
|
118
|
+
};
|
|
162
119
|
}
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
120
|
+
Object.keys(config).forEach(key => {
|
|
121
|
+
if (config[key] === undefined) {
|
|
122
|
+
delete config[key];
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
return config;
|
|
167
126
|
}
|
|
168
|
-
/**
|
|
169
|
-
* Convert ChatMessage to GoogleGenAI Content format
|
|
170
|
-
*/
|
|
171
127
|
chatMessageToContent(message) {
|
|
172
128
|
if (hasToolCalls(message)) {
|
|
173
|
-
// AssistantToolCallMessage
|
|
174
129
|
const parts = [];
|
|
175
130
|
const textContent = contentToString(message.content);
|
|
176
131
|
if (textContent) {
|
|
177
132
|
parts.push({ text: textContent });
|
|
178
133
|
}
|
|
179
134
|
for (const tc of message.toolCalls) {
|
|
180
|
-
|
|
181
|
-
functionCall: {
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
}
|
|
135
|
+
const part = {
|
|
136
|
+
functionCall: { name: tc.name, args: tc.arguments }
|
|
137
|
+
};
|
|
138
|
+
if (typeof tc.metadata?.thoughtSignature === 'string') {
|
|
139
|
+
part.thoughtSignature = tc.metadata.thoughtSignature;
|
|
140
|
+
}
|
|
141
|
+
parts.push(part);
|
|
186
142
|
}
|
|
187
143
|
return { role: 'model', parts };
|
|
188
144
|
}
|
|
189
145
|
else if (isToolResult(message)) {
|
|
190
|
-
// ToolResultMessage
|
|
191
146
|
return {
|
|
192
147
|
role: 'user',
|
|
193
148
|
parts: [{
|
|
194
149
|
functionResponse: {
|
|
195
150
|
name: message.name,
|
|
196
|
-
response:
|
|
151
|
+
response: toFunctionResponsePayload(message.kind, message.value)
|
|
197
152
|
}
|
|
198
153
|
}]
|
|
199
154
|
};
|
|
200
155
|
}
|
|
201
156
|
else {
|
|
202
|
-
// StandardChatMessage
|
|
203
157
|
return {
|
|
204
158
|
role: message.role === 'assistant' ? 'model' : 'user',
|
|
205
159
|
parts: [{ text: contentToString(message.content) }]
|
|
206
160
|
};
|
|
207
161
|
}
|
|
208
162
|
}
|
|
209
|
-
/**
|
|
210
|
-
* Merge consecutive tool result Contents into a single user message.
|
|
211
|
-
* Gemini API requires multiple functionResponses in one user message.
|
|
212
|
-
*/
|
|
213
|
-
mergeToolResultContents(contents) {
|
|
214
|
-
const merged = [];
|
|
215
|
-
for (const c of contents) {
|
|
216
|
-
const prev = merged[merged.length - 1];
|
|
217
|
-
if (prev &&
|
|
218
|
-
c.role === 'user' &&
|
|
219
|
-
prev.role === 'user' &&
|
|
220
|
-
c.parts?.length === 1 && c.parts[0].functionResponse &&
|
|
221
|
-
prev.parts && prev.parts.length > 0 && prev.parts[0].functionResponse) {
|
|
222
|
-
prev.parts.push(c.parts[0]);
|
|
223
|
-
}
|
|
224
|
-
else {
|
|
225
|
-
merged.push(c);
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
return merged;
|
|
229
|
-
}
|
|
230
|
-
/**
|
|
231
|
-
* Convert JSON Schema to GoogleGenAI Schema format
|
|
232
|
-
*/
|
|
233
163
|
convertJsonSchema(schema) {
|
|
234
164
|
if (!schema || typeof schema !== 'object')
|
|
235
165
|
return undefined;
|
|
236
|
-
// GoogleGenAI uses a specific schema format
|
|
237
|
-
// For now, we'll pass it through and let the API handle it
|
|
238
166
|
return schema;
|
|
239
167
|
}
|
|
240
|
-
/**
|
|
241
|
-
* Convert ToolDefinition[] to GoogleGenAI tools format
|
|
242
|
-
*/
|
|
243
|
-
convertTools(tools) {
|
|
244
|
-
const functionDeclarations = tools.map(tool => ({
|
|
245
|
-
name: tool.name,
|
|
246
|
-
description: tool.description,
|
|
247
|
-
parametersJsonSchema: tool.parameters,
|
|
248
|
-
}));
|
|
249
|
-
return [{ functionDeclarations }];
|
|
250
|
-
}
|
|
251
168
|
/**
|
|
252
169
|
* Convert ToolChoice to GoogleGenAI FunctionCallingConfig
|
|
253
170
|
*/
|
|
@@ -277,11 +194,15 @@ export class GoogleGenAIDriver {
|
|
|
277
194
|
for (const part of parts) {
|
|
278
195
|
if (part.functionCall) {
|
|
279
196
|
const fc = part.functionCall;
|
|
280
|
-
|
|
197
|
+
const toolCall = {
|
|
281
198
|
id: fc.id || `call_${toolCalls.length}`,
|
|
282
199
|
name: fc.name || '',
|
|
283
200
|
arguments: fc.args ?? {},
|
|
284
|
-
}
|
|
201
|
+
};
|
|
202
|
+
if (typeof part.thoughtSignature === 'string') {
|
|
203
|
+
toolCall.metadata = { thoughtSignature: part.thoughtSignature };
|
|
204
|
+
}
|
|
205
|
+
toolCalls.push(toolCall);
|
|
285
206
|
}
|
|
286
207
|
}
|
|
287
208
|
return toolCalls;
|
|
@@ -294,52 +215,10 @@ export class GoogleGenAIDriver {
|
|
|
294
215
|
// Merge options with defaults
|
|
295
216
|
const mergedOptions = { ...this.defaultOptions, ...options };
|
|
296
217
|
this.queryLogger.mark(mergedOptions);
|
|
297
|
-
// Convert prompt to GoogleGenAI format
|
|
298
|
-
// Instructions → systemInstruction (Part[])
|
|
299
|
-
const systemInstructionParts = prompt.instructions?.map(el => this.elementToPart(el));
|
|
300
|
-
// Data + Output → contents (Content[])
|
|
301
|
-
const allDataElements = [...(prompt.data || []), ...(prompt.output || [])];
|
|
302
|
-
const contents = allDataElements.length > 0
|
|
303
|
-
? this.mergeToolResultContents(allDataElements.map(el => this.elementToContent(el)))
|
|
304
|
-
: [{ parts: [{ text: 'Please process according to the instructions.' }] }];
|
|
305
|
-
// Create generation config
|
|
306
|
-
const config = {
|
|
307
|
-
temperature: mergedOptions.temperature ?? this.defaultTemperature,
|
|
308
|
-
maxOutputTokens: mergedOptions.maxTokens,
|
|
309
|
-
topP: mergedOptions.topP,
|
|
310
|
-
topK: mergedOptions.topK,
|
|
311
|
-
candidateCount: mergedOptions.candidateCount,
|
|
312
|
-
stopSequences: mergedOptions.stopSequences,
|
|
313
|
-
thinkingConfig: mergedOptions.thinkingConfig ??
|
|
314
|
-
(mergedOptions.mode === 'thinking' ? { thinkingLevel: 'HIGH' } : undefined),
|
|
315
|
-
};
|
|
316
|
-
// Add system instruction if present
|
|
317
|
-
if (systemInstructionParts && systemInstructionParts.length > 0) {
|
|
318
|
-
config.systemInstruction = systemInstructionParts;
|
|
319
|
-
}
|
|
320
|
-
// Handle structured outputs
|
|
321
|
-
if (prompt.metadata?.outputSchema) {
|
|
322
|
-
config.responseMimeType = 'application/json';
|
|
323
|
-
config.responseSchema = this.convertJsonSchema(prompt.metadata.outputSchema);
|
|
324
|
-
}
|
|
325
|
-
// Add tools configuration
|
|
326
|
-
if (mergedOptions.tools && mergedOptions.tools.length > 0) {
|
|
327
|
-
config.tools = this.convertTools(mergedOptions.tools);
|
|
328
|
-
}
|
|
329
|
-
if (mergedOptions.toolChoice) {
|
|
330
|
-
config.toolConfig = {
|
|
331
|
-
functionCallingConfig: this.convertToolChoice(mergedOptions.toolChoice),
|
|
332
|
-
};
|
|
333
|
-
}
|
|
334
|
-
// Remove undefined values
|
|
335
|
-
Object.keys(config).forEach(key => {
|
|
336
|
-
if (config[key] === undefined) {
|
|
337
|
-
delete config[key];
|
|
338
|
-
}
|
|
339
|
-
});
|
|
340
|
-
// Get model name
|
|
341
218
|
const model = mergedOptions.model || this.defaultModel;
|
|
342
|
-
|
|
219
|
+
const { systemInstructionParts, contents, cacheHandle } = await this.buildPromptPayload(prompt, mergedOptions, model);
|
|
220
|
+
const config = this.buildGenerationConfig(mergedOptions, cacheHandle, systemInstructionParts, prompt);
|
|
221
|
+
this.cacheController?.recordQuery?.();
|
|
343
222
|
const response = await this.client.models.generateContent({
|
|
344
223
|
model,
|
|
345
224
|
contents,
|
|
@@ -399,52 +278,10 @@ export class GoogleGenAIDriver {
|
|
|
399
278
|
async streamQuery(prompt, options) {
|
|
400
279
|
const mergedOptions = { ...this.defaultOptions, ...options };
|
|
401
280
|
this.queryLogger.mark(mergedOptions);
|
|
402
|
-
// Convert prompt to GoogleGenAI format
|
|
403
|
-
// Instructions → systemInstruction (Part[])
|
|
404
|
-
const systemInstructionParts = prompt.instructions?.map(el => this.elementToPart(el));
|
|
405
|
-
// Data + Output → contents (Content[])
|
|
406
|
-
const allDataElements = [...(prompt.data || []), ...(prompt.output || [])];
|
|
407
|
-
const contents = allDataElements.length > 0
|
|
408
|
-
? allDataElements.map(el => this.elementToContent(el))
|
|
409
|
-
: [{ parts: [{ text: 'Please process according to the instructions.' }] }];
|
|
410
|
-
// Create generation config
|
|
411
|
-
const config = {
|
|
412
|
-
temperature: mergedOptions.temperature ?? this.defaultTemperature,
|
|
413
|
-
maxOutputTokens: mergedOptions.maxTokens,
|
|
414
|
-
topP: mergedOptions.topP,
|
|
415
|
-
topK: mergedOptions.topK,
|
|
416
|
-
candidateCount: mergedOptions.candidateCount,
|
|
417
|
-
stopSequences: mergedOptions.stopSequences,
|
|
418
|
-
thinkingConfig: mergedOptions.thinkingConfig ??
|
|
419
|
-
(mergedOptions.mode === 'thinking' ? { thinkingLevel: 'HIGH' } : undefined),
|
|
420
|
-
};
|
|
421
|
-
// Add system instruction if present
|
|
422
|
-
if (systemInstructionParts && systemInstructionParts.length > 0) {
|
|
423
|
-
config.systemInstruction = systemInstructionParts;
|
|
424
|
-
}
|
|
425
|
-
// Handle structured outputs
|
|
426
|
-
if (prompt.metadata?.outputSchema) {
|
|
427
|
-
config.responseMimeType = 'application/json';
|
|
428
|
-
config.responseSchema = this.convertJsonSchema(prompt.metadata.outputSchema);
|
|
429
|
-
}
|
|
430
|
-
// Add tools configuration
|
|
431
|
-
if (mergedOptions.tools && mergedOptions.tools.length > 0) {
|
|
432
|
-
config.tools = this.convertTools(mergedOptions.tools);
|
|
433
|
-
}
|
|
434
|
-
if (mergedOptions.toolChoice) {
|
|
435
|
-
config.toolConfig = {
|
|
436
|
-
functionCallingConfig: this.convertToolChoice(mergedOptions.toolChoice),
|
|
437
|
-
};
|
|
438
|
-
}
|
|
439
|
-
// Remove undefined values
|
|
440
|
-
Object.keys(config).forEach(key => {
|
|
441
|
-
if (config[key] === undefined) {
|
|
442
|
-
delete config[key];
|
|
443
|
-
}
|
|
444
|
-
});
|
|
445
|
-
// Get model name
|
|
446
281
|
const model = mergedOptions.model || this.defaultModel;
|
|
447
|
-
|
|
282
|
+
const { systemInstructionParts, contents, cacheHandle } = await this.buildPromptPayload(prompt, mergedOptions, model);
|
|
283
|
+
const config = this.buildGenerationConfig(mergedOptions, cacheHandle, systemInstructionParts, prompt);
|
|
284
|
+
this.cacheController?.recordQuery?.();
|
|
448
285
|
const streamResponse = await this.client.models.generateContentStream({
|
|
449
286
|
model,
|
|
450
287
|
contents,
|
|
@@ -550,7 +387,7 @@ export class GoogleGenAIDriver {
|
|
|
550
387
|
* Close the client
|
|
551
388
|
*/
|
|
552
389
|
async close() {
|
|
553
|
-
|
|
390
|
+
await this.cacheController?.close();
|
|
554
391
|
}
|
|
555
392
|
}
|
|
556
393
|
//# sourceMappingURL=google-genai-driver.js.map
|