@bowenqt/qiniu-ai-sdk 0.15.0 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ai/agent-graph.d.ts +5 -0
- package/dist/ai/agent-graph.d.ts.map +1 -1
- package/dist/ai/agent-graph.js +21 -2
- package/dist/ai/agent-graph.js.map +1 -1
- package/dist/ai/agent-graph.mjs +21 -2
- package/dist/ai/create-agent.d.ts +3 -0
- package/dist/ai/create-agent.d.ts.map +1 -1
- package/dist/ai/create-agent.js +6 -5
- package/dist/ai/create-agent.js.map +1 -1
- package/dist/ai/create-agent.mjs +6 -5
- package/dist/ai/generate-object.d.ts.map +1 -1
- package/dist/ai/generate-object.js +7 -1
- package/dist/ai/generate-object.js.map +1 -1
- package/dist/ai/generate-object.mjs +7 -1
- package/dist/ai/generate-text.d.ts +4 -1
- package/dist/ai/generate-text.d.ts.map +1 -1
- package/dist/ai/generate-text.js +10 -2
- package/dist/ai/generate-text.js.map +1 -1
- package/dist/ai/generate-text.mjs +10 -2
- package/dist/ai/internal-types.d.ts +11 -0
- package/dist/ai/internal-types.d.ts.map +1 -1
- package/dist/ai/internal-types.js +15 -0
- package/dist/ai/internal-types.js.map +1 -1
- package/dist/ai/internal-types.mjs +13 -0
- package/dist/ai/memory/index.d.ts +147 -0
- package/dist/ai/memory/index.d.ts.map +1 -0
- package/dist/ai/memory/index.js +240 -0
- package/dist/ai/memory/index.js.map +1 -0
- package/dist/ai/memory/index.mjs +234 -0
- package/dist/ai/nodes/memory-node.d.ts.map +1 -1
- package/dist/ai/nodes/memory-node.js +14 -16
- package/dist/ai/nodes/memory-node.js.map +1 -1
- package/dist/ai/nodes/memory-node.mjs +15 -17
- package/dist/ai/stream-object.d.ts +109 -0
- package/dist/ai/stream-object.d.ts.map +1 -0
- package/dist/ai/stream-object.js +383 -0
- package/dist/ai/stream-object.js.map +1 -0
- package/dist/ai/stream-object.mjs +347 -0
- package/dist/index.d.ts +8 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +16 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +7 -1
- package/dist/lib/capability-cache.d.ts +72 -0
- package/dist/lib/capability-cache.d.ts.map +1 -0
- package/dist/lib/capability-cache.js +117 -0
- package/dist/lib/capability-cache.js.map +1 -0
- package/dist/lib/capability-cache.mjs +113 -0
- package/dist/lib/content-converter.d.ts +33 -0
- package/dist/lib/content-converter.d.ts.map +1 -0
- package/dist/lib/content-converter.js +166 -0
- package/dist/lib/content-converter.js.map +1 -0
- package/dist/lib/content-converter.mjs +161 -0
- package/dist/lib/messages.js +4 -3
- package/dist/lib/messages.js.map +1 -1
- package/dist/lib/messages.mjs +4 -3
- package/dist/lib/partial-json-parser.d.ts +63 -0
- package/dist/lib/partial-json-parser.d.ts.map +1 -0
- package/dist/lib/partial-json-parser.js +142 -0
- package/dist/lib/partial-json-parser.js.map +1 -0
- package/dist/lib/partial-json-parser.mjs +137 -0
- package/dist/lib/token-estimator.d.ts.map +1 -1
- package/dist/lib/token-estimator.js +3 -2
- package/dist/lib/token-estimator.js.map +1 -1
- package/dist/lib/token-estimator.mjs +3 -2
- package/dist/lib/types.d.ts +20 -4
- package/dist/lib/types.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Capability cache for model feature detection.
|
|
4
|
+
* Caches model capabilities per client/baseUrl to avoid redundant probing.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```typescript
|
|
8
|
+
* import { capabilityCache } from './capability-cache';
|
|
9
|
+
*
|
|
10
|
+
* // Check if model supports streaming JSON
|
|
11
|
+
* const supports = capabilityCache.get(client, 'gemini-2.5-flash', 'stream_json_schema');
|
|
12
|
+
*
|
|
13
|
+
* // Cache result after probing
|
|
14
|
+
* capabilityCache.set(client, 'gemini-2.5-flash', 'stream_json_schema', true);
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
exports.capabilityCache = void 0;
|
|
19
|
+
exports.createCapabilityCache = createCapabilityCache;
|
|
20
|
+
/**
|
|
21
|
+
* Default TTL for cache entries (1 hour).
|
|
22
|
+
*/
|
|
23
|
+
const DEFAULT_TTL_MS = 60 * 60 * 1000;
|
|
24
|
+
/**
|
|
25
|
+
* Capability cache implementation.
|
|
26
|
+
* Scoped by baseUrl + model + capability to avoid cross-provider contamination.
|
|
27
|
+
*/
|
|
28
|
+
class CapabilityCache {
|
|
29
|
+
constructor(ttlMs = DEFAULT_TTL_MS) {
|
|
30
|
+
this.cache = new Map();
|
|
31
|
+
this.ttlMs = ttlMs;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Generate cache key from client, model, and capability.
|
|
35
|
+
*/
|
|
36
|
+
getKey(client, model, capability) {
|
|
37
|
+
const baseUrl = client.getBaseUrl();
|
|
38
|
+
return `${baseUrl}:${model}:${capability}`;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Get cached capability status.
|
|
42
|
+
* Returns undefined if not cached or expired.
|
|
43
|
+
*/
|
|
44
|
+
get(client, model, capability) {
|
|
45
|
+
const key = this.getKey(client, model, capability);
|
|
46
|
+
const entry = this.cache.get(key);
|
|
47
|
+
if (!entry) {
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
// Check expiration
|
|
51
|
+
if (Date.now() - entry.timestamp > this.ttlMs) {
|
|
52
|
+
this.cache.delete(key);
|
|
53
|
+
return undefined;
|
|
54
|
+
}
|
|
55
|
+
return entry.supported;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Set capability status.
|
|
59
|
+
*/
|
|
60
|
+
set(client, model, capability, supported) {
|
|
61
|
+
const key = this.getKey(client, model, capability);
|
|
62
|
+
this.cache.set(key, {
|
|
63
|
+
supported,
|
|
64
|
+
timestamp: Date.now(),
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Check if capability is cached and supported.
|
|
69
|
+
*/
|
|
70
|
+
isSupported(client, model, capability) {
|
|
71
|
+
return this.get(client, model, capability) === true;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Check if capability is cached and not supported.
|
|
75
|
+
*/
|
|
76
|
+
isNotSupported(client, model, capability) {
|
|
77
|
+
return this.get(client, model, capability) === false;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Clear all cached entries.
|
|
81
|
+
*/
|
|
82
|
+
clear() {
|
|
83
|
+
this.cache.clear();
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Clear entries for a specific client.
|
|
87
|
+
*/
|
|
88
|
+
clearForClient(client) {
|
|
89
|
+
const baseUrl = client.getBaseUrl();
|
|
90
|
+
const keysToDelete = [];
|
|
91
|
+
for (const key of this.cache.keys()) {
|
|
92
|
+
if (key.startsWith(baseUrl + ':')) {
|
|
93
|
+
keysToDelete.push(key);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
for (const key of keysToDelete) {
|
|
97
|
+
this.cache.delete(key);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Get cache size.
|
|
102
|
+
*/
|
|
103
|
+
size() {
|
|
104
|
+
return this.cache.size;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Global capability cache instance.
|
|
109
|
+
*/
|
|
110
|
+
exports.capabilityCache = new CapabilityCache();
|
|
111
|
+
/**
|
|
112
|
+
* Create a new capability cache with custom TTL (for testing).
|
|
113
|
+
*/
|
|
114
|
+
function createCapabilityCache(ttlMs) {
|
|
115
|
+
return new CapabilityCache(ttlMs);
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=capability-cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capability-cache.js","sourceRoot":"","sources":["../../src/lib/capability-cache.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Capability cache for model feature detection.
|
|
3
|
+
* Caches model capabilities per client/baseUrl to avoid redundant probing.
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* ```typescript
|
|
7
|
+
* import { capabilityCache } from './capability-cache.mjs';
|
|
8
|
+
*
|
|
9
|
+
* // Check if model supports streaming JSON
|
|
10
|
+
* const supports = capabilityCache.get(client, 'gemini-2.5-flash', 'stream_json_schema');
|
|
11
|
+
*
|
|
12
|
+
* // Cache result after probing
|
|
13
|
+
* capabilityCache.set(client, 'gemini-2.5-flash', 'stream_json_schema', true);
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Default TTL for cache entries (1 hour).
|
|
18
|
+
*/
|
|
19
|
+
const DEFAULT_TTL_MS = 60 * 60 * 1000;
|
|
20
|
+
/**
|
|
21
|
+
* Capability cache implementation.
|
|
22
|
+
* Scoped by baseUrl + model + capability to avoid cross-provider contamination.
|
|
23
|
+
*/
|
|
24
|
+
class CapabilityCache {
|
|
25
|
+
constructor(ttlMs = DEFAULT_TTL_MS) {
|
|
26
|
+
this.cache = new Map();
|
|
27
|
+
this.ttlMs = ttlMs;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Generate cache key from client, model, and capability.
|
|
31
|
+
*/
|
|
32
|
+
getKey(client, model, capability) {
|
|
33
|
+
const baseUrl = client.getBaseUrl();
|
|
34
|
+
return `${baseUrl}:${model}:${capability}`;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Get cached capability status.
|
|
38
|
+
* Returns undefined if not cached or expired.
|
|
39
|
+
*/
|
|
40
|
+
get(client, model, capability) {
|
|
41
|
+
const key = this.getKey(client, model, capability);
|
|
42
|
+
const entry = this.cache.get(key);
|
|
43
|
+
if (!entry) {
|
|
44
|
+
return undefined;
|
|
45
|
+
}
|
|
46
|
+
// Check expiration
|
|
47
|
+
if (Date.now() - entry.timestamp > this.ttlMs) {
|
|
48
|
+
this.cache.delete(key);
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
51
|
+
return entry.supported;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Set capability status.
|
|
55
|
+
*/
|
|
56
|
+
set(client, model, capability, supported) {
|
|
57
|
+
const key = this.getKey(client, model, capability);
|
|
58
|
+
this.cache.set(key, {
|
|
59
|
+
supported,
|
|
60
|
+
timestamp: Date.now(),
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Check if capability is cached and supported.
|
|
65
|
+
*/
|
|
66
|
+
isSupported(client, model, capability) {
|
|
67
|
+
return this.get(client, model, capability) === true;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Check if capability is cached and not supported.
|
|
71
|
+
*/
|
|
72
|
+
isNotSupported(client, model, capability) {
|
|
73
|
+
return this.get(client, model, capability) === false;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Clear all cached entries.
|
|
77
|
+
*/
|
|
78
|
+
clear() {
|
|
79
|
+
this.cache.clear();
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Clear entries for a specific client.
|
|
83
|
+
*/
|
|
84
|
+
clearForClient(client) {
|
|
85
|
+
const baseUrl = client.getBaseUrl();
|
|
86
|
+
const keysToDelete = [];
|
|
87
|
+
for (const key of this.cache.keys()) {
|
|
88
|
+
if (key.startsWith(baseUrl + ':')) {
|
|
89
|
+
keysToDelete.push(key);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
for (const key of keysToDelete) {
|
|
93
|
+
this.cache.delete(key);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Get cache size.
|
|
98
|
+
*/
|
|
99
|
+
size() {
|
|
100
|
+
return this.cache.size;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Global capability cache instance.
|
|
105
|
+
*/
|
|
106
|
+
export const capabilityCache = new CapabilityCache();
|
|
107
|
+
/**
|
|
108
|
+
* Create a new capability cache with custom TTL (for testing).
|
|
109
|
+
*/
|
|
110
|
+
export function createCapabilityCache(ttlMs) {
|
|
111
|
+
return new CapabilityCache(ttlMs);
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=capability-cache.js.map
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Content converter for multimodal messages.
|
|
3
|
+
* Normalizes SDK convenience formats to API-compatible formats.
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* ```typescript
|
|
7
|
+
* import { normalizeContent } from './content-converter';
|
|
8
|
+
*
|
|
9
|
+
* const content: ContentPart[] = [
|
|
10
|
+
* { type: 'text', text: 'Describe this image' },
|
|
11
|
+
* { type: 'image', image: fs.readFileSync('photo.jpg') },
|
|
12
|
+
* ];
|
|
13
|
+
*
|
|
14
|
+
* const normalized = normalizeContent(content);
|
|
15
|
+
* // [{ type: 'text', text: '...' }, { type: 'image_url', image_url: { url: 'data:...' } }]
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
import type { ContentPart } from './types';
|
|
19
|
+
/**
|
|
20
|
+
* Normalize content parts for API calls.
|
|
21
|
+
* Converts `image` sugar format to `image_url` API format.
|
|
22
|
+
*/
|
|
23
|
+
export declare function normalizeContent(content: string | ContentPart[]): string | ContentPart[];
|
|
24
|
+
/**
|
|
25
|
+
* Helper to convert Blob to data URL asynchronously (for browser use).
|
|
26
|
+
* Only available in browser environments.
|
|
27
|
+
*/
|
|
28
|
+
export declare function blobToDataUrl(blob: Blob): Promise<string>;
|
|
29
|
+
/**
|
|
30
|
+
* Check if content contains any image parts that need normalization.
|
|
31
|
+
*/
|
|
32
|
+
export declare function hasImageParts(content: string | ContentPart[]): boolean;
|
|
33
|
+
//# sourceMappingURL=content-converter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content-converter.d.ts","sourceRoot":"","sources":["../../src/lib/content-converter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAoC,MAAM,SAAS,CAAC;AAE7E;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW,EAAE,GAAG,MAAM,GAAG,WAAW,EAAE,CAQxF;AA+HD;;;GAGG;AACH,wBAAsB,aAAa,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAa/D;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW,EAAE,GAAG,OAAO,CAKtE"}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Content converter for multimodal messages.
|
|
4
|
+
* Normalizes SDK convenience formats to API-compatible formats.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```typescript
|
|
8
|
+
* import { normalizeContent } from './content-converter';
|
|
9
|
+
*
|
|
10
|
+
* const content: ContentPart[] = [
|
|
11
|
+
* { type: 'text', text: 'Describe this image' },
|
|
12
|
+
* { type: 'image', image: fs.readFileSync('photo.jpg') },
|
|
13
|
+
* ];
|
|
14
|
+
*
|
|
15
|
+
* const normalized = normalizeContent(content);
|
|
16
|
+
* // [{ type: 'text', text: '...' }, { type: 'image_url', image_url: { url: 'data:...' } }]
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
|
+
exports.normalizeContent = normalizeContent;
|
|
21
|
+
exports.blobToDataUrl = blobToDataUrl;
|
|
22
|
+
exports.hasImageParts = hasImageParts;
|
|
23
|
+
/**
|
|
24
|
+
* Normalize content parts for API calls.
|
|
25
|
+
* Converts `image` sugar format to `image_url` API format.
|
|
26
|
+
*/
|
|
27
|
+
function normalizeContent(content) {
|
|
28
|
+
// String content doesn't need normalization
|
|
29
|
+
if (typeof content === 'string') {
|
|
30
|
+
return content;
|
|
31
|
+
}
|
|
32
|
+
// Normalize each content part
|
|
33
|
+
return content.map(part => normalizeContentPart(part));
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Normalize a single content part.
|
|
37
|
+
*/
|
|
38
|
+
function normalizeContentPart(part) {
|
|
39
|
+
// Already in API format
|
|
40
|
+
if (part.type === 'text' || part.type === 'image_url') {
|
|
41
|
+
return part;
|
|
42
|
+
}
|
|
43
|
+
// Convert image sugar to image_url
|
|
44
|
+
if (part.type === 'image') {
|
|
45
|
+
return {
|
|
46
|
+
type: 'image_url',
|
|
47
|
+
image_url: {
|
|
48
|
+
url: imageSourceToDataUrl(part.image),
|
|
49
|
+
detail: part.detail,
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
// Unknown type, return as-is
|
|
54
|
+
return part;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Convert ImageSource to data URL.
|
|
58
|
+
*/
|
|
59
|
+
function imageSourceToDataUrl(source) {
|
|
60
|
+
// Already a string (base64 or URL)
|
|
61
|
+
if (typeof source === 'string') {
|
|
62
|
+
// Check if it's already a data URL or regular URL
|
|
63
|
+
if (source.startsWith('data:') || source.startsWith('http://') || source.startsWith('https://')) {
|
|
64
|
+
return source;
|
|
65
|
+
}
|
|
66
|
+
// Assume base64, wrap in data URL
|
|
67
|
+
return `data:image/png;base64,${source}`;
|
|
68
|
+
}
|
|
69
|
+
// URL object
|
|
70
|
+
if (source instanceof URL) {
|
|
71
|
+
return source.toString();
|
|
72
|
+
}
|
|
73
|
+
// Blob (browser)
|
|
74
|
+
if (typeof Blob !== 'undefined' && source instanceof Blob) {
|
|
75
|
+
// Note: Synchronous conversion not possible for Blob
|
|
76
|
+
// For real usage, caller should pre-convert to base64
|
|
77
|
+
throw new Error('Blob must be converted to base64 before passing to normalizeContent. Use blobToDataUrl() helper.');
|
|
78
|
+
}
|
|
79
|
+
// ArrayBuffer or Uint8Array
|
|
80
|
+
if (source instanceof ArrayBuffer) {
|
|
81
|
+
return arrayBufferToDataUrl(new Uint8Array(source));
|
|
82
|
+
}
|
|
83
|
+
if (source instanceof Uint8Array) {
|
|
84
|
+
return arrayBufferToDataUrl(source);
|
|
85
|
+
}
|
|
86
|
+
throw new Error(`Unsupported image source type: ${typeof source}`);
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Convert Uint8Array to data URL.
|
|
90
|
+
*/
|
|
91
|
+
function arrayBufferToDataUrl(buffer) {
|
|
92
|
+
// Detect MIME type from magic bytes
|
|
93
|
+
const mimeType = detectMimeType(buffer);
|
|
94
|
+
// Convert to base64
|
|
95
|
+
const base64 = uint8ArrayToBase64(buffer);
|
|
96
|
+
return `data:${mimeType};base64,${base64}`;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Detect image MIME type from magic bytes.
|
|
100
|
+
*/
|
|
101
|
+
function detectMimeType(buffer) {
|
|
102
|
+
if (buffer.length < 4) {
|
|
103
|
+
return 'application/octet-stream';
|
|
104
|
+
}
|
|
105
|
+
// PNG: 89 50 4E 47
|
|
106
|
+
if (buffer[0] === 0x89 && buffer[1] === 0x50 && buffer[2] === 0x4E && buffer[3] === 0x47) {
|
|
107
|
+
return 'image/png';
|
|
108
|
+
}
|
|
109
|
+
// JPEG: FF D8 FF
|
|
110
|
+
if (buffer[0] === 0xFF && buffer[1] === 0xD8 && buffer[2] === 0xFF) {
|
|
111
|
+
return 'image/jpeg';
|
|
112
|
+
}
|
|
113
|
+
// GIF: 47 49 46 38
|
|
114
|
+
if (buffer[0] === 0x47 && buffer[1] === 0x49 && buffer[2] === 0x46 && buffer[3] === 0x38) {
|
|
115
|
+
return 'image/gif';
|
|
116
|
+
}
|
|
117
|
+
// WebP: 52 49 46 46 ... 57 45 42 50
|
|
118
|
+
if (buffer[0] === 0x52 && buffer[1] === 0x49 && buffer[2] === 0x46 && buffer[3] === 0x46 &&
|
|
119
|
+
buffer.length > 11 && buffer[8] === 0x57 && buffer[9] === 0x45 && buffer[10] === 0x42 && buffer[11] === 0x50) {
|
|
120
|
+
return 'image/webp';
|
|
121
|
+
}
|
|
122
|
+
return 'image/png'; // Default fallback
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Convert Uint8Array to base64 string.
|
|
126
|
+
* Works in both Node.js and browser environments.
|
|
127
|
+
*/
|
|
128
|
+
function uint8ArrayToBase64(buffer) {
|
|
129
|
+
// Node.js environment
|
|
130
|
+
if (typeof Buffer !== 'undefined') {
|
|
131
|
+
return Buffer.from(buffer).toString('base64');
|
|
132
|
+
}
|
|
133
|
+
// Browser environment
|
|
134
|
+
let binary = '';
|
|
135
|
+
for (let i = 0; i < buffer.length; i++) {
|
|
136
|
+
binary += String.fromCharCode(buffer[i]);
|
|
137
|
+
}
|
|
138
|
+
return btoa(binary);
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Helper to convert Blob to data URL asynchronously (for browser use).
|
|
142
|
+
* Only available in browser environments.
|
|
143
|
+
*/
|
|
144
|
+
async function blobToDataUrl(blob) {
|
|
145
|
+
// Check if FileReader is available (browser environment)
|
|
146
|
+
const FR = globalThis.FileReader;
|
|
147
|
+
if (!FR) {
|
|
148
|
+
throw new Error('blobToDataUrl is only available in browser environments');
|
|
149
|
+
}
|
|
150
|
+
return new Promise((resolve, reject) => {
|
|
151
|
+
const reader = new FR();
|
|
152
|
+
reader.onloadend = () => resolve(reader.result);
|
|
153
|
+
reader.onerror = reject;
|
|
154
|
+
reader.readAsDataURL(blob);
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Check if content contains any image parts that need normalization.
|
|
159
|
+
*/
|
|
160
|
+
function hasImageParts(content) {
|
|
161
|
+
if (typeof content === 'string') {
|
|
162
|
+
return false;
|
|
163
|
+
}
|
|
164
|
+
return content.some(part => part.type === 'image');
|
|
165
|
+
}
|
|
166
|
+
//# sourceMappingURL=content-converter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content-converter.js","sourceRoot":"","sources":["../../src/lib/content-converter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Content converter for multimodal messages.
|
|
3
|
+
* Normalizes SDK convenience formats to API-compatible formats.
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* ```typescript
|
|
7
|
+
* import { normalizeContent } from './content-converter.mjs';
|
|
8
|
+
*
|
|
9
|
+
* const content: ContentPart[] = [
|
|
10
|
+
* { type: 'text', text: 'Describe this image' },
|
|
11
|
+
* { type: 'image', image: fs.readFileSync('photo.jpg') },
|
|
12
|
+
* ];
|
|
13
|
+
*
|
|
14
|
+
* const normalized = normalizeContent(content);
|
|
15
|
+
* // [{ type: 'text', text: '...' }, { type: 'image_url', image_url: { url: 'data:...' } }]
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* Normalize content parts for API calls.
|
|
20
|
+
* Converts `image` sugar format to `image_url` API format.
|
|
21
|
+
*/
|
|
22
|
+
export function normalizeContent(content) {
|
|
23
|
+
// String content doesn't need normalization
|
|
24
|
+
if (typeof content === 'string') {
|
|
25
|
+
return content;
|
|
26
|
+
}
|
|
27
|
+
// Normalize each content part
|
|
28
|
+
return content.map(part => normalizeContentPart(part));
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Normalize a single content part.
|
|
32
|
+
*/
|
|
33
|
+
function normalizeContentPart(part) {
|
|
34
|
+
// Already in API format
|
|
35
|
+
if (part.type === 'text' || part.type === 'image_url') {
|
|
36
|
+
return part;
|
|
37
|
+
}
|
|
38
|
+
// Convert image sugar to image_url
|
|
39
|
+
if (part.type === 'image') {
|
|
40
|
+
return {
|
|
41
|
+
type: 'image_url',
|
|
42
|
+
image_url: {
|
|
43
|
+
url: imageSourceToDataUrl(part.image),
|
|
44
|
+
detail: part.detail,
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
// Unknown type, return as-is
|
|
49
|
+
return part;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Convert ImageSource to data URL.
|
|
53
|
+
*/
|
|
54
|
+
function imageSourceToDataUrl(source) {
|
|
55
|
+
// Already a string (base64 or URL)
|
|
56
|
+
if (typeof source === 'string') {
|
|
57
|
+
// Check if it's already a data URL or regular URL
|
|
58
|
+
if (source.startsWith('data:') || source.startsWith('http://') || source.startsWith('https://')) {
|
|
59
|
+
return source;
|
|
60
|
+
}
|
|
61
|
+
// Assume base64, wrap in data URL
|
|
62
|
+
return `data:image/png;base64,${source}`;
|
|
63
|
+
}
|
|
64
|
+
// URL object
|
|
65
|
+
if (source instanceof URL) {
|
|
66
|
+
return source.toString();
|
|
67
|
+
}
|
|
68
|
+
// Blob (browser)
|
|
69
|
+
if (typeof Blob !== 'undefined' && source instanceof Blob) {
|
|
70
|
+
// Note: Synchronous conversion not possible for Blob
|
|
71
|
+
// For real usage, caller should pre-convert to base64
|
|
72
|
+
throw new Error('Blob must be converted to base64 before passing to normalizeContent. Use blobToDataUrl() helper.');
|
|
73
|
+
}
|
|
74
|
+
// ArrayBuffer or Uint8Array
|
|
75
|
+
if (source instanceof ArrayBuffer) {
|
|
76
|
+
return arrayBufferToDataUrl(new Uint8Array(source));
|
|
77
|
+
}
|
|
78
|
+
if (source instanceof Uint8Array) {
|
|
79
|
+
return arrayBufferToDataUrl(source);
|
|
80
|
+
}
|
|
81
|
+
throw new Error(`Unsupported image source type: ${typeof source}`);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Convert Uint8Array to data URL.
|
|
85
|
+
*/
|
|
86
|
+
function arrayBufferToDataUrl(buffer) {
|
|
87
|
+
// Detect MIME type from magic bytes
|
|
88
|
+
const mimeType = detectMimeType(buffer);
|
|
89
|
+
// Convert to base64
|
|
90
|
+
const base64 = uint8ArrayToBase64(buffer);
|
|
91
|
+
return `data:${mimeType};base64,${base64}`;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Detect image MIME type from magic bytes.
|
|
95
|
+
*/
|
|
96
|
+
function detectMimeType(buffer) {
|
|
97
|
+
if (buffer.length < 4) {
|
|
98
|
+
return 'application/octet-stream';
|
|
99
|
+
}
|
|
100
|
+
// PNG: 89 50 4E 47
|
|
101
|
+
if (buffer[0] === 0x89 && buffer[1] === 0x50 && buffer[2] === 0x4E && buffer[3] === 0x47) {
|
|
102
|
+
return 'image/png';
|
|
103
|
+
}
|
|
104
|
+
// JPEG: FF D8 FF
|
|
105
|
+
if (buffer[0] === 0xFF && buffer[1] === 0xD8 && buffer[2] === 0xFF) {
|
|
106
|
+
return 'image/jpeg';
|
|
107
|
+
}
|
|
108
|
+
// GIF: 47 49 46 38
|
|
109
|
+
if (buffer[0] === 0x47 && buffer[1] === 0x49 && buffer[2] === 0x46 && buffer[3] === 0x38) {
|
|
110
|
+
return 'image/gif';
|
|
111
|
+
}
|
|
112
|
+
// WebP: 52 49 46 46 ... 57 45 42 50
|
|
113
|
+
if (buffer[0] === 0x52 && buffer[1] === 0x49 && buffer[2] === 0x46 && buffer[3] === 0x46 &&
|
|
114
|
+
buffer.length > 11 && buffer[8] === 0x57 && buffer[9] === 0x45 && buffer[10] === 0x42 && buffer[11] === 0x50) {
|
|
115
|
+
return 'image/webp';
|
|
116
|
+
}
|
|
117
|
+
return 'image/png'; // Default fallback
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Convert Uint8Array to base64 string.
|
|
121
|
+
* Works in both Node.js and browser environments.
|
|
122
|
+
*/
|
|
123
|
+
function uint8ArrayToBase64(buffer) {
|
|
124
|
+
// Node.js environment
|
|
125
|
+
if (typeof Buffer !== 'undefined') {
|
|
126
|
+
return Buffer.from(buffer).toString('base64');
|
|
127
|
+
}
|
|
128
|
+
// Browser environment
|
|
129
|
+
let binary = '';
|
|
130
|
+
for (let i = 0; i < buffer.length; i++) {
|
|
131
|
+
binary += String.fromCharCode(buffer[i]);
|
|
132
|
+
}
|
|
133
|
+
return btoa(binary);
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Helper to convert Blob to data URL asynchronously (for browser use).
|
|
137
|
+
* Only available in browser environments.
|
|
138
|
+
*/
|
|
139
|
+
export async function blobToDataUrl(blob) {
|
|
140
|
+
// Check if FileReader is available (browser environment)
|
|
141
|
+
const FR = globalThis.FileReader;
|
|
142
|
+
if (!FR) {
|
|
143
|
+
throw new Error('blobToDataUrl is only available in browser environments');
|
|
144
|
+
}
|
|
145
|
+
return new Promise((resolve, reject) => {
|
|
146
|
+
const reader = new FR();
|
|
147
|
+
reader.onloadend = () => resolve(reader.result);
|
|
148
|
+
reader.onerror = reject;
|
|
149
|
+
reader.readAsDataURL(blob);
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Check if content contains any image parts that need normalization.
|
|
154
|
+
*/
|
|
155
|
+
export function hasImageParts(content) {
|
|
156
|
+
if (typeof content === 'string') {
|
|
157
|
+
return false;
|
|
158
|
+
}
|
|
159
|
+
return content.some(part => part.type === 'image');
|
|
160
|
+
}
|
|
161
|
+
//# sourceMappingURL=content-converter.js.map
|
package/dist/lib/messages.js
CHANGED
|
@@ -49,10 +49,11 @@ function estimateMessageTokens(message) {
|
|
|
49
49
|
return 0;
|
|
50
50
|
}
|
|
51
51
|
function estimateTokensFromPart(part) {
|
|
52
|
-
if (part.type === 'text') {
|
|
53
|
-
return estimateTokensFromText(part.text
|
|
52
|
+
if (part.type === 'text' && 'text' in part) {
|
|
53
|
+
return estimateTokensFromText(part.text);
|
|
54
54
|
}
|
|
55
|
-
|
|
55
|
+
// Both image_url (API format) and image (SDK sugar) count as image tokens
|
|
56
|
+
if (part.type === 'image_url' || part.type === 'image') {
|
|
56
57
|
return 50;
|
|
57
58
|
}
|
|
58
59
|
return 0;
|
package/dist/lib/messages.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"messages.js","sourceRoot":"","sources":["../../src/lib/messages.ts"],"names":[],"mappings":";;AAaA,wCAMC;AAMD,0CAqCC;AApDD;;GAEG;AACH,SAAgB,cAAc,CAC1B,OAAsB,EACtB,UAAuC;IAEvC,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;IACnE,OAAO,CAAC,GAAG,OAAO,EAAE,GAAG,IAAI,CAAC,CAAC;AACjC,CAAC;AAED;;;GAGG;AACH,SAAgB,eAAe,CAC3B,QAAuB,EACvB,SAAiB,EACjB,UAA2B,EAAE;IAE7B,IAAI,SAAS,IAAI,CAAC,EAAE,CAAC;QACjB,OAAO,EAAE,CAAC;IACd,CAAC;IAED,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,KAAK,CAAC;IAC/C,MAAM,aAAa,GAAG,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAE7F,MAAM,OAAO,GAAkB,EAAE,CAAC;IAClC,IAAI,WAAW,GAAG,CAAC,CAAC;IAEpB,KAAK,IAAI,CAAC,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QAC/C,MAAM,OAAO,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;QAC5B,IAAI,UAAU,IAAI,OAAO,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC1C,SAAS;QACb,CAAC;QAED,MAAM,aAAa,GAAG,qBAAqB,CAAC,OAAO,CAAC,CAAC;QACrD,IAAI,WAAW,GAAG,aAAa,GAAG,SAAS,EAAE,CAAC;YAC1C,MAAM;QACV,CAAC;QAED,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACtB,WAAW,IAAI,aAAa,CAAC;IACjC,CAAC;IAED,OAAO,CAAC,OAAO,EAAE,CAAC;IAElB,IAAI,aAAa,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC;QACpD,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;IACnC,CAAC;IAED,OAAO,OAAO,CAAC;AACnB,CAAC;AAED,SAAS,qBAAqB,CAAC,OAAoB;IAC/C,IAAI,OAAO,OAAO,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;QACtC,OAAO,sBAAsB,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IACnD,CAAC;IAED,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QACjC,OAAO,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,CAAC,GAAG,GAAG,sBAAsB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;IACxF,CAAC;IAED,OAAO,CAAC,CAAC;AACb,CAAC;AAED,SAAS,sBAAsB,CAAC,IAAiB;IAC7C,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"messages.js","sourceRoot":"","sources":["../../src/lib/messages.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/messages.mjs
CHANGED
|
@@ -45,10 +45,11 @@ function estimateMessageTokens(message) {
|
|
|
45
45
|
return 0;
|
|
46
46
|
}
|
|
47
47
|
function estimateTokensFromPart(part) {
|
|
48
|
-
if (part.type === 'text') {
|
|
49
|
-
return estimateTokensFromText(part.text
|
|
48
|
+
if (part.type === 'text' && 'text' in part) {
|
|
49
|
+
return estimateTokensFromText(part.text);
|
|
50
50
|
}
|
|
51
|
-
|
|
51
|
+
// Both image_url (API format) and image (SDK sugar) count as image tokens
|
|
52
|
+
if (part.type === 'image_url' || part.type === 'image') {
|
|
52
53
|
return 50;
|
|
53
54
|
}
|
|
54
55
|
return 0;
|