@ottocode/sdk 0.1.173
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/README.md +338 -0
- package/package.json +128 -0
- package/src/agent/types.ts +19 -0
- package/src/auth/src/copilot-oauth.ts +190 -0
- package/src/auth/src/index.ts +100 -0
- package/src/auth/src/oauth.ts +234 -0
- package/src/auth/src/openai-oauth.ts +394 -0
- package/src/auth/src/wallet.ts +51 -0
- package/src/browser.ts +32 -0
- package/src/config/src/index.ts +110 -0
- package/src/config/src/manager.ts +181 -0
- package/src/config/src/paths.ts +98 -0
- package/src/core/src/errors.ts +102 -0
- package/src/core/src/index.ts +108 -0
- package/src/core/src/providers/resolver.ts +244 -0
- package/src/core/src/streaming/artifacts.ts +41 -0
- package/src/core/src/terminals/bun-pty.ts +13 -0
- package/src/core/src/terminals/circular-buffer.ts +30 -0
- package/src/core/src/terminals/ensure-bun-pty.ts +70 -0
- package/src/core/src/terminals/index.ts +8 -0
- package/src/core/src/terminals/manager.ts +158 -0
- package/src/core/src/terminals/rust-libs.ts +30 -0
- package/src/core/src/terminals/terminal.ts +132 -0
- package/src/core/src/tools/bin-manager.ts +250 -0
- package/src/core/src/tools/builtin/bash.ts +155 -0
- package/src/core/src/tools/builtin/bash.txt +7 -0
- package/src/core/src/tools/builtin/file-cache.ts +39 -0
- package/src/core/src/tools/builtin/finish.ts +12 -0
- package/src/core/src/tools/builtin/finish.txt +10 -0
- package/src/core/src/tools/builtin/fs/cd.ts +19 -0
- package/src/core/src/tools/builtin/fs/cd.txt +5 -0
- package/src/core/src/tools/builtin/fs/index.ts +20 -0
- package/src/core/src/tools/builtin/fs/ls.ts +72 -0
- package/src/core/src/tools/builtin/fs/ls.txt +8 -0
- package/src/core/src/tools/builtin/fs/pwd.ts +17 -0
- package/src/core/src/tools/builtin/fs/pwd.txt +5 -0
- package/src/core/src/tools/builtin/fs/read.ts +119 -0
- package/src/core/src/tools/builtin/fs/read.txt +8 -0
- package/src/core/src/tools/builtin/fs/tree.ts +149 -0
- package/src/core/src/tools/builtin/fs/tree.txt +11 -0
- package/src/core/src/tools/builtin/fs/util.ts +95 -0
- package/src/core/src/tools/builtin/fs/write.ts +106 -0
- package/src/core/src/tools/builtin/fs/write.txt +11 -0
- package/src/core/src/tools/builtin/git.commit.txt +6 -0
- package/src/core/src/tools/builtin/git.diff.txt +5 -0
- package/src/core/src/tools/builtin/git.status.txt +5 -0
- package/src/core/src/tools/builtin/git.ts +151 -0
- package/src/core/src/tools/builtin/glob.ts +128 -0
- package/src/core/src/tools/builtin/glob.txt +10 -0
- package/src/core/src/tools/builtin/grep.ts +136 -0
- package/src/core/src/tools/builtin/grep.txt +9 -0
- package/src/core/src/tools/builtin/ignore.ts +45 -0
- package/src/core/src/tools/builtin/patch/apply.ts +546 -0
- package/src/core/src/tools/builtin/patch/constants.ts +5 -0
- package/src/core/src/tools/builtin/patch/normalize.ts +31 -0
- package/src/core/src/tools/builtin/patch/parse-enveloped.ts +209 -0
- package/src/core/src/tools/builtin/patch/parse-unified.ts +231 -0
- package/src/core/src/tools/builtin/patch/parse.ts +28 -0
- package/src/core/src/tools/builtin/patch/text.ts +23 -0
- package/src/core/src/tools/builtin/patch/types.ts +82 -0
- package/src/core/src/tools/builtin/patch.ts +167 -0
- package/src/core/src/tools/builtin/patch.txt +207 -0
- package/src/core/src/tools/builtin/progress.ts +55 -0
- package/src/core/src/tools/builtin/progress.txt +7 -0
- package/src/core/src/tools/builtin/ripgrep.ts +125 -0
- package/src/core/src/tools/builtin/ripgrep.txt +7 -0
- package/src/core/src/tools/builtin/terminal.ts +300 -0
- package/src/core/src/tools/builtin/terminal.txt +93 -0
- package/src/core/src/tools/builtin/todos.ts +66 -0
- package/src/core/src/tools/builtin/todos.txt +7 -0
- package/src/core/src/tools/builtin/websearch.ts +250 -0
- package/src/core/src/tools/builtin/websearch.txt +12 -0
- package/src/core/src/tools/error.ts +67 -0
- package/src/core/src/tools/loader.ts +421 -0
- package/src/core/src/types/index.ts +11 -0
- package/src/core/src/types/types.ts +4 -0
- package/src/core/src/utils/ansi.ts +27 -0
- package/src/core/src/utils/debug.ts +40 -0
- package/src/core/src/utils/logger.ts +150 -0
- package/src/index.ts +313 -0
- package/src/prompts/src/agents/build.txt +89 -0
- package/src/prompts/src/agents/general.txt +15 -0
- package/src/prompts/src/agents/plan.txt +10 -0
- package/src/prompts/src/agents/research.txt +50 -0
- package/src/prompts/src/base.txt +24 -0
- package/src/prompts/src/debug.ts +104 -0
- package/src/prompts/src/index.ts +1 -0
- package/src/prompts/src/modes/oneshot.txt +9 -0
- package/src/prompts/src/providers/anthropic.txt +247 -0
- package/src/prompts/src/providers/anthropicSpoof.txt +1 -0
- package/src/prompts/src/providers/default.txt +466 -0
- package/src/prompts/src/providers/google.txt +230 -0
- package/src/prompts/src/providers/moonshot.txt +24 -0
- package/src/prompts/src/providers/openai.txt +414 -0
- package/src/prompts/src/providers.ts +143 -0
- package/src/providers/src/anthropic-caching.ts +202 -0
- package/src/providers/src/anthropic-oauth-client.ts +157 -0
- package/src/providers/src/authorization.ts +17 -0
- package/src/providers/src/catalog-manual.ts +135 -0
- package/src/providers/src/catalog-merged.ts +9 -0
- package/src/providers/src/catalog.ts +8329 -0
- package/src/providers/src/copilot-client.ts +39 -0
- package/src/providers/src/env.ts +31 -0
- package/src/providers/src/google-client.ts +16 -0
- package/src/providers/src/index.ts +75 -0
- package/src/providers/src/moonshot-client.ts +25 -0
- package/src/providers/src/oauth-models.ts +39 -0
- package/src/providers/src/openai-oauth-client.ts +108 -0
- package/src/providers/src/opencode-client.ts +64 -0
- package/src/providers/src/openrouter-client.ts +31 -0
- package/src/providers/src/pricing.ts +178 -0
- package/src/providers/src/setu-client.ts +643 -0
- package/src/providers/src/utils.ts +210 -0
- package/src/providers/src/validate.ts +39 -0
- package/src/providers/src/zai-client.ts +47 -0
- package/src/skills/index.ts +34 -0
- package/src/skills/loader.ts +152 -0
- package/src/skills/parser.ts +108 -0
- package/src/skills/tool.ts +87 -0
- package/src/skills/types.ts +41 -0
- package/src/skills/validator.ts +110 -0
- package/src/types/src/auth.ts +33 -0
- package/src/types/src/config.ts +36 -0
- package/src/types/src/index.ts +20 -0
- package/src/types/src/provider.ts +71 -0
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
type MessageBlock = {
|
|
2
|
+
type: string;
|
|
3
|
+
cache_control?: { type: string };
|
|
4
|
+
[key: string]: unknown;
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
type Message = {
|
|
8
|
+
role: string;
|
|
9
|
+
content: unknown;
|
|
10
|
+
[key: string]: unknown;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
type ParsedBody = {
|
|
14
|
+
system?: MessageBlock[];
|
|
15
|
+
messages?: Message[];
|
|
16
|
+
[key: string]: unknown;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export function addAnthropicCacheControl(parsed: ParsedBody): ParsedBody {
|
|
20
|
+
const MAX_SYSTEM_CACHE = 1;
|
|
21
|
+
const MAX_MESSAGE_CACHE = 1;
|
|
22
|
+
let systemCacheUsed = 0;
|
|
23
|
+
let messageCacheUsed = 0;
|
|
24
|
+
|
|
25
|
+
if (parsed.system && Array.isArray(parsed.system)) {
|
|
26
|
+
parsed.system = parsed.system.map((block, index) => {
|
|
27
|
+
if (block.cache_control) return block;
|
|
28
|
+
if (
|
|
29
|
+
systemCacheUsed < MAX_SYSTEM_CACHE &&
|
|
30
|
+
index === 0 &&
|
|
31
|
+
block.type === 'text'
|
|
32
|
+
) {
|
|
33
|
+
systemCacheUsed++;
|
|
34
|
+
return { ...block, cache_control: { type: 'ephemeral' } };
|
|
35
|
+
}
|
|
36
|
+
return block;
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (parsed.messages && Array.isArray(parsed.messages)) {
|
|
41
|
+
const messageCount = parsed.messages.length;
|
|
42
|
+
parsed.messages = parsed.messages.map((msg, msgIndex) => {
|
|
43
|
+
const isLast = msgIndex === messageCount - 1;
|
|
44
|
+
|
|
45
|
+
if (Array.isArray(msg.content)) {
|
|
46
|
+
const blocks = msg.content as MessageBlock[];
|
|
47
|
+
const content = blocks.map((block, blockIndex) => {
|
|
48
|
+
if (block.cache_control) return block;
|
|
49
|
+
if (
|
|
50
|
+
isLast &&
|
|
51
|
+
messageCacheUsed < MAX_MESSAGE_CACHE &&
|
|
52
|
+
blockIndex === blocks.length - 1
|
|
53
|
+
) {
|
|
54
|
+
messageCacheUsed++;
|
|
55
|
+
return { ...block, cache_control: { type: 'ephemeral' } };
|
|
56
|
+
}
|
|
57
|
+
return block;
|
|
58
|
+
});
|
|
59
|
+
return { ...msg, content };
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (
|
|
63
|
+
isLast &&
|
|
64
|
+
messageCacheUsed < MAX_MESSAGE_CACHE &&
|
|
65
|
+
typeof msg.content === 'string'
|
|
66
|
+
) {
|
|
67
|
+
messageCacheUsed++;
|
|
68
|
+
return {
|
|
69
|
+
...msg,
|
|
70
|
+
content: [
|
|
71
|
+
{
|
|
72
|
+
type: 'text',
|
|
73
|
+
text: msg.content,
|
|
74
|
+
cache_control: { type: 'ephemeral' },
|
|
75
|
+
},
|
|
76
|
+
],
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return msg;
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return parsed;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export function createAnthropicCachingFetch(): typeof fetch {
|
|
88
|
+
return async (input: RequestInfo | URL, init?: RequestInit) => {
|
|
89
|
+
let body = init?.body;
|
|
90
|
+
if (body && typeof body === 'string') {
|
|
91
|
+
try {
|
|
92
|
+
const parsed = JSON.parse(body);
|
|
93
|
+
const modified = addAnthropicCacheControl(parsed);
|
|
94
|
+
body = JSON.stringify(modified);
|
|
95
|
+
} catch {
|
|
96
|
+
// If parsing fails, send as-is
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return fetch(input, { ...init, body });
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export function createConditionalCachingFetch(
|
|
104
|
+
shouldCache: (model: string) => boolean,
|
|
105
|
+
model: string,
|
|
106
|
+
): typeof fetch {
|
|
107
|
+
return async (input: RequestInfo | URL, init?: RequestInit) => {
|
|
108
|
+
if (!shouldCache(model)) {
|
|
109
|
+
return fetch(input, init);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
let body = init?.body;
|
|
113
|
+
if (body && typeof body === 'string') {
|
|
114
|
+
try {
|
|
115
|
+
const parsed = JSON.parse(body);
|
|
116
|
+
|
|
117
|
+
const MAX_SYSTEM_CACHE = 1;
|
|
118
|
+
const MAX_MESSAGE_CACHE = 1;
|
|
119
|
+
let systemCacheUsed = 0;
|
|
120
|
+
let messageCacheUsed = 0;
|
|
121
|
+
|
|
122
|
+
if (parsed.messages && Array.isArray(parsed.messages)) {
|
|
123
|
+
const messageCount = parsed.messages.length;
|
|
124
|
+
parsed.messages = parsed.messages.map(
|
|
125
|
+
(msg: Message, msgIndex: number) => {
|
|
126
|
+
if (msg.role === 'system' && systemCacheUsed < MAX_SYSTEM_CACHE) {
|
|
127
|
+
systemCacheUsed++;
|
|
128
|
+
if (typeof msg.content === 'string') {
|
|
129
|
+
return {
|
|
130
|
+
...msg,
|
|
131
|
+
content: [
|
|
132
|
+
{
|
|
133
|
+
type: 'text',
|
|
134
|
+
text: msg.content,
|
|
135
|
+
cache_control: { type: 'ephemeral' },
|
|
136
|
+
},
|
|
137
|
+
],
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
if (Array.isArray(msg.content)) {
|
|
141
|
+
const blocks = msg.content as MessageBlock[];
|
|
142
|
+
const content = blocks.map((block, i) => {
|
|
143
|
+
if (i === blocks.length - 1 && !block.cache_control) {
|
|
144
|
+
return { ...block, cache_control: { type: 'ephemeral' } };
|
|
145
|
+
}
|
|
146
|
+
return block;
|
|
147
|
+
});
|
|
148
|
+
return { ...msg, content };
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const isLast = msgIndex === messageCount - 1;
|
|
153
|
+
|
|
154
|
+
if (Array.isArray(msg.content)) {
|
|
155
|
+
const blocks = msg.content as MessageBlock[];
|
|
156
|
+
const content = blocks.map((block, blockIndex) => {
|
|
157
|
+
if (block.cache_control) return block;
|
|
158
|
+
if (
|
|
159
|
+
isLast &&
|
|
160
|
+
messageCacheUsed < MAX_MESSAGE_CACHE &&
|
|
161
|
+
blockIndex === blocks.length - 1
|
|
162
|
+
) {
|
|
163
|
+
messageCacheUsed++;
|
|
164
|
+
return { ...block, cache_control: { type: 'ephemeral' } };
|
|
165
|
+
}
|
|
166
|
+
return block;
|
|
167
|
+
});
|
|
168
|
+
return { ...msg, content };
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (
|
|
172
|
+
isLast &&
|
|
173
|
+
messageCacheUsed < MAX_MESSAGE_CACHE &&
|
|
174
|
+
typeof msg.content === 'string'
|
|
175
|
+
) {
|
|
176
|
+
messageCacheUsed++;
|
|
177
|
+
return {
|
|
178
|
+
...msg,
|
|
179
|
+
content: [
|
|
180
|
+
{
|
|
181
|
+
type: 'text',
|
|
182
|
+
text: msg.content,
|
|
183
|
+
cache_control: { type: 'ephemeral' },
|
|
184
|
+
},
|
|
185
|
+
],
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
return msg;
|
|
190
|
+
},
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
body = JSON.stringify(parsed);
|
|
195
|
+
} catch {
|
|
196
|
+
// If parsing fails, send as-is
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
return fetch(input, { ...init, body });
|
|
201
|
+
};
|
|
202
|
+
}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { createAnthropic } from '@ai-sdk/anthropic';
|
|
2
|
+
import { addAnthropicCacheControl } from './anthropic-caching.ts';
|
|
3
|
+
|
|
4
|
+
const CLAUDE_CLI_VERSION = '1.0.61';
|
|
5
|
+
|
|
6
|
+
export type AnthropicOAuthConfig = {
|
|
7
|
+
oauth: {
|
|
8
|
+
access: string;
|
|
9
|
+
refresh: string;
|
|
10
|
+
expires: number;
|
|
11
|
+
};
|
|
12
|
+
toolNameTransformer?: (name: string) => string;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
function buildOAuthHeaders(accessToken: string): Record<string, string> {
|
|
16
|
+
const headers: Record<string, string> = {
|
|
17
|
+
authorization: `Bearer ${accessToken}`,
|
|
18
|
+
'anthropic-beta':
|
|
19
|
+
'claude-code-20250219,oauth-2025-04-20,interleaved-thinking-2025-05-14',
|
|
20
|
+
'anthropic-dangerous-direct-browser-access': 'true',
|
|
21
|
+
'anthropic-version': '2023-06-01',
|
|
22
|
+
'user-agent': `claude-cli/${CLAUDE_CLI_VERSION} (external, cli)`,
|
|
23
|
+
'x-app': 'cli',
|
|
24
|
+
'content-type': 'application/json',
|
|
25
|
+
accept: 'application/json',
|
|
26
|
+
'x-stainless-arch': process.arch === 'arm64' ? 'arm64' : 'x64',
|
|
27
|
+
'x-stainless-helper-method': 'stream',
|
|
28
|
+
'x-stainless-lang': 'js',
|
|
29
|
+
'x-stainless-os':
|
|
30
|
+
process.platform === 'darwin'
|
|
31
|
+
? 'MacOS'
|
|
32
|
+
: process.platform === 'win32'
|
|
33
|
+
? 'Windows'
|
|
34
|
+
: 'Linux',
|
|
35
|
+
'x-stainless-package-version': '0.70.0',
|
|
36
|
+
'x-stainless-retry-count': '0',
|
|
37
|
+
'x-stainless-runtime': 'node',
|
|
38
|
+
'x-stainless-runtime-version': process.version,
|
|
39
|
+
'x-stainless-timeout': '600',
|
|
40
|
+
};
|
|
41
|
+
return headers;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function filterExistingHeaders(
|
|
45
|
+
initHeaders: HeadersInit | undefined,
|
|
46
|
+
): Record<string, string> {
|
|
47
|
+
const headers: Record<string, string> = {};
|
|
48
|
+
if (!initHeaders) return headers;
|
|
49
|
+
|
|
50
|
+
if (initHeaders instanceof Headers) {
|
|
51
|
+
initHeaders.forEach((value, key) => {
|
|
52
|
+
if (key.toLowerCase() !== 'x-api-key') {
|
|
53
|
+
headers[key] = value;
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
} else if (Array.isArray(initHeaders)) {
|
|
57
|
+
for (const [key, value] of initHeaders) {
|
|
58
|
+
if (
|
|
59
|
+
key &&
|
|
60
|
+
key.toLowerCase() !== 'x-api-key' &&
|
|
61
|
+
typeof value === 'string'
|
|
62
|
+
) {
|
|
63
|
+
headers[key] = value;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
} else {
|
|
67
|
+
for (const [key, value] of Object.entries(initHeaders)) {
|
|
68
|
+
if (key.toLowerCase() !== 'x-api-key' && typeof value === 'string') {
|
|
69
|
+
headers[key] = value;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return headers;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export function createAnthropicOAuthFetch(
|
|
77
|
+
config: AnthropicOAuthConfig,
|
|
78
|
+
): typeof fetch {
|
|
79
|
+
const { oauth, toolNameTransformer } = config;
|
|
80
|
+
|
|
81
|
+
return async (input: string | URL | Request, init?: RequestInit) => {
|
|
82
|
+
const existingHeaders = filterExistingHeaders(init?.headers);
|
|
83
|
+
const oauthHeaders = buildOAuthHeaders(oauth.access);
|
|
84
|
+
const headers = { ...existingHeaders, ...oauthHeaders };
|
|
85
|
+
|
|
86
|
+
let url = typeof input === 'string' ? input : input.toString();
|
|
87
|
+
if (url.includes('/v1/messages') && !url.includes('beta=true')) {
|
|
88
|
+
url += url.includes('?') ? '&beta=true' : '?beta=true';
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
let body = init?.body;
|
|
92
|
+
if (body && typeof body === 'string') {
|
|
93
|
+
try {
|
|
94
|
+
const parsed = JSON.parse(body);
|
|
95
|
+
|
|
96
|
+
if (toolNameTransformer) {
|
|
97
|
+
if (parsed.tools && Array.isArray(parsed.tools)) {
|
|
98
|
+
parsed.tools = parsed.tools.map(
|
|
99
|
+
(tool: { name: string; [key: string]: unknown }) => ({
|
|
100
|
+
...tool,
|
|
101
|
+
name: toolNameTransformer(tool.name),
|
|
102
|
+
}),
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (parsed.messages && Array.isArray(parsed.messages)) {
|
|
107
|
+
parsed.messages = parsed.messages.map(
|
|
108
|
+
(msg: { content: unknown; [key: string]: unknown }) => {
|
|
109
|
+
if (Array.isArray(msg.content)) {
|
|
110
|
+
const content = msg.content.map(
|
|
111
|
+
(block: {
|
|
112
|
+
type: string;
|
|
113
|
+
name?: string;
|
|
114
|
+
[key: string]: unknown;
|
|
115
|
+
}) => {
|
|
116
|
+
if (
|
|
117
|
+
(block.type === 'tool_use' ||
|
|
118
|
+
block.type === 'tool_result') &&
|
|
119
|
+
block.name
|
|
120
|
+
) {
|
|
121
|
+
return {
|
|
122
|
+
...block,
|
|
123
|
+
name: toolNameTransformer(block.name),
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
return block;
|
|
127
|
+
},
|
|
128
|
+
);
|
|
129
|
+
return { ...msg, content };
|
|
130
|
+
}
|
|
131
|
+
return msg;
|
|
132
|
+
},
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const withCache = addAnthropicCacheControl(parsed);
|
|
138
|
+
body = JSON.stringify(withCache);
|
|
139
|
+
} catch {
|
|
140
|
+
// If parsing fails, send as-is
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return fetch(url, { ...init, body, headers });
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export function createAnthropicOAuthModel(
|
|
149
|
+
model: string,
|
|
150
|
+
config: AnthropicOAuthConfig,
|
|
151
|
+
) {
|
|
152
|
+
const customFetch = createAnthropicOAuthFetch(config);
|
|
153
|
+
return createAnthropic({
|
|
154
|
+
apiKey: '',
|
|
155
|
+
fetch: customFetch as typeof fetch,
|
|
156
|
+
})(model);
|
|
157
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import {
|
|
2
|
+
isAuthorized as mgrIsAuthorized,
|
|
3
|
+
ensureEnv as mgrEnsureEnv,
|
|
4
|
+
} from '../../config/src/index.ts';
|
|
5
|
+
import type { OttoConfig } from '../../config/src/index.ts';
|
|
6
|
+
import type { ProviderId } from '../../types/src/index.ts';
|
|
7
|
+
|
|
8
|
+
export async function isProviderAuthorized(
|
|
9
|
+
cfg: OttoConfig,
|
|
10
|
+
provider: ProviderId,
|
|
11
|
+
) {
|
|
12
|
+
return await mgrIsAuthorized(provider, cfg.projectRoot);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export async function ensureProviderEnv(cfg: OttoConfig, provider: ProviderId) {
|
|
16
|
+
await mgrEnsureEnv(provider, cfg.projectRoot);
|
|
17
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ModelInfo,
|
|
3
|
+
ProviderCatalogEntry,
|
|
4
|
+
ProviderId,
|
|
5
|
+
ProviderFamily,
|
|
6
|
+
} from '../../types/src/index.ts';
|
|
7
|
+
|
|
8
|
+
type CatalogMap = Partial<Record<ProviderId, ProviderCatalogEntry>>;
|
|
9
|
+
|
|
10
|
+
const SETU_ID: ProviderId = 'setu';
|
|
11
|
+
|
|
12
|
+
const isAllowedOpenAIModel = (id: string): boolean => {
|
|
13
|
+
if (id === 'codex-mini-latest') return true;
|
|
14
|
+
if (id.startsWith('gpt-5')) return true;
|
|
15
|
+
if (id.includes('codex')) return true;
|
|
16
|
+
return false;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const isAllowedAnthropicModel = (id: string): boolean => {
|
|
20
|
+
if (id.includes('-3-5-') || id.includes('-3.5-')) return true;
|
|
21
|
+
if (id.match(/claude-(haiku|sonnet|opus)-3/)) return true;
|
|
22
|
+
if (id.includes('-4-') || id.includes('-4.')) return true;
|
|
23
|
+
if (id.match(/claude-(haiku|sonnet|opus)-4/)) return true;
|
|
24
|
+
return false;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const isAllowedGoogleModel = (id: string): boolean => {
|
|
28
|
+
if (id.startsWith('gemini-3')) return true;
|
|
29
|
+
return false;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const SETU_SOURCES: Array<{
|
|
33
|
+
id: ProviderId;
|
|
34
|
+
npm: string;
|
|
35
|
+
family: ProviderFamily;
|
|
36
|
+
}> = [
|
|
37
|
+
{
|
|
38
|
+
id: 'openai',
|
|
39
|
+
npm: '@ai-sdk/openai',
|
|
40
|
+
family: 'openai',
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
id: 'anthropic',
|
|
44
|
+
npm: '@ai-sdk/anthropic',
|
|
45
|
+
family: 'anthropic',
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
id: 'moonshot',
|
|
49
|
+
npm: '@ai-sdk/openai-compatible',
|
|
50
|
+
family: 'moonshot',
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
id: 'google',
|
|
54
|
+
npm: '@ai-sdk/google',
|
|
55
|
+
family: 'google',
|
|
56
|
+
},
|
|
57
|
+
];
|
|
58
|
+
|
|
59
|
+
function cloneModel(model: ModelInfo): ModelInfo {
|
|
60
|
+
return {
|
|
61
|
+
...model,
|
|
62
|
+
modalities: model.modalities
|
|
63
|
+
? {
|
|
64
|
+
input: model.modalities.input
|
|
65
|
+
? [...model.modalities.input]
|
|
66
|
+
: undefined,
|
|
67
|
+
output: model.modalities.output
|
|
68
|
+
? [...model.modalities.output]
|
|
69
|
+
: undefined,
|
|
70
|
+
}
|
|
71
|
+
: undefined,
|
|
72
|
+
cost: model.cost ? { ...model.cost } : undefined,
|
|
73
|
+
limit: model.limit ? { ...model.limit } : undefined,
|
|
74
|
+
provider: model.provider ? { ...model.provider } : undefined,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function buildSetuEntry(base: CatalogMap): ProviderCatalogEntry | null {
|
|
79
|
+
const setuModels = SETU_SOURCES.flatMap(({ id, npm, family }) => {
|
|
80
|
+
const allModels = base[id]?.models ?? [];
|
|
81
|
+
const sourceModels = allModels.filter((model) => {
|
|
82
|
+
if (id === 'openai') return isAllowedOpenAIModel(model.id);
|
|
83
|
+
if (id === 'anthropic') return isAllowedAnthropicModel(model.id);
|
|
84
|
+
if (id === 'google') return isAllowedGoogleModel(model.id);
|
|
85
|
+
return true;
|
|
86
|
+
});
|
|
87
|
+
return sourceModels.map((model) => {
|
|
88
|
+
const cloned = cloneModel(model);
|
|
89
|
+
cloned.provider = { ...(cloned.provider ?? {}), npm, family };
|
|
90
|
+
return cloned;
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
if (!setuModels.length) return null;
|
|
95
|
+
|
|
96
|
+
setuModels.sort((a, b) => {
|
|
97
|
+
const providerA = a.provider?.npm ?? '';
|
|
98
|
+
const providerB = b.provider?.npm ?? '';
|
|
99
|
+
if (providerA === providerB) {
|
|
100
|
+
return a.id.localeCompare(b.id);
|
|
101
|
+
}
|
|
102
|
+
if (providerA === '@ai-sdk/openai') return -1;
|
|
103
|
+
if (providerB === '@ai-sdk/openai') return 1;
|
|
104
|
+
return providerA.localeCompare(providerB);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
const defaultModelId = 'codex-mini-latest';
|
|
108
|
+
const defaultIdx = setuModels.findIndex((m) => m.id === defaultModelId);
|
|
109
|
+
if (defaultIdx > 0) {
|
|
110
|
+
const [picked] = setuModels.splice(defaultIdx, 1);
|
|
111
|
+
setuModels.unshift(picked);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return {
|
|
115
|
+
id: SETU_ID,
|
|
116
|
+
label: 'Setu',
|
|
117
|
+
env: ['SETU_PRIVATE_KEY'],
|
|
118
|
+
api: 'https://setu.ottocode.io/v1',
|
|
119
|
+
doc: 'https://setu.ottocode.io/docs',
|
|
120
|
+
models: setuModels,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export function mergeManualCatalog(
|
|
125
|
+
base: CatalogMap,
|
|
126
|
+
): Record<ProviderId, ProviderCatalogEntry> {
|
|
127
|
+
const manualEntry = buildSetuEntry(base);
|
|
128
|
+
const merged: Record<ProviderId, ProviderCatalogEntry> = {
|
|
129
|
+
...(base as Record<ProviderId, ProviderCatalogEntry>),
|
|
130
|
+
};
|
|
131
|
+
if (manualEntry) {
|
|
132
|
+
merged[SETU_ID] = manualEntry;
|
|
133
|
+
}
|
|
134
|
+
return merged;
|
|
135
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ProviderCatalogEntry,
|
|
3
|
+
ProviderId,
|
|
4
|
+
} from '../../types/src/index.ts';
|
|
5
|
+
import { catalog as generatedCatalog } from './catalog.ts';
|
|
6
|
+
import { mergeManualCatalog } from './catalog-manual.ts';
|
|
7
|
+
|
|
8
|
+
export const catalog: Record<ProviderId, ProviderCatalogEntry> =
|
|
9
|
+
mergeManualCatalog(generatedCatalog);
|