@codeworksh/aikit 0.3.0 → 0.4.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.
Files changed (41) hide show
  1. package/README.md +73 -81
  2. package/{agent → dist/pack/agent}/codemode/drivers/drivers.d.mts +1 -1
  3. package/dist/pack/codemode-BEDXG7WN.d.mts +8736 -0
  4. package/{index.d.mts → dist/pack/index.d.mts} +3 -3
  5. package/dist/pack/index.mjs +8226 -0
  6. package/dist/pack/index.mjs.map +1 -0
  7. package/package.json +32 -22
  8. package/src/agent/agent.ts +790 -0
  9. package/src/agent/codemode/codemode.ts +561 -0
  10. package/src/agent/codemode/drivers/drivers.ts +1 -0
  11. package/src/agent/codemode/drivers/quickjs-wasi-driver.ts +149 -0
  12. package/src/agent/codemode/index.ts +1 -0
  13. package/src/agent/loop.ts +903 -0
  14. package/src/agent.ts +11 -0
  15. package/src/event/event.ts +277 -0
  16. package/src/index.ts +6 -0
  17. package/src/llm.ts +31 -0
  18. package/src/message/message.ts +311 -0
  19. package/src/model/catalog.ts +94 -0
  20. package/src/model/model.ts +250 -0
  21. package/src/model/transform.ts +59 -0
  22. package/src/provider/provider.ts +60 -0
  23. package/src/provider/providers/anthropic/index.ts +792 -0
  24. package/src/provider/providers/github/github.ts +34 -0
  25. package/src/provider/providers/openai/completions.ts +953 -0
  26. package/src/provider/providers/utils.ts +7 -0
  27. package/src/provider/register.ts +6 -0
  28. package/src/provider/stream.ts +278 -0
  29. package/src/stream.ts +72 -0
  30. package/src/utils/eventstream.ts +95 -0
  31. package/src/utils/helpers.ts +24 -0
  32. package/src/utils/jsonparse.ts +32 -0
  33. package/src/utils/overflow.ts +121 -0
  34. package/src/utils/sanitize.ts +25 -0
  35. package/src/utils/validation.ts +87 -0
  36. package/LICENSE +0 -21
  37. package/codemode-z3ZIw-5q.d.mts +0 -8234
  38. package/index.mjs +0 -2694
  39. package/index.mjs.map +0 -1
  40. /package/{agent → dist/pack/agent}/codemode/drivers/drivers.mjs +0 -0
  41. /package/{agent → dist/pack/agent}/codemode/drivers/drivers.mjs.map +0 -0
