@codeworksh/aikit 0.4.0 → 0.4.1-dev.20260530133305
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/LICENSE +21 -0
- package/README.md +109 -137
- package/cli.d.mts +1 -0
- package/cli.mjs +308 -0
- package/cli.mjs.map +1 -0
- package/codex-DfYk740t.mjs +521 -0
- package/codex-DfYk740t.mjs.map +1 -0
- package/index.d.mts +7197 -0
- package/index.mjs +1478 -0
- package/index.mjs.map +1 -0
- package/oauth/openai/codex.d.mts +107 -0
- package/oauth/openai/codex.mjs +2 -0
- package/package.json +28 -33
- package/{dist/pack/index.mjs → registry-CYfzJ6lk.mjs} +210 -3300
- package/registry-CYfzJ6lk.mjs.map +1 -0
- package/dist/pack/agent/codemode/drivers/drivers.d.mts +0 -7
- package/dist/pack/agent/codemode/drivers/drivers.mjs +0 -122
- package/dist/pack/agent/codemode/drivers/drivers.mjs.map +0 -1
- package/dist/pack/codemode-BEDXG7WN.d.mts +0 -8736
- package/dist/pack/index.d.mts +0 -71
- package/dist/pack/index.mjs.map +0 -1
- package/src/agent/agent.ts +0 -790
- package/src/agent/codemode/codemode.ts +0 -561
- package/src/agent/codemode/drivers/drivers.ts +0 -1
- package/src/agent/codemode/drivers/quickjs-wasi-driver.ts +0 -149
- package/src/agent/codemode/index.ts +0 -1
- package/src/agent/loop.ts +0 -903
- package/src/agent.ts +0 -11
- package/src/event/event.ts +0 -277
- package/src/index.ts +0 -6
- package/src/llm.ts +0 -31
- package/src/message/message.ts +0 -311
- package/src/model/catalog.ts +0 -94
- package/src/model/model.ts +0 -250
- package/src/model/transform.ts +0 -59
- package/src/provider/provider.ts +0 -60
- package/src/provider/providers/anthropic/index.ts +0 -792
- package/src/provider/providers/github/github.ts +0 -34
- package/src/provider/providers/openai/completions.ts +0 -953
- package/src/provider/providers/utils.ts +0 -7
- package/src/provider/register.ts +0 -6
- package/src/provider/stream.ts +0 -278
- package/src/stream.ts +0 -72
- package/src/utils/eventstream.ts +0 -95
- package/src/utils/helpers.ts +0 -24
- package/src/utils/jsonparse.ts +0 -32
- package/src/utils/overflow.ts +0 -121
- package/src/utils/sanitize.ts +0 -25
- package/src/utils/validation.ts +0 -87
package/src/provider/register.ts
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import anthropicProvider from "./providers/anthropic/index";
|
|
2
|
-
import openAICompletionsProvider from "./providers/openai/completions";
|
|
3
|
-
import { Stream } from "./stream";
|
|
4
|
-
|
|
5
|
-
Stream.registerProtocolProvider(anthropicProvider, "providers/anthropic/index.ts");
|
|
6
|
-
Stream.registerProtocolProvider(openAICompletionsProvider, "providers/openai/completions.ts");
|
package/src/provider/stream.ts
DELETED
|
@@ -1,278 +0,0 @@
|
|
|
1
|
-
import { NamedError } from "@codeworksh/utils";
|
|
2
|
-
import Type, { type Static } from "typebox";
|
|
3
|
-
import type { Message } from "../message/message";
|
|
4
|
-
import { Model } from "../model/model";
|
|
5
|
-
import type { AssistantMessageEventStream } from "../utils/eventstream";
|
|
6
|
-
|
|
7
|
-
export namespace Stream {
|
|
8
|
-
export const ProtocolProviderNotFoundError = NamedError.create(
|
|
9
|
-
"ProtocolProviderNotFoundError",
|
|
10
|
-
Type.Object({
|
|
11
|
-
protocol: Model.KnownProtocolSchema,
|
|
12
|
-
}),
|
|
13
|
-
);
|
|
14
|
-
export type ProtocolProviderNotFoundError = InstanceType<typeof ProtocolProviderNotFoundError>;
|
|
15
|
-
|
|
16
|
-
export const ProtocolMismatchError = NamedError.create(
|
|
17
|
-
"ProtocolMismatchError",
|
|
18
|
-
Type.Object({
|
|
19
|
-
actual: Model.KnownProtocolSchema,
|
|
20
|
-
expected: Model.KnownProtocolSchema,
|
|
21
|
-
}),
|
|
22
|
-
);
|
|
23
|
-
export type ProtocolMismatchError = InstanceType<typeof ProtocolMismatchError>;
|
|
24
|
-
|
|
25
|
-
export const ThinkingLevelEnum = {
|
|
26
|
-
off: "off",
|
|
27
|
-
minimal: "minimal",
|
|
28
|
-
low: "low",
|
|
29
|
-
medium: "medium",
|
|
30
|
-
high: "high",
|
|
31
|
-
xhigh: "xhigh",
|
|
32
|
-
} as const;
|
|
33
|
-
export const ThinkingLevelSchema = Type.Union([
|
|
34
|
-
Type.Literal(ThinkingLevelEnum.off),
|
|
35
|
-
Type.Literal(ThinkingLevelEnum.minimal),
|
|
36
|
-
Type.Literal(ThinkingLevelEnum.low),
|
|
37
|
-
Type.Literal(ThinkingLevelEnum.medium),
|
|
38
|
-
Type.Literal(ThinkingLevelEnum.high),
|
|
39
|
-
Type.Literal(ThinkingLevelEnum.xhigh),
|
|
40
|
-
]);
|
|
41
|
-
export type ThinkingLevel = Static<typeof ThinkingLevelSchema>;
|
|
42
|
-
|
|
43
|
-
export const ThinkingBudgetsSchema = Type.Object({
|
|
44
|
-
off: Type.Optional(Type.Number()),
|
|
45
|
-
minimal: Type.Optional(Type.Number()),
|
|
46
|
-
low: Type.Optional(Type.Number()),
|
|
47
|
-
medium: Type.Optional(Type.Number()),
|
|
48
|
-
high: Type.Optional(Type.Number()),
|
|
49
|
-
});
|
|
50
|
-
export type ThinkingBudgets = Static<typeof ThinkingBudgetsSchema>;
|
|
51
|
-
|
|
52
|
-
export const CacheRetentionSchema = Type.Union([Type.Literal("none"), Type.Literal("short"), Type.Literal("long")]);
|
|
53
|
-
export type CacheRetention = Static<typeof CacheRetentionSchema>;
|
|
54
|
-
|
|
55
|
-
export const TransportSchema = Type.Union([Type.Literal("sse"), Type.Literal("websocket"), Type.Literal("auto")]);
|
|
56
|
-
export type Transport = Static<typeof TransportSchema>;
|
|
57
|
-
|
|
58
|
-
export const OptionsSchema = Type.Object({
|
|
59
|
-
temperature: Type.Optional(Type.Number()),
|
|
60
|
-
maxTokens: Type.Optional(Type.Number()),
|
|
61
|
-
signal: Type.Optional(Type.Unsafe<AbortSignal>({})),
|
|
62
|
-
apiKey: Type.Optional(Type.String()),
|
|
63
|
-
transport: Type.Optional(TransportSchema),
|
|
64
|
-
cacheRetention: Type.Optional(CacheRetentionSchema),
|
|
65
|
-
sessionId: Type.Optional(Type.String()),
|
|
66
|
-
onPayload: Type.Optional(
|
|
67
|
-
Type.Unsafe<(payload: unknown, model: Model.TModel<Model.KnownProtocol>) => unknown>({}),
|
|
68
|
-
),
|
|
69
|
-
headers: Type.Optional(Type.Record(Type.String(), Type.String())),
|
|
70
|
-
maxRetryDelayMs: Type.Optional(Type.Number()),
|
|
71
|
-
metadata: Type.Optional(Type.Record(Type.String(), Type.Unknown())),
|
|
72
|
-
});
|
|
73
|
-
export type Options = Static<typeof OptionsSchema>;
|
|
74
|
-
export type ProviderOptions = Options & Record<string, unknown>;
|
|
75
|
-
|
|
76
|
-
export const SimpleOptionsSchema = Type.Evaluate(
|
|
77
|
-
Type.Intersect([
|
|
78
|
-
OptionsSchema,
|
|
79
|
-
Type.Object({
|
|
80
|
-
reasoning: Type.Optional(ThinkingLevelSchema),
|
|
81
|
-
thinkingBudgets: Type.Optional(ThinkingBudgetsSchema),
|
|
82
|
-
}),
|
|
83
|
-
]),
|
|
84
|
-
);
|
|
85
|
-
export type SimpleOptions = Static<typeof SimpleOptionsSchema>;
|
|
86
|
-
|
|
87
|
-
// Contract:
|
|
88
|
-
// - Must return an AssistantMessageEventStream.
|
|
89
|
-
// - Once invoked, request/model/runtime failures should be encoded in the
|
|
90
|
-
// returned stream, not thrown.
|
|
91
|
-
// - Error termination must produce an AssistantMessage with stopReason
|
|
92
|
-
// "error" or "aborted" and errorMessage, emitted via the stream protocol.
|
|
93
|
-
export type StreamFunction<
|
|
94
|
-
TProtocol extends Model.KnownProtocol = Model.KnownProtocol,
|
|
95
|
-
TOptions extends Options = Options,
|
|
96
|
-
> = (model: Model.TModel<TProtocol>, context: Message.Context, options?: TOptions) => AssistantMessageEventStream;
|
|
97
|
-
|
|
98
|
-
export function buildBaseOptions(model: Model.Info, options?: SimpleOptions, apiKey?: string): Options {
|
|
99
|
-
return {
|
|
100
|
-
temperature: options?.temperature,
|
|
101
|
-
maxTokens: options?.maxTokens || Math.min(model.maxTokens, 32000),
|
|
102
|
-
signal: options?.signal,
|
|
103
|
-
apiKey: apiKey || options?.apiKey,
|
|
104
|
-
transport: options?.transport,
|
|
105
|
-
cacheRetention: options?.cacheRetention,
|
|
106
|
-
sessionId: options?.sessionId,
|
|
107
|
-
headers: options?.headers,
|
|
108
|
-
onPayload: options?.onPayload,
|
|
109
|
-
maxRetryDelayMs: options?.maxRetryDelayMs,
|
|
110
|
-
metadata: options?.metadata,
|
|
111
|
-
};
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
export function clampReasoning(effort: ThinkingLevel | undefined): Exclude<ThinkingLevel, "xhigh"> | undefined {
|
|
115
|
-
return effort === ThinkingLevelEnum.xhigh ? ThinkingLevelEnum.high : effort;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
export function adjustMaxTokensForThinking(
|
|
119
|
-
baseMaxTokens: number,
|
|
120
|
-
modelMaxTokens: number,
|
|
121
|
-
reasoningLevel: ThinkingLevel,
|
|
122
|
-
customBudgets?: ThinkingBudgets,
|
|
123
|
-
): { maxTokens: number; thinkingBudget: number } {
|
|
124
|
-
const defaultBudgets: ThinkingBudgets = {
|
|
125
|
-
minimal: 1024,
|
|
126
|
-
low: 2048,
|
|
127
|
-
medium: 8192,
|
|
128
|
-
high: 16384,
|
|
129
|
-
};
|
|
130
|
-
const budgets = { ...defaultBudgets, ...customBudgets };
|
|
131
|
-
const minOutputTokens = 1024;
|
|
132
|
-
const level = clampReasoning(reasoningLevel)!;
|
|
133
|
-
let thinkingBudget = budgets[level]!;
|
|
134
|
-
const maxTokens = Math.min(baseMaxTokens + thinkingBudget, modelMaxTokens);
|
|
135
|
-
|
|
136
|
-
if (maxTokens <= thinkingBudget) {
|
|
137
|
-
thinkingBudget = Math.max(0, maxTokens - minOutputTokens);
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
return { maxTokens, thinkingBudget };
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
export type ProtocolStreamFunction = (
|
|
144
|
-
model: Model.Info,
|
|
145
|
-
context: Message.Context,
|
|
146
|
-
options?: Options,
|
|
147
|
-
) => AssistantMessageEventStream;
|
|
148
|
-
|
|
149
|
-
export type ProtocolStreamSimpleFunction = (
|
|
150
|
-
model: Model.Info,
|
|
151
|
-
context: Message.Context,
|
|
152
|
-
options?: SimpleOptions,
|
|
153
|
-
) => AssistantMessageEventStream;
|
|
154
|
-
|
|
155
|
-
export interface ProtocolProvider<
|
|
156
|
-
TProtocol extends Model.KnownProtocol = Model.KnownProtocol,
|
|
157
|
-
TOptions extends Options = Options,
|
|
158
|
-
> {
|
|
159
|
-
protocol: TProtocol;
|
|
160
|
-
stream: StreamFunction<TProtocol, TOptions>;
|
|
161
|
-
streamSimple: StreamFunction<TProtocol, SimpleOptions>;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
type RegisteredProtocolProvider = {
|
|
165
|
-
provider: ProtocolProvider<Model.KnownProtocol, Options>;
|
|
166
|
-
sourceId?: string;
|
|
167
|
-
};
|
|
168
|
-
|
|
169
|
-
const protocolProviderRegistry = new Map<Model.KnownProtocol, RegisteredProtocolProvider>();
|
|
170
|
-
|
|
171
|
-
function wrapStream<TProtocol extends Model.KnownProtocol, TOptions extends Options>(
|
|
172
|
-
protocol: TProtocol,
|
|
173
|
-
stream: StreamFunction<TProtocol, TOptions>,
|
|
174
|
-
): ProtocolStreamFunction {
|
|
175
|
-
return (model, context, options) => {
|
|
176
|
-
if (model.protocol !== protocol) {
|
|
177
|
-
throw new ProtocolMismatchError({
|
|
178
|
-
actual: model.protocol,
|
|
179
|
-
expected: protocol,
|
|
180
|
-
});
|
|
181
|
-
}
|
|
182
|
-
return stream(model as Model.TModel<TProtocol>, context, options as TOptions);
|
|
183
|
-
};
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
function wrapStreamSimple<TProtocol extends Model.KnownProtocol>(
|
|
187
|
-
protocol: TProtocol,
|
|
188
|
-
streamSimple: StreamFunction<TProtocol, SimpleOptions>,
|
|
189
|
-
): ProtocolStreamSimpleFunction {
|
|
190
|
-
return (model, context, options) => {
|
|
191
|
-
if (model.protocol !== protocol) {
|
|
192
|
-
throw new ProtocolMismatchError({
|
|
193
|
-
actual: model.protocol,
|
|
194
|
-
expected: protocol,
|
|
195
|
-
});
|
|
196
|
-
}
|
|
197
|
-
return streamSimple(model as Model.TModel<TProtocol>, context, options);
|
|
198
|
-
};
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
export function registerProtocolProvider<TProtocol extends Model.KnownProtocol, TOptions extends Options>(
|
|
202
|
-
provider: ProtocolProvider<TProtocol, TOptions>,
|
|
203
|
-
sourceId?: string,
|
|
204
|
-
): void {
|
|
205
|
-
protocolProviderRegistry.set(provider.protocol, {
|
|
206
|
-
provider: {
|
|
207
|
-
protocol: provider.protocol,
|
|
208
|
-
stream: wrapStream(provider.protocol, provider.stream),
|
|
209
|
-
streamSimple: wrapStreamSimple(provider.protocol, provider.streamSimple),
|
|
210
|
-
},
|
|
211
|
-
sourceId,
|
|
212
|
-
});
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
export function getProtocolProvider(
|
|
216
|
-
protocol: Model.KnownProtocol,
|
|
217
|
-
): ProtocolProvider<Model.KnownProtocol, Options> | undefined {
|
|
218
|
-
return protocolProviderRegistry.get(protocol)?.provider;
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
export function resolveProtocolProvider(model: Model.Info): ProtocolProvider<Model.KnownProtocol, Options> {
|
|
222
|
-
const provider = getProtocolProvider(model.protocol);
|
|
223
|
-
if (!provider) {
|
|
224
|
-
throw new ProtocolProviderNotFoundError({
|
|
225
|
-
protocol: model.protocol,
|
|
226
|
-
});
|
|
227
|
-
}
|
|
228
|
-
return provider;
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
export function stream(model: Model.Info, context: Message.Context, options?: Options): AssistantMessageEventStream {
|
|
232
|
-
const provider = resolveProtocolProvider(model);
|
|
233
|
-
return provider.stream(model, context, options);
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
export async function complete(
|
|
237
|
-
model: Model.Info,
|
|
238
|
-
context: Message.Context,
|
|
239
|
-
options?: Options,
|
|
240
|
-
): Promise<Message.AssistantMessage> {
|
|
241
|
-
const s = stream(model, context, options);
|
|
242
|
-
return s.result();
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
export function streamSimple(
|
|
246
|
-
model: Model.Info,
|
|
247
|
-
context: Message.Context,
|
|
248
|
-
options?: SimpleOptions,
|
|
249
|
-
): AssistantMessageEventStream {
|
|
250
|
-
const provider = resolveProtocolProvider(model);
|
|
251
|
-
return provider.streamSimple(model, context, options);
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
export async function completeSimple(
|
|
255
|
-
model: Model.Info,
|
|
256
|
-
context: Message.Context,
|
|
257
|
-
options?: SimpleOptions,
|
|
258
|
-
): Promise<Message.AssistantMessage> {
|
|
259
|
-
const s = streamSimple(model, context, options);
|
|
260
|
-
return s.result();
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
export function getApiProviders(): ProtocolProvider<Model.KnownProtocol, Options>[] {
|
|
264
|
-
return Array.from(protocolProviderRegistry.values(), (entry) => entry.provider);
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
export function unregisterProtocolProviders(sourceId: string): void {
|
|
268
|
-
for (const [api, entry] of protocolProviderRegistry.entries()) {
|
|
269
|
-
if (entry.sourceId === sourceId) {
|
|
270
|
-
protocolProviderRegistry.delete(api);
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
export function clearProtocolProviders(): void {
|
|
276
|
-
protocolProviderRegistry.clear();
|
|
277
|
-
}
|
|
278
|
-
}
|
package/src/stream.ts
DELETED
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
import "./provider/register";
|
|
2
|
-
|
|
3
|
-
import type { Message } from "./message/message";
|
|
4
|
-
import type { Model } from "./model/model";
|
|
5
|
-
import { Stream } from "./provider/stream";
|
|
6
|
-
import type { AssistantMessageEventStream } from "./utils/eventstream";
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Stream assistant responses for a model and context.
|
|
10
|
-
*
|
|
11
|
-
* Example:
|
|
12
|
-
*
|
|
13
|
-
* ```ts
|
|
14
|
-
* const s = stream(model, context, {
|
|
15
|
-
* apiKey: process.env.ANTHROPIC_API_KEY,
|
|
16
|
-
* });
|
|
17
|
-
*
|
|
18
|
-
* for await (const event of s) {
|
|
19
|
-
* if (event.type === "text.delta") {
|
|
20
|
-
* process.stdout.write(event.delta);
|
|
21
|
-
* }
|
|
22
|
-
* }
|
|
23
|
-
*
|
|
24
|
-
* const message = await s.result();
|
|
25
|
-
* ```
|
|
26
|
-
*
|
|
27
|
-
* This export also includes convenience helpers:
|
|
28
|
-
*
|
|
29
|
-
* ```ts
|
|
30
|
-
* const message = await stream.complete(model, context, options);
|
|
31
|
-
* const simple = stream.simple(model, context, options);
|
|
32
|
-
* const simpleMessage = await stream.completeSimple(model, context, options);
|
|
33
|
-
* ```
|
|
34
|
-
*/
|
|
35
|
-
type StreamCallable = {
|
|
36
|
-
(model: Model.Info, context: Message.Context, options?: Stream.Options): AssistantMessageEventStream;
|
|
37
|
-
complete: typeof Stream.complete;
|
|
38
|
-
simple: typeof Stream.streamSimple;
|
|
39
|
-
completeSimple: typeof Stream.completeSimple;
|
|
40
|
-
resolveProtocolProvider: typeof Stream.resolveProtocolProvider;
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
const streamImpl = (
|
|
44
|
-
model: Model.Info,
|
|
45
|
-
context: Message.Context,
|
|
46
|
-
options?: Stream.Options,
|
|
47
|
-
): AssistantMessageEventStream => Stream.stream(model, context, options);
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Start a streaming assistant response for a model/context pair.
|
|
51
|
-
*
|
|
52
|
-
* This is the main streaming entrypoint.
|
|
53
|
-
* Attached helpers:
|
|
54
|
-
*
|
|
55
|
-
* - `stream.complete(...)` resolves the final assistant message without manually iterating events.
|
|
56
|
-
* - `stream.simple(...)` uses `Stream.SimpleOptions` for higher-level reasoning controls.
|
|
57
|
-
* - `stream.completeSimple(...)` is the non-streaming counterpart to `stream.simple(...)`.
|
|
58
|
-
* - `stream.resolveProtocolProvider(...)` exposes protocol resolution for advanced integrations.
|
|
59
|
-
*/
|
|
60
|
-
export const stream = Object.assign(streamImpl, {
|
|
61
|
-
complete: Stream.complete,
|
|
62
|
-
simple: Stream.streamSimple,
|
|
63
|
-
completeSimple: Stream.completeSimple,
|
|
64
|
-
resolveProtocolProvider: Stream.resolveProtocolProvider,
|
|
65
|
-
}) as StreamCallable;
|
|
66
|
-
|
|
67
|
-
/** Resolve a streamed response directly to the final assistant message. */
|
|
68
|
-
export const complete = Stream.complete;
|
|
69
|
-
/** Start a stream using the simplified options surface. */
|
|
70
|
-
export const streamSimple = Stream.streamSimple;
|
|
71
|
-
/** Resolve a simplified stream request directly to the final assistant message. */
|
|
72
|
-
export const completeSimple = Stream.completeSimple;
|
package/src/utils/eventstream.ts
DELETED
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @description Defines the Generic event stream class for async iteration.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import type { Event } from "../event/event";
|
|
6
|
-
import type { Message } from "../message/message";
|
|
7
|
-
|
|
8
|
-
// Implements the async iterator pattern
|
|
9
|
-
// LLM output are streams of events for consuming
|
|
10
|
-
// This class helps with that by acting like buffer data structure to manage the streams
|
|
11
|
-
// for producer and consumer
|
|
12
|
-
export class EventStream<T, R = T> implements AsyncIterable<T> {
|
|
13
|
-
private queue: T[] = [];
|
|
14
|
-
private waiting: ((value: IteratorResult<T>) => void)[] = [];
|
|
15
|
-
private done = false;
|
|
16
|
-
private readonly finalResultPromise: Promise<R>;
|
|
17
|
-
private resolveFinalResult!: (result: R) => void;
|
|
18
|
-
|
|
19
|
-
constructor(
|
|
20
|
-
private isComplete: (event: T) => boolean,
|
|
21
|
-
private extractResult: (event: T) => R,
|
|
22
|
-
) {
|
|
23
|
-
this.finalResultPromise = new Promise((resolve) => {
|
|
24
|
-
this.resolveFinalResult = resolve;
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
push(event: T): void {
|
|
29
|
-
if (this.done) return;
|
|
30
|
-
|
|
31
|
-
if (this.isComplete(event)) {
|
|
32
|
-
this.done = true;
|
|
33
|
-
this.resolveFinalResult(this.extractResult(event));
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// Deliver to waiting consumer or queue it
|
|
37
|
-
const waiter = this.waiting.shift();
|
|
38
|
-
if (waiter) {
|
|
39
|
-
waiter({ value: event, done: false });
|
|
40
|
-
} else {
|
|
41
|
-
this.queue.push(event);
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
end(result?: R): void {
|
|
46
|
-
this.done = true;
|
|
47
|
-
if (result !== undefined) {
|
|
48
|
-
this.resolveFinalResult(result);
|
|
49
|
-
}
|
|
50
|
-
// Notify all waiting consumers that we're done
|
|
51
|
-
while (this.waiting.length > 0) {
|
|
52
|
-
const waiter = this.waiting.shift()!;
|
|
53
|
-
waiter({ value: undefined as any, done: true });
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
async *[Symbol.asyncIterator](): AsyncIterator<T> {
|
|
58
|
-
while (true) {
|
|
59
|
-
if (this.queue.length > 0) {
|
|
60
|
-
yield this.queue.shift()!;
|
|
61
|
-
} else if (this.done) {
|
|
62
|
-
return;
|
|
63
|
-
} else {
|
|
64
|
-
const result = await new Promise<IteratorResult<T>>((resolve) => this.waiting.push(resolve));
|
|
65
|
-
if (result.done) return;
|
|
66
|
-
yield result.value;
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
result(): Promise<R> {
|
|
72
|
-
return this.finalResultPromise;
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
export class AssistantMessageEventStream extends EventStream<Event.LLMMessageEvent, Message.AssistantMessage> {
|
|
77
|
-
constructor() {
|
|
78
|
-
super(
|
|
79
|
-
(event) => event.type === "done" || event.type === "error",
|
|
80
|
-
(event) => {
|
|
81
|
-
if (event.type === "done") {
|
|
82
|
-
return event.message;
|
|
83
|
-
} else if (event.type === "error") {
|
|
84
|
-
return event.error;
|
|
85
|
-
}
|
|
86
|
-
throw new Error("Unexpected event type for final result");
|
|
87
|
-
},
|
|
88
|
-
);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
/** Factory function for AssistantMessageEventStream (for use in extensions) */
|
|
93
|
-
export function createAssistantMessageEventStream(): AssistantMessageEventStream {
|
|
94
|
-
return new AssistantMessageEventStream();
|
|
95
|
-
}
|
package/src/utils/helpers.ts
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import Type, { type TUnsafe } from "typebox";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Creates a string enum schema compatible with Google's API and other providers
|
|
5
|
-
* that don't support anyOf/const patterns.
|
|
6
|
-
*
|
|
7
|
-
* @example
|
|
8
|
-
* const OperationSchema = StringEnum(["add", "subtract", "multiply", "divide"], {
|
|
9
|
-
* description: "The operation to perform"
|
|
10
|
-
* });
|
|
11
|
-
*
|
|
12
|
-
* type Operation = Static<typeof OperationSchema>; // "add" | "subtract" | "multiply" | "divide"
|
|
13
|
-
*/
|
|
14
|
-
export function StringEnum<T extends readonly string[]>(
|
|
15
|
-
values: T,
|
|
16
|
-
options?: { description?: string; default?: T[number] },
|
|
17
|
-
): TUnsafe<T[number]> {
|
|
18
|
-
return Type.Unsafe<T[number]>({
|
|
19
|
-
type: "string",
|
|
20
|
-
enum: values as any,
|
|
21
|
-
...(options?.description && { description: options.description }),
|
|
22
|
-
...(options?.default && { default: options.default }),
|
|
23
|
-
});
|
|
24
|
-
}
|
package/src/utils/jsonparse.ts
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @description Helper function to parse partial jsons during LLM streaming.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { parse as partialParse } from "partial-json";
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Attempts to parse potentially incomplete JSON during streaming.
|
|
9
|
-
* Always returns a valid object, even if the JSON is incomplete.
|
|
10
|
-
*
|
|
11
|
-
* @param partialJson The partial JSON string from streaming
|
|
12
|
-
* @returns Parsed object or empty object if parsing fails
|
|
13
|
-
*/
|
|
14
|
-
export function parseStreamingJson<T = any>(partialJson: string | undefined): T {
|
|
15
|
-
if (!partialJson || partialJson.trim() === "") {
|
|
16
|
-
return {} as T;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
// Try standard parsing first (fastest for complete JSON)
|
|
20
|
-
try {
|
|
21
|
-
return JSON.parse(partialJson) as T;
|
|
22
|
-
} catch {
|
|
23
|
-
// Try partial-json for incomplete JSON
|
|
24
|
-
try {
|
|
25
|
-
const result = partialParse(partialJson);
|
|
26
|
-
return (result ?? {}) as T;
|
|
27
|
-
} catch {
|
|
28
|
-
// If all parsing fails, return empty object
|
|
29
|
-
return {} as T;
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
}
|
package/src/utils/overflow.ts
DELETED
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
import type { Message } from "../message/message";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Regex patterns to detect context overflow errors from different providers.
|
|
5
|
-
*
|
|
6
|
-
* These patterns match error messages returned when the input exceeds
|
|
7
|
-
* the model's context window.
|
|
8
|
-
*
|
|
9
|
-
* Provider-specific patterns (with example error messages):
|
|
10
|
-
*
|
|
11
|
-
* - Anthropic: "prompt is too long: 213462 tokens > 200000 maximum"
|
|
12
|
-
* - OpenAI: "Your input exceeds the context window of this model"
|
|
13
|
-
* - Google: "The input token count (1196265) exceeds the maximum number of tokens allowed (1048575)"
|
|
14
|
-
* - xAI: "This model's maximum prompt length is 131072 but the request contains 537812 tokens"
|
|
15
|
-
* - Groq: "Please reduce the length of the messages or completion"
|
|
16
|
-
* - OpenRouter: "This endpoint's maximum context length is X tokens. However, you requested about Y tokens"
|
|
17
|
-
* - llama.cpp: "the request exceeds the available context size, try increasing it"
|
|
18
|
-
* - LM Studio: "tokens to keep from the initial prompt is greater than the context length"
|
|
19
|
-
* - GitHub Copilot: "prompt token count of X exceeds the limit of Y"
|
|
20
|
-
* - MiniMax: "invalid params, context window exceeds limit"
|
|
21
|
-
* - Kimi For Coding: "Your request exceeded model token limit: X (requested: Y)"
|
|
22
|
-
* - Cerebras: Returns "400/413 status code (no body)" - handled separately below
|
|
23
|
-
* - Mistral: Returns "400/413 status code (no body)" - handled separately below
|
|
24
|
-
* - z.ai: Does NOT error, accepts overflow silently - handled via usage.input > contextWindow
|
|
25
|
-
* - Ollama: Silently truncates input - not detectable via error message
|
|
26
|
-
*/
|
|
27
|
-
const OVERFLOW_PATTERNS = [
|
|
28
|
-
/prompt is too long/i, // Anthropic
|
|
29
|
-
/input is too long for requested model/i, // Amazon Bedrock
|
|
30
|
-
/exceeds the context window/i, // OpenAI (Completions & Responses API)
|
|
31
|
-
/input token count.*exceeds the maximum/i, // Google (Gemini)
|
|
32
|
-
/maximum prompt length is \d+/i, // xAI (Grok)
|
|
33
|
-
/reduce the length of the messages/i, // Groq
|
|
34
|
-
/maximum context length is \d+ tokens/i, // OpenRouter (all backends)
|
|
35
|
-
/exceeds the limit of \d+/i, // GitHub Copilot
|
|
36
|
-
/exceeds the available context size/i, // llama.cpp server
|
|
37
|
-
/greater than the context length/i, // LM Studio
|
|
38
|
-
/context window exceeds limit/i, // MiniMax
|
|
39
|
-
/exceeded model token limit/i, // Kimi For Coding
|
|
40
|
-
/context[_ ]length[_ ]exceeded/i, // Generic fallback
|
|
41
|
-
/too many tokens/i, // Generic fallback
|
|
42
|
-
/token limit exceeded/i, // Generic fallback
|
|
43
|
-
];
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Check if an assistant message represents a context overflow error.
|
|
47
|
-
*
|
|
48
|
-
* This handles two cases:
|
|
49
|
-
* 1. Error-based overflow: Most providers return stopReason "error" with a
|
|
50
|
-
* specific error message pattern.
|
|
51
|
-
* 2. Silent overflow: Some providers accept overflow requests and return
|
|
52
|
-
* successfully. For these, we check if usage.input exceeds the context window.
|
|
53
|
-
*
|
|
54
|
-
* ## Reliability by Provider
|
|
55
|
-
*
|
|
56
|
-
* **Reliable detection (returns error with detectable message):**
|
|
57
|
-
* - Anthropic: "prompt is too long: X tokens > Y maximum"
|
|
58
|
-
* - OpenAI (Completions & Responses): "exceeds the context window"
|
|
59
|
-
* - Google Gemini: "input token count exceeds the maximum"
|
|
60
|
-
* - xAI (Grok): "maximum prompt length is X but request contains Y"
|
|
61
|
-
* - Groq: "reduce the length of the messages"
|
|
62
|
-
* - Cerebras: 400/413 status code (no body)
|
|
63
|
-
* - Mistral: 400/413 status code (no body)
|
|
64
|
-
* - OpenRouter (all backends): "maximum context length is X tokens"
|
|
65
|
-
* - llama.cpp: "exceeds the available context size"
|
|
66
|
-
* - LM Studio: "greater than the context length"
|
|
67
|
-
* - Kimi For Coding: "exceeded model token limit: X (requested: Y)"
|
|
68
|
-
*
|
|
69
|
-
* **Unreliable detection:**
|
|
70
|
-
* - z.ai: Sometimes accepts overflow silently (detectable via usage.input > contextWindow),
|
|
71
|
-
* sometimes returns rate limit errors. Pass contextWindow param to detect silent overflow.
|
|
72
|
-
* - Ollama: Silently truncates input without error. Cannot be detected via this function.
|
|
73
|
-
* The response will have usage.input < expected, but we don't know the expected value.
|
|
74
|
-
*
|
|
75
|
-
* ## Custom Providers
|
|
76
|
-
*
|
|
77
|
-
* If you've added custom models via settings.json, this function may not detect
|
|
78
|
-
* overflow errors from those providers. To add support:
|
|
79
|
-
*
|
|
80
|
-
* 1. Send a request that exceeds the model's context window
|
|
81
|
-
* 2. Check the errorMessage in the response
|
|
82
|
-
* 3. Create a regex pattern that matches the error
|
|
83
|
-
* 4. The pattern should be added to OVERFLOW_PATTERNS in this file, or
|
|
84
|
-
* check the errorMessage yourself before calling this function
|
|
85
|
-
*
|
|
86
|
-
* @param message - The assistant message to check
|
|
87
|
-
* @param contextWindow - Optional context window size for detecting silent overflow (z.ai)
|
|
88
|
-
* @returns true if the message indicates a context overflow
|
|
89
|
-
*/
|
|
90
|
-
export function isContextOverflow(message: Message.AssistantMessage, contextWindow?: number): boolean {
|
|
91
|
-
// Case 1: Check error message patterns
|
|
92
|
-
if (message.stopReason === "error" && message.errorMessage) {
|
|
93
|
-
// Check known patterns
|
|
94
|
-
if (OVERFLOW_PATTERNS.some((p) => p.test(message.errorMessage!))) {
|
|
95
|
-
return true;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
// Cerebras and Mistral return 400/413 with no body for context overflow
|
|
99
|
-
// Note: 429 is rate limiting (requests/tokens per time), NOT context overflow
|
|
100
|
-
if (/^4(00|13)\s*(status code)?\s*\(no body\)/i.test(message.errorMessage)) {
|
|
101
|
-
return true;
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// Case 2: Silent overflow (z.ai style) - successful but usage exceeds context
|
|
106
|
-
if (contextWindow && message.stopReason === "stop") {
|
|
107
|
-
const inputTokens = message.usage.input + message.usage.cacheRead;
|
|
108
|
-
if (inputTokens > contextWindow) {
|
|
109
|
-
return true;
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
return false;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* Get the overflow patterns for testing purposes.
|
|
118
|
-
*/
|
|
119
|
-
export function getOverflowPatterns(): RegExp[] {
|
|
120
|
-
return [...OVERFLOW_PATTERNS];
|
|
121
|
-
}
|
package/src/utils/sanitize.ts
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Removes unpaired Unicode surrogate characters from a string.
|
|
3
|
-
*
|
|
4
|
-
* Unpaired surrogates (high surrogates 0xD800-0xDBFF without matching low surrogates 0xDC00-0xDFFF,
|
|
5
|
-
* or vice versa) cause JSON serialization errors in many API providers.
|
|
6
|
-
*
|
|
7
|
-
* Valid emoji and other characters outside the Basic Multilingual Plane use properly paired
|
|
8
|
-
* surrogates and will NOT be affected by this function.
|
|
9
|
-
*
|
|
10
|
-
* @param text - The text to sanitize
|
|
11
|
-
* @returns The sanitized text with unpaired surrogates removed
|
|
12
|
-
*
|
|
13
|
-
* @example
|
|
14
|
-
* // Valid emoji (properly paired surrogates) are preserved
|
|
15
|
-
* sanitizeSurrogates("Hello 🙈 World") // => "Hello 🙈 World"
|
|
16
|
-
*
|
|
17
|
-
* // Unpaired high surrogate is removed
|
|
18
|
-
* const unpaired = String.fromCharCode(0xD83D); // high surrogate without low
|
|
19
|
-
* sanitizeSurrogates(`Text ${unpaired} here`) // => "Text here"
|
|
20
|
-
*/
|
|
21
|
-
export function sanitizeSurrogates(text: string): string {
|
|
22
|
-
// Replace unpaired high surrogates (0xD800-0xDBFF not followed by low surrogate)
|
|
23
|
-
// Replace unpaired low surrogates (0xDC00-0xDFFF not preceded by high surrogate)
|
|
24
|
-
return text.replace(/[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/g, "");
|
|
25
|
-
}
|