genaicode 2.0.0 → 2.3.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/CHANGELOG.md +57 -0
- package/README.md +194 -26
- package/dist/core/client.d.ts +15 -3
- package/dist/core/client.js +87 -3
- package/dist/core/client.js.map +1 -1
- package/dist/core/errors.d.ts +38 -0
- package/dist/core/errors.js +118 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/middleware.d.ts +43 -0
- package/dist/core/middleware.js +175 -0
- package/dist/core/middleware.js.map +1 -0
- package/dist/core/plugins.d.ts +8 -1
- package/dist/core/plugins.js +25 -1
- package/dist/core/plugins.js.map +1 -1
- package/dist/core/result.d.ts +2 -2
- package/dist/core/result.js +5 -1
- package/dist/core/result.js.map +1 -1
- package/dist/core/stream.d.ts +11 -0
- package/dist/core/stream.js +93 -0
- package/dist/core/stream.js.map +1 -0
- package/dist/core/types.d.ts +101 -0
- package/dist/index.d.ts +6 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/providers/anthropic-converter.js +32 -6
- package/dist/providers/anthropic-converter.js.map +1 -1
- package/dist/providers/anthropic.js +64 -0
- package/dist/providers/anthropic.js.map +1 -1
- package/dist/providers/fixtures/multimodal-tool-roundtrip.d.ts +4 -0
- package/dist/providers/fixtures/multimodal-tool-roundtrip.js +32 -0
- package/dist/providers/fixtures/multimodal-tool-roundtrip.js.map +1 -0
- package/dist/providers/google-converter.js +53 -2
- package/dist/providers/google-converter.js.map +1 -1
- package/dist/providers/google.js +65 -0
- package/dist/providers/google.js.map +1 -1
- package/dist/providers/openai-converter.d.ts +20 -1
- package/dist/providers/openai-converter.js +98 -0
- package/dist/providers/openai-converter.js.map +1 -1
- package/dist/providers/openai.js +18 -1
- package/dist/providers/openai.js.map +1 -1
- package/dist/providers.d.ts +1 -1
- package/dist/providers.js +1 -1
- package/dist/providers.js.map +1 -1
- package/docs/pivot.md +33 -14
- package/docs/provider-packages.md +60 -0
- package/docs/retry.md +62 -0
- package/docs/semver.md +56 -0
- package/package.json +5 -2
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
function readStatus(error) {
|
|
2
|
+
if (!error || typeof error !== 'object')
|
|
3
|
+
return undefined;
|
|
4
|
+
const candidate = error;
|
|
5
|
+
for (const value of [candidate.status, candidate.statusCode, candidate.response?.status]) {
|
|
6
|
+
if (typeof value === 'number')
|
|
7
|
+
return value;
|
|
8
|
+
}
|
|
9
|
+
return undefined;
|
|
10
|
+
}
|
|
11
|
+
function readCode(error) {
|
|
12
|
+
if (!error || typeof error !== 'object')
|
|
13
|
+
return undefined;
|
|
14
|
+
const code = error.code;
|
|
15
|
+
return typeof code === 'string' ? code : undefined;
|
|
16
|
+
}
|
|
17
|
+
function messageOf(error) {
|
|
18
|
+
if (error instanceof Error)
|
|
19
|
+
return error.message;
|
|
20
|
+
return String(error);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Classify a provider/SDK error for application-owned retry loops.
|
|
24
|
+
*
|
|
25
|
+
* GenAIcode does not retry automatically. Use this helper (or your own policy)
|
|
26
|
+
* inside ordinary application control flow. See docs/retry.md.
|
|
27
|
+
*/
|
|
28
|
+
export function classifyError(error) {
|
|
29
|
+
const status = readStatus(error);
|
|
30
|
+
const code = readCode(error);
|
|
31
|
+
const message = messageOf(error).toLowerCase();
|
|
32
|
+
if (error instanceof DOMException && error.name === 'AbortError') {
|
|
33
|
+
return { class: 'permanent', retryable: false, reason: 'aborted', cause: error };
|
|
34
|
+
}
|
|
35
|
+
if (code === 'ECONNRESET' || code === 'ETIMEDOUT' || code === 'ECONNREFUSED' || code === 'ENOTFOUND') {
|
|
36
|
+
return { class: 'transient', retryable: true, reason: `network:${code}`, code, cause: error };
|
|
37
|
+
}
|
|
38
|
+
if (status === 408 || status === 425 || status === 429 || (status !== undefined && status >= 500)) {
|
|
39
|
+
return {
|
|
40
|
+
class: 'transient',
|
|
41
|
+
retryable: true,
|
|
42
|
+
reason: `http:${status}`,
|
|
43
|
+
status,
|
|
44
|
+
code,
|
|
45
|
+
cause: error,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
if (status !== undefined && status >= 400 && status < 500) {
|
|
49
|
+
return {
|
|
50
|
+
class: 'permanent',
|
|
51
|
+
retryable: false,
|
|
52
|
+
reason: `http:${status}`,
|
|
53
|
+
status,
|
|
54
|
+
code,
|
|
55
|
+
cause: error,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
if (message.includes('rate limit') ||
|
|
59
|
+
message.includes('timeout') ||
|
|
60
|
+
message.includes('temporar') ||
|
|
61
|
+
message.includes('unavailable') ||
|
|
62
|
+
message.includes('overloaded')) {
|
|
63
|
+
return { class: 'transient', retryable: true, reason: 'message-heuristic', status, code, cause: error };
|
|
64
|
+
}
|
|
65
|
+
if (message.includes('invalid') ||
|
|
66
|
+
message.includes('authentication') ||
|
|
67
|
+
message.includes('unauthorized') ||
|
|
68
|
+
message.includes('permission') ||
|
|
69
|
+
message.includes('not found')) {
|
|
70
|
+
return { class: 'permanent', retryable: false, reason: 'message-heuristic', status, code, cause: error };
|
|
71
|
+
}
|
|
72
|
+
return { class: 'unknown', retryable: false, reason: 'unclassified', status, code, cause: error };
|
|
73
|
+
}
|
|
74
|
+
export function isRetryable(error) {
|
|
75
|
+
return classifyError(error).retryable;
|
|
76
|
+
}
|
|
77
|
+
function sleep(ms, signal) {
|
|
78
|
+
return new Promise((resolve, reject) => {
|
|
79
|
+
if (signal?.aborted) {
|
|
80
|
+
reject(signal.reason instanceof Error ? signal.reason : new DOMException('Aborted', 'AbortError'));
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
const timer = setTimeout(resolve, ms);
|
|
84
|
+
signal?.addEventListener('abort', () => {
|
|
85
|
+
clearTimeout(timer);
|
|
86
|
+
reject(signal.reason instanceof Error ? signal.reason : new DOMException('Aborted', 'AbortError'));
|
|
87
|
+
}, { once: true });
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Explicit retry helper for application code. Not wired into the client by default.
|
|
92
|
+
*
|
|
93
|
+
* Idempotency: only wrap operations that are safe to repeat (most pure generation
|
|
94
|
+
* calls are; tool side effects are not unless the application makes them idempotent).
|
|
95
|
+
*/
|
|
96
|
+
export async function withRetry(operation, options = {}) {
|
|
97
|
+
const attempts = Math.max(1, options.attempts ?? 3);
|
|
98
|
+
const delayMs = options.delayMs ?? 250;
|
|
99
|
+
const maxDelayMs = options.maxDelayMs ?? 5000;
|
|
100
|
+
const shouldRetry = options.shouldRetry ?? ((error) => isRetryable(error));
|
|
101
|
+
let lastError;
|
|
102
|
+
for (let attempt = 1; attempt <= attempts; attempt += 1) {
|
|
103
|
+
try {
|
|
104
|
+
return await operation();
|
|
105
|
+
}
|
|
106
|
+
catch (error) {
|
|
107
|
+
lastError = error;
|
|
108
|
+
if (attempt >= attempts || !shouldRetry(error, attempt)) {
|
|
109
|
+
throw error;
|
|
110
|
+
}
|
|
111
|
+
const wait = Math.min(maxDelayMs, delayMs * 2 ** (attempt - 1));
|
|
112
|
+
options.onRetry?.({ attempt, error, delayMs: wait });
|
|
113
|
+
await sleep(wait, options.signal);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
throw lastError instanceof Error ? lastError : new Error(String(lastError));
|
|
117
|
+
}
|
|
118
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/core/errors.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { GenerationRequest, ModelProvider } from './types.js';
|
|
2
|
+
import { type GenAIPlugin } from './plugins.js';
|
|
3
|
+
export interface TimingPluginOptions {
|
|
4
|
+
onTiming?: (info: {
|
|
5
|
+
plugin: string;
|
|
6
|
+
provider?: string;
|
|
7
|
+
durationMs: number;
|
|
8
|
+
ok: boolean;
|
|
9
|
+
}) => void;
|
|
10
|
+
}
|
|
11
|
+
/** Observability middleware: records wall-clock duration around each generate call. */
|
|
12
|
+
export declare function timingPlugin(options?: TimingPluginOptions): GenAIPlugin;
|
|
13
|
+
export interface RateLimitPluginOptions {
|
|
14
|
+
/** Maximum concurrent in-flight generate calls. Defaults to 1. */
|
|
15
|
+
concurrency?: number;
|
|
16
|
+
/** Minimum delay between starting successive calls, in milliseconds. */
|
|
17
|
+
minIntervalMs?: number;
|
|
18
|
+
}
|
|
19
|
+
/** Simple concurrency / interval limiter. Does not talk to external rate-limit stores. */
|
|
20
|
+
export declare function rateLimitPlugin(options?: RateLimitPluginOptions): GenAIPlugin;
|
|
21
|
+
export interface CachePluginOptions {
|
|
22
|
+
/** Stable cache key. Defaults to a JSON serialization of the request (excluding signal). */
|
|
23
|
+
key?: (request: GenerationRequest) => string;
|
|
24
|
+
maxEntries?: number;
|
|
25
|
+
}
|
|
26
|
+
/** In-memory response cache. Intentionally short-circuits `next` on hit. */
|
|
27
|
+
export declare function cachePlugin(options?: CachePluginOptions): GenAIPlugin;
|
|
28
|
+
export interface FallbackPluginOptions {
|
|
29
|
+
/** Additional providers tried after the primary provider fails. */
|
|
30
|
+
providers: readonly ModelProvider[];
|
|
31
|
+
/** Decide whether an error should trigger fallback. Defaults to always. */
|
|
32
|
+
shouldFallback?: (error: unknown, attempt: number) => boolean;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Fallback middleware: on primary failure, try alternate providers in order.
|
|
36
|
+
* Each alternate receives the same GenerationRequest.
|
|
37
|
+
*/
|
|
38
|
+
export declare function fallbackPlugin(options: FallbackPluginOptions): GenAIPlugin;
|
|
39
|
+
/**
|
|
40
|
+
* Compose multiple providers into one ModelProvider that tries each until one succeeds.
|
|
41
|
+
* Prefer this when there is no single "primary" provider wired through plugins.
|
|
42
|
+
*/
|
|
43
|
+
export declare function fallbackProvider(providers: readonly ModelProvider[], name?: string): ModelProvider;
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { definePlugin } from './plugins.js';
|
|
2
|
+
import { providerStream } from './stream.js';
|
|
3
|
+
/** Observability middleware: records wall-clock duration around each generate call. */
|
|
4
|
+
export function timingPlugin(options = {}) {
|
|
5
|
+
const onTiming = options.onTiming ??
|
|
6
|
+
((info) => {
|
|
7
|
+
console.log(`[genaicode] ${info.plugin} ${info.ok ? 'ok' : 'error'} in ${info.durationMs.toFixed(1)}ms`);
|
|
8
|
+
});
|
|
9
|
+
return definePlugin({
|
|
10
|
+
name: 'timing',
|
|
11
|
+
async generate(request, next) {
|
|
12
|
+
const startedAt = performance.now();
|
|
13
|
+
try {
|
|
14
|
+
const result = await next(request);
|
|
15
|
+
onTiming({ plugin: 'timing', durationMs: performance.now() - startedAt, ok: true });
|
|
16
|
+
return result;
|
|
17
|
+
}
|
|
18
|
+
catch (error) {
|
|
19
|
+
onTiming({ plugin: 'timing', durationMs: performance.now() - startedAt, ok: false });
|
|
20
|
+
throw error;
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
/** Simple concurrency / interval limiter. Does not talk to external rate-limit stores. */
|
|
26
|
+
export function rateLimitPlugin(options = {}) {
|
|
27
|
+
const concurrency = Math.max(1, options.concurrency ?? 1);
|
|
28
|
+
const minIntervalMs = Math.max(0, options.minIntervalMs ?? 0);
|
|
29
|
+
let active = 0;
|
|
30
|
+
let lastStartedAt = 0;
|
|
31
|
+
const waiters = [];
|
|
32
|
+
const pump = () => {
|
|
33
|
+
while (active < concurrency && waiters.length > 0) {
|
|
34
|
+
const now = Date.now();
|
|
35
|
+
// Enforce spacing between starts even when no call is currently in flight
|
|
36
|
+
// (important for concurrency=1 + minIntervalMs).
|
|
37
|
+
const waitMs = lastStartedAt === 0 ? 0 : Math.max(0, minIntervalMs - (now - lastStartedAt));
|
|
38
|
+
if (waitMs > 0) {
|
|
39
|
+
setTimeout(pump, waitMs);
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
const next = waiters.shift();
|
|
43
|
+
if (!next)
|
|
44
|
+
return;
|
|
45
|
+
active += 1;
|
|
46
|
+
lastStartedAt = Date.now();
|
|
47
|
+
next();
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
const acquire = () => new Promise((resolve) => {
|
|
51
|
+
waiters.push(resolve);
|
|
52
|
+
pump();
|
|
53
|
+
});
|
|
54
|
+
const release = () => {
|
|
55
|
+
active = Math.max(0, active - 1);
|
|
56
|
+
pump();
|
|
57
|
+
};
|
|
58
|
+
return definePlugin({
|
|
59
|
+
name: 'rate-limit',
|
|
60
|
+
async generate(request, next) {
|
|
61
|
+
await acquire();
|
|
62
|
+
try {
|
|
63
|
+
return await next(request);
|
|
64
|
+
}
|
|
65
|
+
finally {
|
|
66
|
+
release();
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
function defaultCacheKey(request) {
|
|
72
|
+
return JSON.stringify({
|
|
73
|
+
prompt: request.prompt,
|
|
74
|
+
model: request.model,
|
|
75
|
+
temperature: request.temperature,
|
|
76
|
+
maxOutputTokens: request.maxOutputTokens,
|
|
77
|
+
tools: request.tools,
|
|
78
|
+
toolChoice: request.toolChoice,
|
|
79
|
+
responseFormat: request.responseFormat,
|
|
80
|
+
thinking: request.thinking,
|
|
81
|
+
metadata: request.metadata,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
/** In-memory response cache. Intentionally short-circuits `next` on hit. */
|
|
85
|
+
export function cachePlugin(options = {}) {
|
|
86
|
+
const keyOf = options.key ?? defaultCacheKey;
|
|
87
|
+
const maxEntries = options.maxEntries ?? 128;
|
|
88
|
+
const cache = new Map();
|
|
89
|
+
return definePlugin({
|
|
90
|
+
name: 'cache',
|
|
91
|
+
async generate(request, next) {
|
|
92
|
+
const key = keyOf(request);
|
|
93
|
+
const hit = cache.get(key);
|
|
94
|
+
if (hit) {
|
|
95
|
+
cache.delete(key);
|
|
96
|
+
cache.set(key, hit);
|
|
97
|
+
return hit;
|
|
98
|
+
}
|
|
99
|
+
const result = await next(request);
|
|
100
|
+
cache.set(key, result);
|
|
101
|
+
if (cache.size > maxEntries) {
|
|
102
|
+
const oldest = cache.keys().next().value;
|
|
103
|
+
if (oldest !== undefined)
|
|
104
|
+
cache.delete(oldest);
|
|
105
|
+
}
|
|
106
|
+
return result;
|
|
107
|
+
},
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Fallback middleware: on primary failure, try alternate providers in order.
|
|
112
|
+
* Each alternate receives the same GenerationRequest.
|
|
113
|
+
*/
|
|
114
|
+
export function fallbackPlugin(options) {
|
|
115
|
+
const shouldFallback = options.shouldFallback ?? (() => true);
|
|
116
|
+
return definePlugin({
|
|
117
|
+
name: 'fallback',
|
|
118
|
+
async generate(request, next) {
|
|
119
|
+
try {
|
|
120
|
+
return await next(request);
|
|
121
|
+
}
|
|
122
|
+
catch (error) {
|
|
123
|
+
if (!shouldFallback(error, 0))
|
|
124
|
+
throw error;
|
|
125
|
+
let lastError = error;
|
|
126
|
+
for (let index = 0; index < options.providers.length; index += 1) {
|
|
127
|
+
if (!shouldFallback(lastError, index + 1) && index > 0)
|
|
128
|
+
throw lastError;
|
|
129
|
+
try {
|
|
130
|
+
return await options.providers[index].generate(request);
|
|
131
|
+
}
|
|
132
|
+
catch (fallbackError) {
|
|
133
|
+
lastError = fallbackError;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
throw lastError;
|
|
137
|
+
}
|
|
138
|
+
},
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Compose multiple providers into one ModelProvider that tries each until one succeeds.
|
|
143
|
+
* Prefer this when there is no single "primary" provider wired through plugins.
|
|
144
|
+
*/
|
|
145
|
+
export function fallbackProvider(providers, name = 'fallback') {
|
|
146
|
+
if (providers.length === 0) {
|
|
147
|
+
throw new Error('fallbackProvider requires at least one provider.');
|
|
148
|
+
}
|
|
149
|
+
const streamProvider = providers.find((provider) => Boolean(provider.stream)) ?? providers[0];
|
|
150
|
+
return {
|
|
151
|
+
name,
|
|
152
|
+
capabilities: {
|
|
153
|
+
streaming: providers.some((provider) => provider.capabilities?.streaming || Boolean(provider.stream)),
|
|
154
|
+
tools: providers.every((provider) => provider.capabilities?.tools !== false),
|
|
155
|
+
systemPrompt: providers.every((provider) => provider.capabilities?.systemPrompt !== false),
|
|
156
|
+
},
|
|
157
|
+
async generate(request) {
|
|
158
|
+
let lastError;
|
|
159
|
+
for (const provider of providers) {
|
|
160
|
+
try {
|
|
161
|
+
return await provider.generate(request);
|
|
162
|
+
}
|
|
163
|
+
catch (error) {
|
|
164
|
+
lastError = error;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
throw lastError instanceof Error ? lastError : new Error(String(lastError));
|
|
168
|
+
},
|
|
169
|
+
stream(request) {
|
|
170
|
+
// Prefer the first provider with a native stream implementation.
|
|
171
|
+
return providerStream(streamProvider, request);
|
|
172
|
+
},
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
//# sourceMappingURL=middleware.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"middleware.js","sourceRoot":"","sources":["../../src/core/middleware.ts"],"names":[],"mappings":"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"}
|
package/dist/core/plugins.d.ts
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
|
-
import type { GenerationRequest, GenerationResult, ModelProvider } from './types.js';
|
|
1
|
+
import type { GenerationRequest, GenerationResult, ModelProvider, StreamEvent } from './types.js';
|
|
2
2
|
export type GenerateNext = (request?: GenerationRequest) => Promise<GenerationResult>;
|
|
3
|
+
export type StreamNext = (request?: GenerationRequest) => AsyncIterable<StreamEvent>;
|
|
3
4
|
export interface GenAIPlugin {
|
|
4
5
|
readonly name: string;
|
|
5
6
|
generate(request: GenerationRequest, next: GenerateNext): Promise<GenerationResult>;
|
|
7
|
+
/**
|
|
8
|
+
* Optional streaming middleware. When omitted, the stream path passes through
|
|
9
|
+
* to the next plugin / provider unchanged.
|
|
10
|
+
*/
|
|
11
|
+
stream?(request: GenerationRequest, next: StreamNext): AsyncIterable<StreamEvent>;
|
|
6
12
|
}
|
|
7
13
|
export declare function definePlugin(plugin: GenAIPlugin): GenAIPlugin;
|
|
8
14
|
/**
|
|
@@ -10,5 +16,6 @@ export declare function definePlugin(plugin: GenAIPlugin): GenAIPlugin;
|
|
|
10
16
|
*
|
|
11
17
|
* Plugins run in registration order. Each plugin may modify the request passed
|
|
12
18
|
* to `next`, transform its result, handle an error, or intentionally short-circuit.
|
|
19
|
+
* Streaming uses the same order; plugins without `stream` pass through.
|
|
13
20
|
*/
|
|
14
21
|
export declare function withPlugins(provider: ModelProvider, plugins: readonly GenAIPlugin[]): ModelProvider;
|
package/dist/core/plugins.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { generateAsStream, providerStream } from './stream.js';
|
|
1
2
|
export function definePlugin(plugin) {
|
|
2
3
|
return plugin;
|
|
3
4
|
}
|
|
@@ -6,12 +7,14 @@ export function definePlugin(plugin) {
|
|
|
6
7
|
*
|
|
7
8
|
* Plugins run in registration order. Each plugin may modify the request passed
|
|
8
9
|
* to `next`, transform its result, handle an error, or intentionally short-circuit.
|
|
10
|
+
* Streaming uses the same order; plugins without `stream` pass through.
|
|
9
11
|
*/
|
|
10
12
|
export function withPlugins(provider, plugins) {
|
|
11
13
|
if (plugins.length === 0)
|
|
12
14
|
return provider;
|
|
13
|
-
|
|
15
|
+
const wrapped = {
|
|
14
16
|
name: provider.name,
|
|
17
|
+
capabilities: provider.capabilities,
|
|
15
18
|
generate(request) {
|
|
16
19
|
let lastIndex = -1;
|
|
17
20
|
const dispatch = (index, currentRequest) => {
|
|
@@ -26,6 +29,27 @@ export function withPlugins(provider, plugins) {
|
|
|
26
29
|
};
|
|
27
30
|
return dispatch(0, request);
|
|
28
31
|
},
|
|
32
|
+
stream(request) {
|
|
33
|
+
let lastIndex = -1;
|
|
34
|
+
const dispatch = (index, currentRequest) => {
|
|
35
|
+
if (index <= lastIndex) {
|
|
36
|
+
throw new Error('A GenAIcode plugin called next() more than once.');
|
|
37
|
+
}
|
|
38
|
+
lastIndex = index;
|
|
39
|
+
const plugin = plugins[index];
|
|
40
|
+
if (!plugin) {
|
|
41
|
+
return provider.stream
|
|
42
|
+
? providerStream(provider, currentRequest)
|
|
43
|
+
: generateAsStream((nextRequest) => provider.generate(nextRequest), currentRequest);
|
|
44
|
+
}
|
|
45
|
+
if (plugin.stream) {
|
|
46
|
+
return plugin.stream(currentRequest, (nextRequest = currentRequest) => dispatch(index + 1, nextRequest));
|
|
47
|
+
}
|
|
48
|
+
return dispatch(index + 1, currentRequest);
|
|
49
|
+
};
|
|
50
|
+
return dispatch(0, request);
|
|
51
|
+
},
|
|
29
52
|
};
|
|
53
|
+
return wrapped;
|
|
30
54
|
}
|
|
31
55
|
//# sourceMappingURL=plugins.js.map
|
package/dist/core/plugins.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugins.js","sourceRoot":"","sources":["../../src/core/plugins.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"plugins.js","sourceRoot":"","sources":["../../src/core/plugins.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAgB/D,MAAM,UAAU,YAAY,CAAC,MAAmB;IAC9C,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CAAC,QAAuB,EAAE,OAA+B;IAClF,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,QAAQ,CAAC;IAE1C,MAAM,OAAO,GAAkB;QAC7B,IAAI,EAAE,QAAQ,CAAC,IAAI;QACnB,YAAY,EAAE,QAAQ,CAAC,YAAY;QACnC,QAAQ,CAAC,OAAO;YACd,IAAI,SAAS,GAAG,CAAC,CAAC,CAAC;YACnB,MAAM,QAAQ,GAAG,CAAC,KAAa,EAAE,cAAiC,EAA6B,EAAE;gBAC/F,IAAI,KAAK,IAAI,SAAS,EAAE,CAAC;oBACvB,OAAO,OAAO,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,kDAAkD,CAAC,CAAC,CAAC;gBACvF,CAAC;gBACD,SAAS,GAAG,KAAK,CAAC;gBAClB,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;gBAC9B,IAAI,CAAC,MAAM;oBAAE,OAAO,QAAQ,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC;gBACtD,OAAO,MAAM,CAAC,QAAQ,CAAC,cAAc,EAAE,CAAC,WAAW,GAAG,cAAc,EAAE,EAAE,CAAC,QAAQ,CAAC,KAAK,GAAG,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC;YAC7G,CAAC,CAAC;YACF,OAAO,QAAQ,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;QAC9B,CAAC;QACD,MAAM,CAAC,OAAO;YACZ,IAAI,SAAS,GAAG,CAAC,CAAC,CAAC;YACnB,MAAM,QAAQ,GAAG,CAAC,KAAa,EAAE,cAAiC,EAA8B,EAAE;gBAChG,IAAI,KAAK,IAAI,SAAS,EAAE,CAAC;oBACvB,MAAM,IAAI,KAAK,CAAC,kDAAkD,CAAC,CAAC;gBACtE,CAAC;gBACD,SAAS,GAAG,KAAK,CAAC;gBAClB,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;gBAC9B,IAAI,CAAC,MAAM,EAAE,CAAC;oBACZ,OAAO,QAAQ,CAAC,MAAM;wBACpB,CAAC,CAAC,cAAc,CAAC,QAAQ,EAAE,cAAc,CAAC;wBAC1C,CAAC,CAAC,gBAAgB,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,cAAc,CAAC,CAAC;gBACxF,CAAC;gBACD,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;oBAClB,OAAO,MAAM,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC,WAAW,GAAG,cAAc,EAAE,EAAE,CAAC,QAAQ,CAAC,KAAK,GAAG,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC;gBAC3G,CAAC;gBACD,OAAO,QAAQ,CAAC,KAAK,GAAG,CAAC,EAAE,cAAc,CAAC,CAAC;YAC7C,CAAC,CAAC;YACF,OAAO,QAAQ,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;QAC9B,CAAC;KACF,CAAC;IAEF,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
package/dist/core/result.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { GenerationResult, PromptItem, ToolCall } from './types.js';
|
|
1
|
+
import type { GenerationResult, JsonResultParser, PromptItem, ToolCall } from './types.js';
|
|
2
2
|
export declare function resultText(result: GenerationResult): string;
|
|
3
3
|
export declare function resultToolCalls(result: GenerationResult): ToolCall[];
|
|
4
4
|
export declare function resultToPromptItem(result: GenerationResult): PromptItem;
|
|
5
|
-
export declare function parseJsonResult<T = unknown>(result: GenerationResult, parse?:
|
|
5
|
+
export declare function parseJsonResult<T = unknown>(result: GenerationResult, parse?: JsonResultParser<T>): T;
|
package/dist/core/result.js
CHANGED
|
@@ -18,6 +18,10 @@ export function resultToPromptItem(result) {
|
|
|
18
18
|
export function parseJsonResult(result, parse = (value) => value) {
|
|
19
19
|
const text = resultText(result).trim();
|
|
20
20
|
const fenced = /^```(?:json)?\s*([\s\S]*?)\s*```$/i.exec(text);
|
|
21
|
-
|
|
21
|
+
const parsedValue = JSON.parse(fenced?.[1] ?? text);
|
|
22
|
+
if (typeof parse === 'function') {
|
|
23
|
+
return parse(parsedValue);
|
|
24
|
+
}
|
|
25
|
+
return parse.parse(parsedValue);
|
|
22
26
|
}
|
|
23
27
|
//# sourceMappingURL=result.js.map
|
package/dist/core/result.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"result.js","sourceRoot":"","sources":["../../src/core/result.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,UAAU,CAAC,MAAwB;IACjD,OAAO,MAAM,CAAC,KAAK;SAChB,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,MAAM,CAAC;SACtC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC;SACxB,IAAI,CAAC,EAAE,CAAC,CAAC;AACd,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,MAAwB;IACtD,OAAO,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;AAC9F,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,MAAwB;IACzD,OAAO;QACL,IAAI,EAAE,WAAW;QACjB,IAAI,EAAE,UAAU,CAAC,MAAM,CAAC,IAAI,SAAS;QACrC,SAAS,EAAE,eAAe,CAAC,MAAM,CAAC;QAClC,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC;KACvF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,eAAe,CAC7B,MAAwB,EACxB,
|
|
1
|
+
{"version":3,"file":"result.js","sourceRoot":"","sources":["../../src/core/result.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,UAAU,CAAC,MAAwB;IACjD,OAAO,MAAM,CAAC,KAAK;SAChB,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,MAAM,CAAC;SACtC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC;SACxB,IAAI,CAAC,EAAE,CAAC,CAAC;AACd,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,MAAwB;IACtD,OAAO,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;AAC9F,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,MAAwB;IACzD,OAAO;QACL,IAAI,EAAE,WAAW;QACjB,IAAI,EAAE,UAAU,CAAC,MAAM,CAAC,IAAI,SAAS;QACrC,SAAS,EAAE,eAAe,CAAC,MAAM,CAAC;QAClC,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC;KACvF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,eAAe,CAC7B,MAAwB,EACxB,QAA6B,CAAC,KAAK,EAAE,EAAE,CAAC,KAAU;IAElD,MAAM,IAAI,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;IACvC,MAAM,MAAM,GAAG,oCAAoC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC/D,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,CAAY,CAAC;IAC/D,IAAI,OAAO,KAAK,KAAK,UAAU,EAAE,CAAC;QAChC,OAAO,KAAK,CAAC,WAAW,CAAC,CAAC;IAC5B,CAAC;IACD,OAAO,KAAK,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;AAClC,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { GenerationResult, ModelProvider, StreamEvent } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Turn a completed generation into a short synthetic stream.
|
|
4
|
+
* Used when a provider (or plugin chain) has no native `stream` implementation.
|
|
5
|
+
*/
|
|
6
|
+
export declare function generateAsStream(generate: (request: Parameters<ModelProvider['generate']>[0]) => Promise<GenerationResult>, request: Parameters<ModelProvider['generate']>[0]): AsyncGenerator<StreamEvent>;
|
|
7
|
+
export declare function providerStream(provider: ModelProvider, request: Parameters<ModelProvider['generate']>[0]): AsyncIterable<StreamEvent>;
|
|
8
|
+
/** Collect a stream into the final `GenerationResult` (from `done` or by accumulation). */
|
|
9
|
+
export declare function collectStream(events: AsyncIterable<StreamEvent>): Promise<GenerationResult>;
|
|
10
|
+
/** Yield only text deltas from a stream. */
|
|
11
|
+
export declare function streamTextDeltas(events: AsyncIterable<StreamEvent>): AsyncGenerator<string>;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { resultText, resultToolCalls } from './result.js';
|
|
2
|
+
/**
|
|
3
|
+
* Turn a completed generation into a short synthetic stream.
|
|
4
|
+
* Used when a provider (or plugin chain) has no native `stream` implementation.
|
|
5
|
+
*/
|
|
6
|
+
export async function* generateAsStream(generate, request) {
|
|
7
|
+
try {
|
|
8
|
+
const result = await generate(request);
|
|
9
|
+
const text = resultText(result);
|
|
10
|
+
if (text) {
|
|
11
|
+
yield { type: 'text-delta', text };
|
|
12
|
+
}
|
|
13
|
+
for (const toolCall of resultToolCalls(result)) {
|
|
14
|
+
yield { type: 'tool-call', toolCall };
|
|
15
|
+
}
|
|
16
|
+
for (const part of result.parts) {
|
|
17
|
+
if (part.type === 'image') {
|
|
18
|
+
yield { type: 'image', image: part.image };
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
if (result.usage) {
|
|
22
|
+
yield { type: 'usage', usage: result.usage };
|
|
23
|
+
}
|
|
24
|
+
yield { type: 'done', result };
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
yield { type: 'error', error };
|
|
28
|
+
throw error;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
export function providerStream(provider, request) {
|
|
32
|
+
if (provider.stream) {
|
|
33
|
+
return provider.stream(request);
|
|
34
|
+
}
|
|
35
|
+
return generateAsStream((nextRequest) => provider.generate(nextRequest), request);
|
|
36
|
+
}
|
|
37
|
+
/** Collect a stream into the final `GenerationResult` (from `done` or by accumulation). */
|
|
38
|
+
export async function collectStream(events) {
|
|
39
|
+
let text = '';
|
|
40
|
+
const toolCalls = [];
|
|
41
|
+
const images = [];
|
|
42
|
+
let usage;
|
|
43
|
+
let model;
|
|
44
|
+
let finishReason;
|
|
45
|
+
let raw;
|
|
46
|
+
let doneResult;
|
|
47
|
+
for await (const event of events) {
|
|
48
|
+
switch (event.type) {
|
|
49
|
+
case 'text-delta':
|
|
50
|
+
text += event.text;
|
|
51
|
+
break;
|
|
52
|
+
case 'tool-call':
|
|
53
|
+
toolCalls.push(event.toolCall);
|
|
54
|
+
break;
|
|
55
|
+
case 'image':
|
|
56
|
+
images.push({ type: 'image', image: event.image });
|
|
57
|
+
break;
|
|
58
|
+
case 'usage':
|
|
59
|
+
usage = event.usage;
|
|
60
|
+
break;
|
|
61
|
+
case 'done':
|
|
62
|
+
doneResult = event.result;
|
|
63
|
+
break;
|
|
64
|
+
case 'error':
|
|
65
|
+
throw event.error instanceof Error ? event.error : new Error(String(event.error));
|
|
66
|
+
case 'tool-call-delta':
|
|
67
|
+
break;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
if (doneResult) {
|
|
71
|
+
return doneResult;
|
|
72
|
+
}
|
|
73
|
+
const parts = [];
|
|
74
|
+
if (text)
|
|
75
|
+
parts.push({ type: 'text', text });
|
|
76
|
+
for (const toolCall of toolCalls) {
|
|
77
|
+
parts.push({ type: 'toolCall', toolCall });
|
|
78
|
+
}
|
|
79
|
+
parts.push(...images);
|
|
80
|
+
return { parts, model, finishReason, usage, raw };
|
|
81
|
+
}
|
|
82
|
+
/** Yield only text deltas from a stream. */
|
|
83
|
+
export async function* streamTextDeltas(events) {
|
|
84
|
+
for await (const event of events) {
|
|
85
|
+
if (event.type === 'text-delta' && event.text) {
|
|
86
|
+
yield event.text;
|
|
87
|
+
}
|
|
88
|
+
else if (event.type === 'error') {
|
|
89
|
+
throw event.error instanceof Error ? event.error : new Error(String(event.error));
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=stream.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stream.js","sourceRoot":"","sources":["../../src/core/stream.ts"],"names":[],"mappings":"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"}
|