@@ -0,0 +1,94 @@
1
+ import { Filesystem, lazy } from "@codeworksh/utils";
2
+
3
+ export namespace ModelCatalog {
4
+ export interface ModelsDevModel {
5
+ id: string;
6
+ name: string;
7
+ family: string;
8
+ attachment: boolean;
9
+ reasoning?: boolean;
10
+ tool_call?: boolean;
11
+ temperature?: boolean;
12
+ knowledge?: string | boolean;
13
+ release_date: string;
14
+ last_updated: string;
15
+ modalities: {
16
+ input?: string[];
17
+ output: string[];
18
+ };
19
+ open_weights: boolean;
20
+ baseUrl?: string;
21
+ headers?: Record<string, string>;
22
+ cost?: {
23
+ input?: number;
24
+ output?: number;
25
+ cache_read?: number;
26
+ cache_write?: number;
27
+ };
28
+ limit?: {
29
+ context?: number;
30
+ output?: number;
31
+ };
32
+ }
33
+ export interface ModelsDevProvider {
34
+ id: string;
35
+ env: string[];
36
+ npm?: string;
37
+ api: string;
38
+ baseUrl?: string;
39
+ name: string;
40
+ doc?: string;
41
+ key?: string;
42
+ headers?: Record<string, string>;
43
+ models: Record<string, ModelsDevModel>;
44
+ }
45
+ // Doesn't represent the full spec from models.dev.
46
+ // Represents the provider entries on a best-effort basis.
47
+ export type ModelsDevCatalog = Record<string, ModelsDevProvider>;
48
+ type LazyModelsDevCatalog = ReturnType<typeof lazy<Promise<ModelsDevCatalog>>>;
49
+
50
+ function modelsDevURL(): string {
51
+ return process.env.OPENCODE_MODELS_URL || "https://models.dev";
52
+ }
53
+
54
+ function modelsDevPath(): string | undefined {
55
+ return process.env.CODEWORK_AIKIT_MODELS_PATH;
56
+ }
57
+
58
+ export const modelsDevData: LazyModelsDevCatalog = lazy(async () => {
59
+ const path = modelsDevPath();
60
+ if (path) {
61
+ const result = await Filesystem.readJson<ModelsDevCatalog>(path).catch(() => undefined);
62
+ if (result) return result;
63
+ }
64
+
65
+ const json = await fetch(`${modelsDevURL()}/api.json`).then((x) => x.text());
66
+ return JSON.parse(json) as ModelsDevCatalog;
67
+ });
68
+
69
+ export async function get(): Promise<ModelsDevCatalog> {
70
+ return modelsDevData();
71
+ }
72
+
73
+ export async function refresh(): Promise<void> {
74
+ const result = await fetch(`${modelsDevURL()}/api.json`, {
75
+ signal: AbortSignal.timeout(10 * 1000),
76
+ }).catch(() => undefined);
77
+ if (!result?.ok) return;
78
+
79
+ const json = await result.text();
80
+ const path = modelsDevPath();
81
+ if (path) {
82
+ await Filesystem.write(path, json);
83
+ }
84
+ modelsDevData.reset();
85
+ }
86
+
87
+ void ModelCatalog.refresh();
88
+ setInterval(
89
+ async () => {
90
+ await ModelCatalog.refresh();
91
+ },
92
+ 60 * 1000 * 60,
93
+ ).unref();
94
+ }
@@ -0,0 +1,250 @@
1
+ import { lazy } from "@codeworksh/utils";
2
+ import Type, { type Static } from "typebox";
3
+ import { keys, mapValues, pick, pipe } from "remeda";
4
+ import { Provider } from "../provider/provider";
5
+ import { ModelCatalog } from "./catalog";
6
+ import { applyModification } from "./transform";
7
+
8
+ export namespace Model {
9
+ export const KnownProtocolEnum = {
10
+ anthropicMessages: "anthropic-messages",
11
+ openaiCompletions: "openai-completions",
12
+ openaiResponses: "openai-responses",
13
+ } as const;
14
+ export const KnownProtocolSchema = Type.Union([
15
+ Type.Literal(KnownProtocolEnum.anthropicMessages),
16
+ Type.Literal(KnownProtocolEnum.openaiCompletions),
17
+ Type.Literal(KnownProtocolEnum.openaiResponses),
18
+ ]);
19
+ export type KnownProtocol = Static<typeof KnownProtocolSchema>;
20
+
21
+ const InputSchema = Type.Array(Type.Union([Type.Literal("text"), Type.Literal("image")]));
22
+ const CostSchema = Type.Object({
23
+ input: Type.Number(),
24
+ output: Type.Number(),
25
+ cacheRead: Type.Number(),
26
+ cacheWrite: Type.Number(),
27
+ });
28
+ const HeadersSchema = Type.Optional(Type.Record(Type.String(), Type.String()));
29
+
30
+ export const SupportedProtocolsSchema = Type.Object({
31
+ anthropicMessages: Type.Optional(Type.Literal(KnownProtocolEnum.anthropicMessages)),
32
+ openaiCompletions: Type.Optional(Type.Literal(KnownProtocolEnum.openaiCompletions)),
33
+ openaiResponses: Type.Optional(Type.Literal(KnownProtocolEnum.openaiResponses)),
34
+ });
35
+ //
36
+ // reprsents common base schema for a model
37
+ export const BaseSchema = Type.Object({
38
+ id: Type.String(),
39
+ name: Type.String(),
40
+ provider: Provider.Info,
41
+ baseUrl: Type.String(),
42
+ reasoning: Type.Boolean(),
43
+ input: InputSchema,
44
+ cost: CostSchema,
45
+ contextWindow: Type.Number(),
46
+ maxTokens: Type.Number(),
47
+ headers: HeadersSchema,
48
+ supportedProtocols: Type.Optional(Type.Partial(SupportedProtocolsSchema)), // optionally supported protocols
49
+ });
50
+
51
+ /**
52
+ * Compatibility settings for OpenAI-compatible completions APIs.
53
+ * Use this to override URL-based auto-detection for custom providers.
54
+ */
55
+ export const OpenAICompletionsCompatSchema = Type.Object({
56
+ supportsStore: Type.Optional(Type.Boolean()),
57
+ supportsDeveloperRole: Type.Optional(Type.Boolean()),
58
+ supportsReasoningEffort: Type.Optional(Type.Boolean()),
59
+ reasoningEffortMap: Type.Optional(Provider.ReasoningEffortMapSchema),
60
+ supportsUsageInStreaming: Type.Optional(Type.Boolean()),
61
+ maxTokensField: Type.Optional(Type.Union([Type.Literal("max_completion_tokens"), Type.Literal("max_tokens")])),
62
+ requiresToolResultName: Type.Optional(Type.Boolean()),
63
+ requiresAssistantAfterToolResult: Type.Optional(Type.Boolean()),
64
+ requiresThinkingAsText: Type.Optional(Type.Boolean()),
65
+ thinkingFormat: Type.Optional(
66
+ Type.Union([
67
+ Type.Literal("openai"),
68
+ Type.Literal("openrouter"),
69
+ Type.Literal("zai"),
70
+ Type.Literal("qwen"),
71
+ Type.Literal("qwen-chat-template"),
72
+ ]),
73
+ ),
74
+ openRouterRouting: Type.Optional(Provider.OpenRouterRoutingSchema),
75
+ vercelGatewayRouting: Type.Optional(Provider.VercelGatewayRoutingSchema),
76
+ zaiToolStream: Type.Optional(Type.Boolean()),
77
+ supportsStrictMode: Type.Optional(Type.Boolean()),
78
+ });
79
+ export type OpenAICompletionsCompat = Static<typeof OpenAICompletionsCompatSchema>;
80
+
81
+ /** Compatibility settings for OpenAI Responses APIs. */
82
+ export const OpenAIResponsesCompatSchema = Type.Object({});
83
+ export type OpenAIResponsesCompat = Static<typeof OpenAIResponsesCompatSchema>;
84
+
85
+ export const OpenAICompatSchema = Type.Union([OpenAICompletionsCompatSchema, OpenAIResponsesCompatSchema]);
86
+
87
+ export const AnthropicSchema = Type.Evaluate(
88
+ Type.Intersect([
89
+ BaseSchema,
90
+ Type.Object({
91
+ protocol: Type.Literal(KnownProtocolEnum.anthropicMessages),
92
+ }),
93
+ ]),
94
+ );
95
+
96
+ export const OpenAICompletionsSchema = Type.Evaluate(
97
+ Type.Intersect([
98
+ BaseSchema,
99
+ Type.Object({
100
+ protocol: Type.Literal(KnownProtocolEnum.openaiCompletions),
101
+ compat: Type.Optional(OpenAICompletionsCompatSchema),
102
+ }),
103
+ ]),
104
+ );
105
+ export const OpenAIResponsesSchema = Type.Evaluate(
106
+ Type.Intersect([
107
+ BaseSchema,
108
+ Type.Object({
109
+ protocol: Type.Literal(KnownProtocolEnum.openaiResponses),
110
+ compat: Type.Optional(OpenAIResponsesCompatSchema),
111
+ }),
112
+ ]),
113
+ );
114
+
115
+ export const Info = Type.Union([AnthropicSchema, OpenAICompletionsSchema, OpenAIResponsesSchema]);
116
+ export type Info = Static<typeof Info>;
117
+ export type TModel<TProtocol extends KnownProtocol> = Extract<Info, { protocol: TProtocol }>;
118
+ const BUILTINS = keys(Provider.KnownProviderEnum) as Provider.KnownProvider[];
119
+
120
+ export function calculateCost(
121
+ model: Info,
122
+ usage: {
123
+ input: number;
124
+ output: number;
125
+ cacheRead: number;
126
+ cacheWrite: number;
127
+ cost: {
128
+ input: number;
129
+ output: number;
130
+ cacheRead: number;
131
+ cacheWrite: number;
132
+ total: number;
133
+ };
134
+ },
135
+ ): void {
136
+ usage.cost.input = (usage.input / 1_000_000) * model.cost.input;
137
+ usage.cost.output = (usage.output / 1_000_000) * model.cost.output;
138
+ usage.cost.cacheRead = (usage.cacheRead / 1_000_000) * model.cost.cacheRead;
139
+ usage.cost.cacheWrite = (usage.cacheWrite / 1_000_000) * model.cost.cacheWrite;
140
+ usage.cost.total = usage.cost.input + usage.cost.output + usage.cost.cacheRead + usage.cost.cacheWrite;
141
+ }
142
+
143
+ export type BuiltInModels = Partial<Record<Provider.KnownProvider, Record<string, Info>>>;
144
+
145
+ export function normalizeInput(input?: string[]): Array<"text" | "image"> {
146
+ const normalized = new Set<"text" | "image">();
147
+ for (const modality of input ?? ["text"]) {
148
+ if (modality === "text" || modality === "image") {
149
+ normalized.add(modality);
150
+ }
151
+ }
152
+ if (normalized.size === 0) normalized.add("text");
153
+ return [...normalized];
154
+ }
155
+
156
+ export function toProviderInfo(
157
+ providerId: Provider.KnownProvider,
158
+ provider: ModelCatalog.ModelsDevProvider,
159
+ ): Provider.Info {
160
+ return {
161
+ id: providerId,
162
+ name: provider.name,
163
+ env: provider.env,
164
+ key: provider.key,
165
+ options: provider.headers,
166
+ };
167
+ }
168
+
169
+ function toModelValue(
170
+ providerId: Provider.KnownProvider,
171
+ provider: ModelCatalog.ModelsDevProvider,
172
+ model: ModelCatalog.ModelsDevModel,
173
+ ): Info {
174
+ return applyModification(providerId, provider, model);
175
+ }
176
+
177
+ export async function getBuiltInModels(): Promise<BuiltInModels> {
178
+ const catalog = await ModelCatalog.get();
179
+ return pipe(
180
+ catalog,
181
+ pick(BUILTINS),
182
+ mapValues((provider, providerId) =>
183
+ mapValues(provider.models, (model) => toModelValue(providerId as Provider.KnownProvider, provider, model)),
184
+ ),
185
+ ) as BuiltInModels;
186
+ }
187
+
188
+ export const registry = lazy(async () => {
189
+ const registry: Map<Provider.KnownProvider, Map<string, Info>> = new Map();
190
+ const models = await getBuiltInModels();
191
+ for (const [provider, value] of Object.entries(models) as Array<[Provider.KnownProvider, Record<string, Info>]>) {
192
+ const providerModels = new Map<string, Info>();
193
+ for (const [id, model] of Object.entries(value)) {
194
+ providerModels.set(id, model);
195
+ }
196
+ registry.set(provider, providerModels);
197
+ }
198
+ return registry;
199
+ });
200
+
201
+ export async function getModel<TProvider extends Provider.KnownProvider, TModel extends Info["id"]>(
202
+ provider: TProvider,
203
+ model: TModel,
204
+ overrides?: Partial<Info>,
205
+ ) {
206
+ const data = await registry();
207
+ const providerModels = data.get(provider);
208
+ const result = providerModels?.get(model);
209
+ if (result && overrides) {
210
+ return { ...result, ...overrides };
211
+ }
212
+ return result;
213
+ }
214
+
215
+ export async function getProviders(): Promise<Provider.KnownProvider[]> {
216
+ const data = await registry();
217
+ return Array.from(data.keys());
218
+ }
219
+
220
+ export async function getModels<TProvider extends Provider.KnownProvider>(provider: TProvider): Promise<Info[]> {
221
+ const data = await registry();
222
+ const models = data.get(provider);
223
+ return models ? Array.from(models.values()) : [];
224
+ }
225
+
226
+ function isGpt5OrLater(modelID: string): boolean {
227
+ const match = /^gpt-(\d+)/.exec(modelID);
228
+ if (!match) {
229
+ return false;
230
+ }
231
+ return Number(match[1]) >= 5;
232
+ }
233
+
234
+ /**
235
+ * Check if a model supports xhigh thinking level.
236
+ * Currently only certain OpenAI Codex models support this.
237
+ */
238
+ export function supportsXhigh(model: Info): boolean {
239
+ return isGpt5OrLater(model.id);
240
+ }
241
+
242
+ /**
243
+ * Check if two models are equal by comparing both their id and provider id.
244
+ * Returns false if either model is null or undefined.
245
+ */
246
+ export function modelsAreEqual(a: Info | null | undefined, b: Info | null | undefined): boolean {
247
+ if (!a || !b) return false;
248
+ return a.id === b.id && a.provider.id === b.provider.id;
249
+ }
250
+ }
@@ -0,0 +1,59 @@
1
+ import { Provider } from "../provider/provider";
2
+ import type { ModelCatalog } from "./catalog";
3
+ import { Model } from "./model";
4
+
5
+ function defaultBaseUrl(providerId: Provider.KnownProvider): string | undefined {
6
+ switch (providerId) {
7
+ case Provider.KnownProviderEnum.openai:
8
+ return "https://api.openai.com/v1";
9
+ default:
10
+ return undefined;
11
+ }
12
+ }
13
+
14
+ function resolveDefaultProtocol(providerId: Provider.KnownProvider): Model.KnownProtocol {
15
+ switch (providerId) {
16
+ case Provider.KnownProviderEnum.anthropic:
17
+ return Model.KnownProtocolEnum.anthropicMessages;
18
+ case Provider.KnownProviderEnum.openai:
19
+ return Model.KnownProtocolEnum.openaiResponses;
20
+ default:
21
+ return Model.KnownProtocolEnum.openaiCompletions;
22
+ }
23
+ }
24
+
25
+ export function applyModification(
26
+ providerId: Provider.KnownProvider,
27
+ provider: ModelCatalog.ModelsDevProvider,
28
+ model: ModelCatalog.ModelsDevModel,
29
+ ): Model.Info {
30
+ const baseUrl = model.baseUrl ?? provider.baseUrl ?? provider.api ?? defaultBaseUrl(providerId);
31
+ const normalized: Model.Info = {
32
+ id: model.id,
33
+ name: model.name,
34
+ provider: Model.toProviderInfo(providerId, provider),
35
+ baseUrl,
36
+ reasoning: Boolean(model.reasoning),
37
+ input: Model.normalizeInput(model.modalities.input),
38
+ cost: {
39
+ input: model.cost?.input ?? 0,
40
+ output: model.cost?.output ?? 0,
41
+ cacheRead: model.cost?.cache_read ?? 0,
42
+ cacheWrite: model.cost?.cache_write ?? 0,
43
+ },
44
+ contextWindow: model.limit?.context ?? 0,
45
+ maxTokens: model.limit?.output ?? 0,
46
+ headers: model.headers ?? provider.headers,
47
+ protocol: resolveDefaultProtocol(providerId),
48
+ };
49
+ //
50
+ // add support for multiple known protocols
51
+ if (providerId === Provider.KnownProviderEnum.openai) {
52
+ normalized.supportedProtocols = {
53
+ openaiCompletions: Model.KnownProtocolEnum.openaiCompletions,
54
+ };
55
+ return normalized;
56
+ } else {
57
+ return normalized;
58
+ }
59
+ }
@@ -0,0 +1,60 @@
1
+ import Type, { type Static } from "typebox";
2
+
3
+ export namespace Provider {
4
+ export const KnownProviderEnum = {
5
+ anthropic: "anthropic",
6
+ openai: "openai",
7
+ githubCopilot: "github-copilot",
8
+ openrouter: "openrouter",
9
+ groq: "groq",
10
+ xai: "xai",
11
+ cerebras: "cerebras",
12
+ zai: "zai",
13
+ opencode: "opencode",
14
+ } as const;
15
+ export const KnownProviderSchema = Type.Union([
16
+ Type.Literal(KnownProviderEnum.anthropic),
17
+ Type.Literal(KnownProviderEnum.openai),
18
+ Type.Literal(KnownProviderEnum.githubCopilot),
19
+ Type.Literal(KnownProviderEnum.openrouter),
20
+ Type.Literal(KnownProviderEnum.groq),
21
+ Type.Literal(KnownProviderEnum.xai),
22
+ Type.Literal(KnownProviderEnum.cerebras),
23
+ Type.Literal(KnownProviderEnum.zai),
24
+ Type.Literal(KnownProviderEnum.opencode),
25
+ ]);
26
+ export type KnownProvider = Static<typeof KnownProviderSchema>;
27
+
28
+ export const Info = Type.Object({
29
+ id: KnownProviderSchema,
30
+ name: Type.String(),
31
+ env: Type.Array(Type.String()),
32
+ key: Type.Optional(Type.String()),
33
+ options: Type.Optional(Type.Record(Type.String(), Type.Any())),
34
+ });
35
+ export type Info = Static<typeof Info>;
36
+
37
+ export const ReasoningEffortMapSchema = Type.Object({
38
+ minimal: Type.Optional(Type.String()),
39
+ low: Type.Optional(Type.String()),
40
+ medium: Type.Optional(Type.String()),
41
+ high: Type.Optional(Type.String()),
42
+ xhigh: Type.Optional(Type.String()),
43
+ });
44
+ export type ReasoningEffortMap = Static<typeof ReasoningEffortMapSchema>;
45
+ export type StrictReasoningEffortMap = {
46
+ [K in keyof ReasoningEffortMap]-?: NonNullable<ReasoningEffortMap[K]>;
47
+ };
48
+
49
+ export const OpenRouterRoutingSchema = Type.Object({
50
+ only: Type.Optional(Type.Array(Type.String())),
51
+ order: Type.Optional(Type.Array(Type.String())),
52
+ });
53
+ export type OpenRouterRouting = Static<typeof OpenRouterRoutingSchema>;
54
+
55
+ export const VercelGatewayRoutingSchema = Type.Object({
56
+ only: Type.Optional(Type.Array(Type.String())),
57
+ order: Type.Optional(Type.Array(Type.String())),
58
+ });
59
+ export type VercelGatewayRouting = Static<typeof VercelGatewayRoutingSchema>;
60
+ }