@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/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Sanchit Kudari
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,8 +1,20 @@
|
|
|
1
1
|
# @codeworksh/aikit
|
|
2
2
|
|
|
3
|
-
@codeworksh/aikit is **TypeScript SDK** for building AI agents and agentic
|
|
3
|
+
@codeworksh/aikit is a **TypeScript SDK** for building AI agents and agentic harnesses. It provides a unified API for working with multiple LLM providers, built on top of the Vercel AI SDK, with full support for tool calling (function calling) required for agentic workflows.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
It gives you the basic primitives for streaming LLM responses without the extra bloat, letting you handle the orchestration yourself.
|
|
6
|
+
|
|
7
|
+
## Table of Contents
|
|
8
|
+
|
|
9
|
+
- [Installation](#installation)
|
|
10
|
+
- [Supported Providers](#supported-providers)
|
|
11
|
+
- [Quick Start](#quick-start)
|
|
12
|
+
- [Tools](#tools)
|
|
13
|
+
- [Providers and Models](#providers-and-models)
|
|
14
|
+
- [CLI Tools](#cli-tools)
|
|
15
|
+
- [Model Generation](#model-generation)
|
|
16
|
+
- [OAuth Providers](#oauth-providers)
|
|
17
|
+
- [Contribute](#contribute)
|
|
6
18
|
|
|
7
19
|
## Installation
|
|
8
20
|
|
|
@@ -12,57 +24,41 @@ npm install @codeworksh/aikit
|
|
|
12
24
|
|
|
13
25
|
Node `>=24.14.1` is required.
|
|
14
26
|
|
|
15
|
-
##
|
|
16
|
-
|
|
17
|
-
- `llm(...)` to resolve a model from the built-in registry
|
|
18
|
-
- `stream(...)` and `stream.complete(...)` for provider-normalized LLM streaming
|
|
19
|
-
- `Agent.create(...)` for a stateful agent instance
|
|
20
|
-
- `agent.loop(...)` and `agent.loopContinue(...)` for lower-level turn orchestration
|
|
21
|
-
- `Message` helpers for typed messages and generated `messageId` values
|
|
22
|
-
|
|
23
|
-
## Quick Start
|
|
24
|
-
|
|
25
|
-
```ts
|
|
26
|
-
import { Agent } from "@codeworksh/aikit";
|
|
27
|
-
|
|
28
|
-
const agent = await Agent.create({
|
|
29
|
-
provider: "anthropic",
|
|
30
|
-
model: "claude-haiku-4-5-20251001",
|
|
31
|
-
getApiKey: async () => process.env.ANTHROPIC_API_KEY,
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
agent.setSystemPrompt("Be concise.");
|
|
27
|
+
## Supported Providers
|
|
35
28
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
const lastMessage = agent.state.messages.at(-1);
|
|
39
|
-
console.log(lastMessage?.messageId);
|
|
40
|
-
console.log(lastMessage?.role);
|
|
41
|
-
```
|
|
29
|
+
Built on top of the Vercel AI SDK, `@codeworksh/aikit` supports a wide array of providers natively:
|
|
42
30
|
|
|
43
|
-
|
|
31
|
+
- **Anthropic** (`@ai-sdk/anthropic`)
|
|
32
|
+
- **OpenAI** (`@ai-sdk/openai`)
|
|
33
|
+
- **Google** (`@ai-sdk/google`)
|
|
34
|
+
- **Google Vertex AI** (`@ai-sdk/google-vertex`)
|
|
35
|
+
- **xAI** (`@ai-sdk/xai`)
|
|
36
|
+
- **OpenRouter** (`@openrouter/ai-sdk-provider`)
|
|
37
|
+
- **OpenAI Compatible APIs** (`@ai-sdk/openai-compatible`)
|
|
44
38
|
|
|
45
|
-
|
|
39
|
+
## Quick Start
|
|
46
40
|
|
|
47
41
|
```ts
|
|
48
|
-
import {
|
|
42
|
+
import { llm, stream, Message } from "@codeworksh/aikit";
|
|
49
43
|
|
|
44
|
+
// Resolve a model from the built-in registry
|
|
50
45
|
const model = await llm("anthropic", "claude-haiku-4-5-20251001");
|
|
51
46
|
if (!model) throw new Error("Model not found");
|
|
52
47
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
48
|
+
// Setup conversation context
|
|
49
|
+
const context: Message.Context = {
|
|
50
|
+
systemPrompt: "You are a helpful coding assistant.",
|
|
51
|
+
messages: [
|
|
52
|
+
Message.createUserMessage({
|
|
53
|
+
role: "user",
|
|
54
|
+
time: { created: Date.now() },
|
|
55
|
+
parts: [{ type: "text", text: "Write a simple loop in TypeScript." }],
|
|
56
|
+
}),
|
|
57
|
+
],
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
// Option 1: Stream events
|
|
61
|
+
const s = stream(model, context, { apiKey: process.env.ANTHROPIC_API_KEY });
|
|
66
62
|
|
|
67
63
|
for await (const event of s) {
|
|
68
64
|
if (event.type === "text.delta") {
|
|
@@ -71,127 +67,103 @@ for await (const event of s) {
|
|
|
71
67
|
}
|
|
72
68
|
|
|
73
69
|
const finalMessage = await s.result();
|
|
74
|
-
console.log(finalMessage.messageId);
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
## Agent Instance
|
|
78
|
-
|
|
79
|
-
`Agent.create(...)` is the simplest way to work with a stateful agent.
|
|
80
|
-
|
|
81
|
-
```ts
|
|
82
|
-
import { Agent } from "@codeworksh/aikit";
|
|
83
|
-
|
|
84
|
-
const agent = await Agent.create({
|
|
85
|
-
provider: "anthropic",
|
|
86
|
-
model: "claude-haiku-4-5-20251001",
|
|
87
|
-
getApiKey: async () => process.env.ANTHROPIC_API_KEY,
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
agent.setSystemPrompt("Be concise.");
|
|
91
|
-
|
|
92
|
-
agent.subscribe((event) => {
|
|
93
|
-
if (event.type === "message.end") {
|
|
94
|
-
console.log(event.message.role, event.message.messageId);
|
|
95
|
-
}
|
|
96
|
-
});
|
|
70
|
+
console.log(`\nMessage ID: ${finalMessage.messageId}`);
|
|
97
71
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
console.log(
|
|
72
|
+
// Option 2: Get complete response without streaming
|
|
73
|
+
const message = await stream.complete(model, context, { apiKey: process.env.ANTHROPIC_API_KEY });
|
|
74
|
+
console.log(message.parts);
|
|
101
75
|
```
|
|
102
76
|
|
|
103
|
-
##
|
|
77
|
+
## Tools
|
|
78
|
+
|
|
79
|
+
Tools enable LLMs to interact with external systems. `@codeworksh/aikit` provides native support for function calling and schema validation using TypeBox.
|
|
104
80
|
|
|
105
81
|
```ts
|
|
106
|
-
import { Type } from "@
|
|
107
|
-
import { Agent } from "@codeworksh/aikit";
|
|
82
|
+
import { Type, llm, stream, Message, validateToolArguments } from "@codeworksh/aikit";
|
|
108
83
|
|
|
109
|
-
const calculatorTool =
|
|
84
|
+
const calculatorTool = {
|
|
110
85
|
name: "calculator",
|
|
111
|
-
label: "Calculator",
|
|
112
86
|
description: "Evaluate arithmetic expressions",
|
|
113
87
|
parameters: Type.Object({
|
|
114
88
|
expression: Type.String(),
|
|
115
89
|
}),
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
},
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
const context: Message.Context = {
|
|
93
|
+
messages: [
|
|
94
|
+
Message.createUserMessage({
|
|
95
|
+
role: "user",
|
|
96
|
+
time: { created: Date.now() },
|
|
97
|
+
parts: [{ type: "text", text: "What is 25 * 18?" }],
|
|
98
|
+
}),
|
|
99
|
+
],
|
|
100
|
+
tools: [calculatorTool],
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
const response = await stream.complete(model, context, { apiKey: process.env.ANTHROPIC_API_KEY });
|
|
104
|
+
|
|
105
|
+
// Check for tool calls in the response
|
|
106
|
+
for (const part of response.parts) {
|
|
107
|
+
if (part.type === "toolCall") {
|
|
108
|
+
console.log(`Executing tool: ${part.name}`);
|
|
109
|
+
|
|
110
|
+
// Validates arguments against TypeBox schema automatically
|
|
111
|
+
const args = validateToolArguments(calculatorTool.parameters, part.arguments);
|
|
112
|
+
// Execute your tool logic here...
|
|
113
|
+
}
|
|
114
|
+
}
|
|
139
115
|
```
|
|
140
116
|
|
|
141
|
-
##
|
|
117
|
+
## Providers and Models
|
|
142
118
|
|
|
143
|
-
|
|
119
|
+
`@codeworksh/aikit` uses a registry to fetch model specifications and metadata.
|
|
144
120
|
|
|
145
121
|
```ts
|
|
146
|
-
import {
|
|
122
|
+
import { llm } from "@codeworksh/aikit";
|
|
147
123
|
|
|
148
|
-
|
|
149
|
-
|
|
124
|
+
// Get all available providers
|
|
125
|
+
const providers = await llm.providers();
|
|
126
|
+
console.log(providers);
|
|
150
127
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
model,
|
|
154
|
-
apiKey: process.env.ANTHROPIC_API_KEY,
|
|
155
|
-
convertToLlm: async (messages) => messages,
|
|
156
|
-
},
|
|
157
|
-
{
|
|
158
|
-
systemPrompt: "Be concise.",
|
|
159
|
-
messages: [],
|
|
160
|
-
tools: [],
|
|
161
|
-
},
|
|
162
|
-
[
|
|
163
|
-
Message.createUserMessage({
|
|
164
|
-
role: "user",
|
|
165
|
-
time: { created: Date.now() },
|
|
166
|
-
parts: [{ type: "text", text: "Reply with exactly: ok" }],
|
|
167
|
-
}),
|
|
168
|
-
],
|
|
169
|
-
);
|
|
128
|
+
// Get all models for a specific provider
|
|
129
|
+
const anthropicModels = await llm.models("anthropic");
|
|
170
130
|
|
|
171
|
-
|
|
172
|
-
|
|
131
|
+
// Get a specific model directly
|
|
132
|
+
const gpt4 = await llm.model("openai", "gpt-4o");
|
|
173
133
|
```
|
|
174
134
|
|
|
175
|
-
##
|
|
135
|
+
## CLI Tools
|
|
176
136
|
|
|
177
|
-
|
|
137
|
+
`@codeworksh/aikit` ships with a CLI tool for managing local metadata and authentication.
|
|
178
138
|
|
|
179
|
-
|
|
139
|
+
You can invoke it using `npx aikit` or `pnpm aikit`.
|
|
180
140
|
|
|
181
|
-
|
|
182
|
-
import { Message } from "@codeworksh/aikit";
|
|
141
|
+
### Model Generation
|
|
183
142
|
|
|
184
|
-
|
|
185
|
-
role: "user",
|
|
186
|
-
time: { created: Date.now() },
|
|
187
|
-
parts: [{ type: "text", text: "hello" }],
|
|
188
|
-
});
|
|
143
|
+
Generate a `models.gen.json` file fetching the latest metadata about providers and their available models from `models.dev`.
|
|
189
144
|
|
|
190
|
-
|
|
145
|
+
```bash
|
|
146
|
+
pnpm aikit modelgen [path]
|
|
191
147
|
```
|
|
192
148
|
|
|
193
|
-
|
|
149
|
+
### OAuth Providers
|
|
150
|
+
|
|
151
|
+
Manage OAuth credentials for providers that require it, such as OpenAI Codex.
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
# Start an OAuth login flow in your browser
|
|
155
|
+
pnpm aikit auth --openai-codex
|
|
156
|
+
|
|
157
|
+
# Check the status of your stored credentials
|
|
158
|
+
pnpm aikit auth --openai-codex --status
|
|
159
|
+
|
|
160
|
+
# Refresh your current credentials
|
|
161
|
+
pnpm aikit auth --openai-codex --refresh
|
|
162
|
+
|
|
163
|
+
# Clear stored credentials
|
|
164
|
+
pnpm aikit auth --openai-codex --logout
|
|
165
|
+
```
|
|
194
166
|
|
|
195
167
|
## Contribute
|
|
196
168
|
|
|
197
|
-
|
|
169
|
+
`@codeworksh/aikit` is open to community contribution. Please ensure you submit an issue before submitting a pull request. The project prefers open community discussion before accepting new features.
|
package/cli.d.mts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|
package/cli.mjs
ADDED
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { a as protocolForPackage, c as ModelCatalog, l as lazy, n as isAISDKPackage, s as Model, u as Filesystem } from "./registry-CYfzJ6lk.mjs";
|
|
3
|
+
import { c as openAICodexHeaders, n as OpenAICodexOAuthClient, t as JsonOpenAICodexAuthStorage } from "./codex-DfYk740t.mjs";
|
|
4
|
+
import { resolve } from "node:path";
|
|
5
|
+
import yargs from "yargs";
|
|
6
|
+
import { hideBin } from "yargs/helpers";
|
|
7
|
+
import { mapValues, pickBy, pipe } from "remeda";
|
|
8
|
+
//#region package.json
|
|
9
|
+
var version = "0.4.0";
|
|
10
|
+
//#endregion
|
|
11
|
+
//#region src/cli/modelgen.ts
|
|
12
|
+
const DEFAULT_PROVIDER_BASE_URLS = {
|
|
13
|
+
[Model.KnownProviderEnum.anthropic]: "https://api.anthropic.com/v1",
|
|
14
|
+
[Model.KnownProviderEnum.openai]: "https://api.openai.com/v1",
|
|
15
|
+
[Model.KnownProviderEnum.openrouter]: "https://openrouter.ai/api/v1",
|
|
16
|
+
[Model.KnownProviderEnum.xai]: "https://api.x.ai/v1"
|
|
17
|
+
};
|
|
18
|
+
function modelsDevURL() {
|
|
19
|
+
return process.env.OPENCODE_MODELS_URL || "https://models.dev";
|
|
20
|
+
}
|
|
21
|
+
function modelsDevPath() {
|
|
22
|
+
return process.env.CODEWORK_MODELS_DEV;
|
|
23
|
+
}
|
|
24
|
+
const modelsDevData = lazy(async () => {
|
|
25
|
+
const path = modelsDevPath();
|
|
26
|
+
if (path) {
|
|
27
|
+
const result = await Filesystem.readJson(path).catch(() => void 0);
|
|
28
|
+
if (result) return result;
|
|
29
|
+
}
|
|
30
|
+
const json = await fetch(`${modelsDevURL()}/api.json`).then((x) => x.text());
|
|
31
|
+
return JSON.parse(json);
|
|
32
|
+
});
|
|
33
|
+
async function pullModelsDevData() {
|
|
34
|
+
return modelsDevData();
|
|
35
|
+
}
|
|
36
|
+
function toModelValue(providerId, provider, model) {
|
|
37
|
+
return applyModification(providerId, provider, model);
|
|
38
|
+
}
|
|
39
|
+
async function loadBuiltInFromModelsDev() {
|
|
40
|
+
return pipe(await pullModelsDevData(), pickBy((provider) => Object.values(provider.models).some((model) => Boolean(model.tool_call) && isAISDKPackage(resolveModelNpm(provider, model)))), mapValues((provider, providerId) => pipe(provider.models, pickBy((model) => Boolean(model.tool_call) && isAISDKPackage(resolveModelNpm(provider, model))), mapValues((model) => toModelValue(providerId, provider, model)), pickBy((model) => model !== void 0))));
|
|
41
|
+
}
|
|
42
|
+
function resolveModelNpm(provider, model) {
|
|
43
|
+
return model.provider?.npm ?? provider.npm ?? "@ai-sdk/openai-compatible";
|
|
44
|
+
}
|
|
45
|
+
function resolveModelBaseUrl(provider, model) {
|
|
46
|
+
const protocol = protocolForPackage(resolveModelNpm(provider, model));
|
|
47
|
+
return model.baseUrl ?? model.provider?.api ?? provider.api ?? DEFAULT_PROVIDER_BASE_URLS[protocol] ?? "";
|
|
48
|
+
}
|
|
49
|
+
function resolveModelAPIMethod(npm) {
|
|
50
|
+
const protocol = protocolForPackage(npm);
|
|
51
|
+
if (protocol === Model.KnownProviderEnum.openai || protocol === Model.KnownProviderEnum.xai) return Model.APIMethodEnum.responses;
|
|
52
|
+
return Model.APIMethodEnum.languageModel;
|
|
53
|
+
}
|
|
54
|
+
function resolveProviderOptionsKey(protocol) {
|
|
55
|
+
if (protocol === Model.KnownProviderEnum.openaiCompatible) return "openai-compatible";
|
|
56
|
+
if (protocol === Model.KnownProviderEnum.googleVertex) return "google-vertex";
|
|
57
|
+
if (protocol === Model.KnownProviderEnum.googleVertexAnthropic) return "google-vertex-anthropic";
|
|
58
|
+
return protocol;
|
|
59
|
+
}
|
|
60
|
+
const OPENAI_RESPONSES_NONE_REASONING_MODELS = new Set([
|
|
61
|
+
"gpt-5.1",
|
|
62
|
+
"gpt-5.2",
|
|
63
|
+
"gpt-5.3-codex",
|
|
64
|
+
"gpt-5.4",
|
|
65
|
+
"gpt-5.4-mini",
|
|
66
|
+
"gpt-5.4-nano",
|
|
67
|
+
"gpt-5.5"
|
|
68
|
+
]);
|
|
69
|
+
function supportsOpenAiXhigh(modelId) {
|
|
70
|
+
return modelId.includes("gpt-5.2") || modelId.includes("gpt-5.3") || modelId.includes("gpt-5.4") || modelId.includes("gpt-5.5");
|
|
71
|
+
}
|
|
72
|
+
function mergeThinkingLevelMap(model, map) {
|
|
73
|
+
model.thinkingLevelMap = {
|
|
74
|
+
...model.thinkingLevelMap,
|
|
75
|
+
...map
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
function applyThinkingLevelMetadata(model) {
|
|
79
|
+
if (model.protocol === Model.KnownProviderEnum.openai && model.id.startsWith("gpt-5")) mergeThinkingLevelMap(model, { off: null });
|
|
80
|
+
if (model.protocol === Model.KnownProviderEnum.openai && model.provider.id === "openai" && OPENAI_RESPONSES_NONE_REASONING_MODELS.has(model.id)) mergeThinkingLevelMap(model, { off: "none" });
|
|
81
|
+
if (supportsOpenAiXhigh(model.id)) mergeThinkingLevelMap(model, { xhigh: "xhigh" });
|
|
82
|
+
if (model.id.includes("opus-4-6") || model.id.includes("opus-4.6")) mergeThinkingLevelMap(model, { xhigh: "max" });
|
|
83
|
+
if (model.id.includes("opus-4-7") || model.id.includes("opus-4.7")) mergeThinkingLevelMap(model, { xhigh: "xhigh" });
|
|
84
|
+
}
|
|
85
|
+
async function generateModels(args = {}) {
|
|
86
|
+
const path = resolve(args.path ?? ModelCatalog.path());
|
|
87
|
+
const models = await loadBuiltInFromModelsDev();
|
|
88
|
+
await Filesystem.writeJson(path, models);
|
|
89
|
+
return path;
|
|
90
|
+
}
|
|
91
|
+
const ModelgenCommand = {
|
|
92
|
+
command: "modelgen [path]",
|
|
93
|
+
describe: "generate models.gen.json",
|
|
94
|
+
builder: (yargs) => yargs.positional("path", {
|
|
95
|
+
type: "string",
|
|
96
|
+
describe: "output path (defaults to CODEWORK_MODELGEN_PATH or ./models.gen.json)"
|
|
97
|
+
}),
|
|
98
|
+
handler: async (args) => {
|
|
99
|
+
const path = await generateModels(args);
|
|
100
|
+
console.log(`Generated model catalog at ${path}`);
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
function applyModification(providerId, provider, model) {
|
|
104
|
+
const npm = resolveModelNpm(provider, model);
|
|
105
|
+
if (!isAISDKPackage(npm)) return;
|
|
106
|
+
const protocol = protocolForPackage(npm);
|
|
107
|
+
const baseUrl = resolveModelBaseUrl(provider, model);
|
|
108
|
+
const providerInfo = {
|
|
109
|
+
id: providerId,
|
|
110
|
+
name: provider.name,
|
|
111
|
+
source: "api",
|
|
112
|
+
env: provider.env
|
|
113
|
+
};
|
|
114
|
+
if (provider.key) providerInfo.key = provider.key;
|
|
115
|
+
const api = {
|
|
116
|
+
id: model.id,
|
|
117
|
+
method: resolveModelAPIMethod(npm)
|
|
118
|
+
};
|
|
119
|
+
if (baseUrl) api.url = baseUrl;
|
|
120
|
+
const info = {
|
|
121
|
+
id: model.id,
|
|
122
|
+
name: model.name,
|
|
123
|
+
provider: providerInfo,
|
|
124
|
+
baseUrl,
|
|
125
|
+
reasoning: Boolean(model.reasoning),
|
|
126
|
+
input: Model.normalizeInput(model.modalities.input),
|
|
127
|
+
cost: {
|
|
128
|
+
input: model.cost?.input ?? 0,
|
|
129
|
+
output: model.cost?.output ?? 0,
|
|
130
|
+
cacheRead: model.cost?.cache_read ?? 0,
|
|
131
|
+
cacheWrite: model.cost?.cache_write ?? 0
|
|
132
|
+
},
|
|
133
|
+
contextWindow: model.limit?.context ?? 4096,
|
|
134
|
+
maxTokens: model.limit?.output ?? 4096,
|
|
135
|
+
headers: {
|
|
136
|
+
...provider.headers,
|
|
137
|
+
...model.provider?.headers,
|
|
138
|
+
...model.headers
|
|
139
|
+
},
|
|
140
|
+
npm,
|
|
141
|
+
api,
|
|
142
|
+
providerOptionsKey: resolveProviderOptionsKey(protocol),
|
|
143
|
+
protocol
|
|
144
|
+
};
|
|
145
|
+
if (Object.keys(info.headers ?? {}).length === 0) delete info.headers;
|
|
146
|
+
applyThinkingLevelMetadata(info);
|
|
147
|
+
return info;
|
|
148
|
+
}
|
|
149
|
+
//#endregion
|
|
150
|
+
//#region src/cli/oauth.ts
|
|
151
|
+
async function promptLine(message) {
|
|
152
|
+
const rl = (await import("node:readline/promises")).createInterface({
|
|
153
|
+
input: process.stdin,
|
|
154
|
+
output: process.stdout
|
|
155
|
+
});
|
|
156
|
+
try {
|
|
157
|
+
return await rl.question(`${message} `);
|
|
158
|
+
} finally {
|
|
159
|
+
rl.close();
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
async function openBrowser(url) {
|
|
163
|
+
const { spawn } = await import("node:child_process");
|
|
164
|
+
const command = process.platform === "darwin" ? {
|
|
165
|
+
file: "open",
|
|
166
|
+
args: [url]
|
|
167
|
+
} : process.platform === "win32" ? {
|
|
168
|
+
file: "cmd",
|
|
169
|
+
args: [
|
|
170
|
+
"/c",
|
|
171
|
+
"start",
|
|
172
|
+
"",
|
|
173
|
+
url
|
|
174
|
+
]
|
|
175
|
+
} : {
|
|
176
|
+
file: "xdg-open",
|
|
177
|
+
args: [url]
|
|
178
|
+
};
|
|
179
|
+
spawn(command.file, command.args, {
|
|
180
|
+
detached: true,
|
|
181
|
+
stdio: "ignore"
|
|
182
|
+
}).unref();
|
|
183
|
+
}
|
|
184
|
+
function printCredentials(credentials, options) {
|
|
185
|
+
if (options.json) {
|
|
186
|
+
console.log(JSON.stringify({
|
|
187
|
+
accountId: credentials.accountId,
|
|
188
|
+
expires: credentials.expires,
|
|
189
|
+
expiresAt: new Date(credentials.expires).toISOString(),
|
|
190
|
+
headers: options.printHeaders ? openAICodexHeaders(credentials) : void 0
|
|
191
|
+
}, null, 2));
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
console.log(`Account: ${credentials.accountId}`);
|
|
195
|
+
console.log(`Expires: ${new Date(credentials.expires).toLocaleString()}`);
|
|
196
|
+
if (options.printHeaders) {
|
|
197
|
+
console.log("Headers:");
|
|
198
|
+
for (const [name, value] of Object.entries(openAICodexHeaders(credentials))) console.log(`${name}: ${value}`);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
async function runOpenAICodexAuth(args) {
|
|
202
|
+
const storage = new JsonOpenAICodexAuthStorage({ path: args.authFile });
|
|
203
|
+
const client = new OpenAICodexOAuthClient({ storage });
|
|
204
|
+
if (args.logout) {
|
|
205
|
+
await client.logout();
|
|
206
|
+
console.log(`Cleared OpenAI Codex credentials from ${storage.path}`);
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
if (args.status) {
|
|
210
|
+
const credentials = await storage.get();
|
|
211
|
+
if (!credentials) {
|
|
212
|
+
console.log(`No OpenAI Codex credentials found at ${storage.path}`);
|
|
213
|
+
process.exitCode = 1;
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
printCredentials(credentials, args);
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
if (args.refresh) {
|
|
220
|
+
const credentials = await client.getCredentials();
|
|
221
|
+
if (!credentials) {
|
|
222
|
+
console.log(`No OpenAI Codex credentials found at ${storage.path}`);
|
|
223
|
+
process.exitCode = 1;
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
console.log(`Refreshed OpenAI Codex credentials in ${storage.path}`);
|
|
227
|
+
printCredentials(credentials, args);
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
const credentials = await client.login({
|
|
231
|
+
originator: args.originator,
|
|
232
|
+
onAuth: (info) => {
|
|
233
|
+
console.log(info.instructions ?? "Complete OpenAI Codex authentication in your browser.");
|
|
234
|
+
console.log(info.url);
|
|
235
|
+
if (args.browser !== false) openBrowser(info.url).catch((error) => {
|
|
236
|
+
console.warn(`Failed to open browser: ${error instanceof Error ? error.message : String(error)}`);
|
|
237
|
+
});
|
|
238
|
+
},
|
|
239
|
+
onPrompt: async (prompt) => promptLine(prompt.message),
|
|
240
|
+
onManualCodeInput: args.manual ? async () => promptLine("Paste the redirect URL or authorization code, or wait for browser callback:") : void 0
|
|
241
|
+
});
|
|
242
|
+
console.log(`Saved OpenAI Codex credentials to ${storage.path}`);
|
|
243
|
+
printCredentials(credentials, args);
|
|
244
|
+
}
|
|
245
|
+
//#endregion
|
|
246
|
+
//#region src/cli.ts
|
|
247
|
+
const cli = yargs(hideBin(process.argv)).scriptName("aikit").wrap(100).help("help", "show help").alias("help", "h").version("version", "show version number", version).alias("version", "v").command(ModelgenCommand).command({
|
|
248
|
+
command: "auth",
|
|
249
|
+
describe: "manage OAuth credentials",
|
|
250
|
+
builder: (yargs) => yargs.option("openai-codex", {
|
|
251
|
+
type: "boolean",
|
|
252
|
+
describe: "use OpenAI Codex OAuth"
|
|
253
|
+
}).option("auth-file", {
|
|
254
|
+
type: "string",
|
|
255
|
+
describe: "path to auth.json (defaults to CODEWORK_CREDENTIALS or ~/.codework/aikit/auth.json)"
|
|
256
|
+
}).option("browser", {
|
|
257
|
+
type: "boolean",
|
|
258
|
+
default: true,
|
|
259
|
+
describe: "open the authorization URL in the default browser"
|
|
260
|
+
}).option("manual", {
|
|
261
|
+
type: "boolean",
|
|
262
|
+
default: false,
|
|
263
|
+
describe: "also prompt for a pasted redirect URL or authorization code"
|
|
264
|
+
}).option("originator", {
|
|
265
|
+
type: "string",
|
|
266
|
+
default: "codework",
|
|
267
|
+
describe: "OAuth originator value"
|
|
268
|
+
}).option("status", {
|
|
269
|
+
type: "boolean",
|
|
270
|
+
describe: "show stored credential status without refreshing"
|
|
271
|
+
}).option("refresh", {
|
|
272
|
+
type: "boolean",
|
|
273
|
+
describe: "refresh stored credentials if expired"
|
|
274
|
+
}).option("logout", {
|
|
275
|
+
type: "boolean",
|
|
276
|
+
describe: "clear stored credentials"
|
|
277
|
+
}).option("json", {
|
|
278
|
+
type: "boolean",
|
|
279
|
+
describe: "print machine-readable output"
|
|
280
|
+
}).option("print-headers", {
|
|
281
|
+
type: "boolean",
|
|
282
|
+
describe: "print request headers for Codex API calls"
|
|
283
|
+
}).check((args) => {
|
|
284
|
+
if (!args.openaiCodex) throw new Error("Choose an auth provider, for example: auth --openai-codex");
|
|
285
|
+
if ([
|
|
286
|
+
args.status,
|
|
287
|
+
args.refresh,
|
|
288
|
+
args.logout
|
|
289
|
+
].filter(Boolean).length > 1) throw new Error("Choose only one of --status, --refresh, or --logout");
|
|
290
|
+
return true;
|
|
291
|
+
}),
|
|
292
|
+
handler: async (args) => {
|
|
293
|
+
await runOpenAICodexAuth(args);
|
|
294
|
+
}
|
|
295
|
+
}).demandCommand(1, "Choose a command").strict().fail((message, error) => {
|
|
296
|
+
if (error) throw error;
|
|
297
|
+
if (message) throw new Error(message);
|
|
298
|
+
});
|
|
299
|
+
try {
|
|
300
|
+
await cli.parse();
|
|
301
|
+
} catch (error) {
|
|
302
|
+
process.exitCode = 1;
|
|
303
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
304
|
+
}
|
|
305
|
+
//#endregion
|
|
306
|
+
export {};
|
|
307
|
+
|
|
308
|
+
//# sourceMappingURL=cli.mjs.map
|