surfcode 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +325 -2
- package/assets/surfcode-logo.gif +0 -0
- package/dist/cli/auth.js +315 -0
- package/dist/cli/auth.js.map +1 -0
- package/dist/cli/config.js +228 -0
- package/dist/cli/config.js.map +1 -0
- package/dist/cli/headless.js +355 -0
- package/dist/cli/headless.js.map +1 -0
- package/dist/cli/inspect.js +462 -0
- package/dist/cli/inspect.js.map +1 -0
- package/dist/cli/interactive.js +130 -0
- package/dist/cli/interactive.js.map +1 -0
- package/dist/cli/sessions.js +170 -0
- package/dist/cli/sessions.js.map +1 -0
- package/dist/cli/sync.js +190 -0
- package/dist/cli/sync.js.map +1 -0
- package/dist/cli/util.js +345 -0
- package/dist/cli/util.js.map +1 -0
- package/dist/cli.js +485 -0
- package/dist/cli.js.map +1 -0
- package/dist/core/agent.js +281 -0
- package/dist/core/agent.js.map +1 -0
- package/dist/core/agents.js +55 -0
- package/dist/core/agents.js.map +1 -0
- package/dist/core/auth.js +107 -0
- package/dist/core/auth.js.map +1 -0
- package/dist/core/catalog.js +306 -0
- package/dist/core/catalog.js.map +1 -0
- package/dist/core/chat/anthropic.js +222 -0
- package/dist/core/chat/anthropic.js.map +1 -0
- package/dist/core/chat/common.js +367 -0
- package/dist/core/chat/common.js.map +1 -0
- package/dist/core/chat/google.js +180 -0
- package/dist/core/chat/google.js.map +1 -0
- package/dist/core/chat/index.js +80 -0
- package/dist/core/chat/index.js.map +1 -0
- package/dist/core/chat/openai.js +164 -0
- package/dist/core/chat/openai.js.map +1 -0
- package/dist/core/chat/types.js +2 -0
- package/dist/core/chat/types.js.map +1 -0
- package/dist/core/clipboard.js +34 -0
- package/dist/core/clipboard.js.map +1 -0
- package/dist/core/compact.js +39 -0
- package/dist/core/compact.js.map +1 -0
- package/dist/core/config.js +211 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/delegate.js +184 -0
- package/dist/core/delegate.js.map +1 -0
- package/dist/core/effort.js +80 -0
- package/dist/core/effort.js.map +1 -0
- package/dist/core/errors.js +32 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/free.js +21 -0
- package/dist/core/free.js.map +1 -0
- package/dist/core/github.js +445 -0
- package/dist/core/github.js.map +1 -0
- package/dist/core/paths.js +51 -0
- package/dist/core/paths.js.map +1 -0
- package/dist/core/prompt.js +95 -0
- package/dist/core/prompt.js.map +1 -0
- package/dist/core/provider.js +298 -0
- package/dist/core/provider.js.map +1 -0
- package/dist/core/session.js +159 -0
- package/dist/core/session.js.map +1 -0
- package/dist/core/sync.js +126 -0
- package/dist/core/sync.js.map +1 -0
- package/dist/core/types.js +2 -0
- package/dist/core/types.js.map +1 -0
- package/dist/core/usage.js +127 -0
- package/dist/core/usage.js.map +1 -0
- package/dist/core/workspace.js +70 -0
- package/dist/core/workspace.js.map +1 -0
- package/dist/data/models.json +1 -0
- package/dist/sync/server.js +179 -0
- package/dist/sync/server.js.map +1 -0
- package/dist/tools/diff.js +21 -0
- package/dist/tools/diff.js.map +1 -0
- package/dist/tools/files.js +227 -0
- package/dist/tools/files.js.map +1 -0
- package/dist/tools/github.js +238 -0
- package/dist/tools/github.js.map +1 -0
- package/dist/tools/index.js +34 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/search.js +231 -0
- package/dist/tools/search.js.map +1 -0
- package/dist/tools/shell.js +118 -0
- package/dist/tools/shell.js.map +1 -0
- package/dist/tools/todos.js +50 -0
- package/dist/tools/todos.js.map +1 -0
- package/dist/tools/webfetch.js +108 -0
- package/dist/tools/webfetch.js.map +1 -0
- package/dist/tui/App.js +3002 -0
- package/dist/tui/App.js.map +1 -0
- package/dist/tui/ansi.js +151 -0
- package/dist/tui/ansi.js.map +1 -0
- package/dist/tui/commands.js +61 -0
- package/dist/tui/commands.js.map +1 -0
- package/dist/tui/explorer.js +152 -0
- package/dist/tui/explorer.js.map +1 -0
- package/dist/tui/icons.js +21 -0
- package/dist/tui/icons.js.map +1 -0
- package/dist/tui/layout.js +324 -0
- package/dist/tui/layout.js.map +1 -0
- package/dist/tui/markdown.js +335 -0
- package/dist/tui/markdown.js.map +1 -0
- package/dist/tui/overlays.js +316 -0
- package/dist/tui/overlays.js.map +1 -0
- package/dist/tui/render.js +234 -0
- package/dist/tui/render.js.map +1 -0
- package/dist/tui/theme.js +148 -0
- package/dist/tui/theme.js.map +1 -0
- package/dist/tui/types.js +73 -0
- package/dist/tui/types.js.map +1 -0
- package/dist/version.js +3 -0
- package/dist/version.js.map +1 -0
- package/package.json +75 -4
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import { streamChat } from './chat/index.js';
|
|
2
|
+
import { costForUsage } from './usage.js';
|
|
3
|
+
const MAX_TASKS = 8;
|
|
4
|
+
const MAX_WORKER_OUTPUT = 6_000;
|
|
5
|
+
const MAX_CONTEXT_CHARS = 16_000;
|
|
6
|
+
export function createDelegateTool(options) {
|
|
7
|
+
const labels = options.delegates.map((delegate) => `${delegate.provider.id}/${delegate.model.id}`);
|
|
8
|
+
return {
|
|
9
|
+
name: 'delegate',
|
|
10
|
+
description: 'Run independent subtasks in parallel on the configured worker models, then return their answers to you. ' +
|
|
11
|
+
'Workers have no tools and cannot edit files. Use this for reviews, research, debugging hypotheses, or comparing approaches. ' +
|
|
12
|
+
`Available workers: ${labels.join(', ')}.`,
|
|
13
|
+
readOnly: true,
|
|
14
|
+
action: 'read',
|
|
15
|
+
parameters: {
|
|
16
|
+
type: 'object',
|
|
17
|
+
properties: {
|
|
18
|
+
tasks: {
|
|
19
|
+
type: 'array',
|
|
20
|
+
description: `1-${MAX_TASKS} independent tasks. All start at the same time.`,
|
|
21
|
+
items: {
|
|
22
|
+
type: 'object',
|
|
23
|
+
properties: {
|
|
24
|
+
worker: {
|
|
25
|
+
type: 'string',
|
|
26
|
+
description: `Optional worker id (${labels.join(', ')}). Omit to assign automatically.`
|
|
27
|
+
},
|
|
28
|
+
task: {
|
|
29
|
+
type: 'string',
|
|
30
|
+
description: 'A self-contained instruction for one worker model.'
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
required: ['task']
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
required: ['tasks']
|
|
38
|
+
},
|
|
39
|
+
async execute(args) {
|
|
40
|
+
const started = Date.now();
|
|
41
|
+
const rawTasks = Array.isArray(args.tasks) ? args.tasks : [];
|
|
42
|
+
const tasks = [];
|
|
43
|
+
for (const [index, entry] of rawTasks.slice(0, MAX_TASKS).entries()) {
|
|
44
|
+
if (!entry || typeof entry !== 'object')
|
|
45
|
+
continue;
|
|
46
|
+
const record = entry;
|
|
47
|
+
const task = String(record.task ?? '').trim();
|
|
48
|
+
if (!task)
|
|
49
|
+
continue;
|
|
50
|
+
const requested = typeof record.worker === 'string' ? record.worker.trim() : '';
|
|
51
|
+
const delegate = requested
|
|
52
|
+
? matchWorker(options.delegates, requested)
|
|
53
|
+
: options.delegates[index % options.delegates.length];
|
|
54
|
+
if (!delegate) {
|
|
55
|
+
tasks.push({
|
|
56
|
+
delegate: options.delegates[index % options.delegates.length],
|
|
57
|
+
task: `[worker "${requested}" was not found; answer this anyway]\n${task}`
|
|
58
|
+
});
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
tasks.push({ delegate, task });
|
|
62
|
+
}
|
|
63
|
+
if (tasks.length === 0) {
|
|
64
|
+
return {
|
|
65
|
+
output: 'No delegation tasks were provided.',
|
|
66
|
+
isError: true,
|
|
67
|
+
display: { summary: 'no tasks' }
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
const context = compactHistory(options.getHistory());
|
|
71
|
+
const results = await Promise.allSettled(tasks.map(({ delegate, task }) => runWorker(options, delegate, task, context)));
|
|
72
|
+
const blocks = [];
|
|
73
|
+
let succeeded = 0;
|
|
74
|
+
let failed = 0;
|
|
75
|
+
for (const [index, result] of results.entries()) {
|
|
76
|
+
const { delegate, task } = tasks[index];
|
|
77
|
+
const label = `${delegate.provider.id}/${delegate.model.id}`;
|
|
78
|
+
if (result.status === 'fulfilled') {
|
|
79
|
+
succeeded += 1;
|
|
80
|
+
const text = result.value.text.trim() || '(the worker returned no text)';
|
|
81
|
+
blocks.push(`### ${label}\n${clip(text, MAX_WORKER_OUTPUT)}`);
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
failed += 1;
|
|
85
|
+
const reason = result.reason instanceof Error ? result.reason.message : String(result.reason);
|
|
86
|
+
blocks.push(`### ${label}\n_Worker failed: ${clip(reason, 800)}_\n\nTask: ${clip(task, 500)}`);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
const seconds = ((Date.now() - started) / 1000).toFixed(1);
|
|
90
|
+
return {
|
|
91
|
+
output: blocks.join('\n\n'),
|
|
92
|
+
title: 'delegate',
|
|
93
|
+
isError: succeeded === 0,
|
|
94
|
+
display: {
|
|
95
|
+
kind: 'text',
|
|
96
|
+
summary: `${succeeded} worker${succeeded === 1 ? '' : 's'}${failed ? ` · ${failed} failed` : ''} · ${seconds}s`,
|
|
97
|
+
lines: succeeded
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
async function runWorker(options, delegate, task, context) {
|
|
104
|
+
const system = `You are a worker model inside SurfCode's multi-model /agent mode.
|
|
105
|
+
The head model is coordinating several workers in parallel. Answer only the task you were given.
|
|
106
|
+
You have NO tools: do not read files, run commands, or claim that you did.
|
|
107
|
+
Use the conversation context below, be specific, and return GitHub-flavored Markdown.
|
|
108
|
+
Keep the answer focused and under 500 words unless the task genuinely needs more.
|
|
109
|
+
|
|
110
|
+
Workspace: ${options.cwd}
|
|
111
|
+
Worker: ${delegate.provider.name} / ${delegate.model.name}`;
|
|
112
|
+
const messages = [
|
|
113
|
+
...(context ? [{ role: 'user', content: `Conversation context:\n\n${context}` }] : []),
|
|
114
|
+
{ role: 'user', content: task }
|
|
115
|
+
];
|
|
116
|
+
const result = await streamChat({
|
|
117
|
+
provider: delegate.provider,
|
|
118
|
+
model: delegate.model,
|
|
119
|
+
messages,
|
|
120
|
+
system,
|
|
121
|
+
tools: [],
|
|
122
|
+
options: {
|
|
123
|
+
signal: options.signal,
|
|
124
|
+
maxTokens: Math.min(options.maxTokens, 8_192),
|
|
125
|
+
temperature: options.temperature,
|
|
126
|
+
effort: options.effort,
|
|
127
|
+
showReasoning: false,
|
|
128
|
+
timeout: delegate.provider.settings.timeout
|
|
129
|
+
},
|
|
130
|
+
callbacks: {
|
|
131
|
+
onText() { },
|
|
132
|
+
onReasoning() { }
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
const usage = {
|
|
136
|
+
inputTokens: result.usage.inputTokens ?? 0,
|
|
137
|
+
outputTokens: result.usage.outputTokens ?? 0,
|
|
138
|
+
reasoningTokens: result.usage.reasoningTokens ?? 0,
|
|
139
|
+
cacheReadTokens: result.usage.cacheReadTokens ?? 0,
|
|
140
|
+
cacheWriteTokens: result.usage.cacheWriteTokens ?? 0,
|
|
141
|
+
cost: costForUsage(delegate.model.meta, result.usage, delegate.provider.dialect),
|
|
142
|
+
requests: 1
|
|
143
|
+
};
|
|
144
|
+
options.onUsage?.(usage);
|
|
145
|
+
return { text: result.text, usage };
|
|
146
|
+
}
|
|
147
|
+
function matchWorker(delegates, reference) {
|
|
148
|
+
const wanted = reference.toLowerCase();
|
|
149
|
+
return delegates.find((delegate) => {
|
|
150
|
+
const id = `${delegate.provider.id}/${delegate.model.id}`.toLowerCase();
|
|
151
|
+
return (id === wanted ||
|
|
152
|
+
delegate.model.id.toLowerCase() === wanted ||
|
|
153
|
+
delegate.provider.id.toLowerCase() === wanted ||
|
|
154
|
+
delegate.model.name.toLowerCase() === wanted);
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
function compactHistory(messages) {
|
|
158
|
+
const blocks = [];
|
|
159
|
+
let total = 0;
|
|
160
|
+
for (let index = messages.length - 1; index >= 0; index -= 1) {
|
|
161
|
+
const message = messages[index];
|
|
162
|
+
if (message.role === 'user') {
|
|
163
|
+
blocks.push(`User: ${clip(message.content, 2_000)}`);
|
|
164
|
+
}
|
|
165
|
+
else if (message.role === 'assistant') {
|
|
166
|
+
if (message.content)
|
|
167
|
+
blocks.push(`Assistant: ${clip(message.content, 2_000)}`);
|
|
168
|
+
for (const call of message.toolCalls ?? []) {
|
|
169
|
+
blocks.push(`Assistant called ${call.name}(${clip(JSON.stringify(call.arguments), 600)})`);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
else {
|
|
173
|
+
blocks.push(`Tool ${message.name}${message.isError ? ' (error)' : ''}: ${clip(message.content, 1_200)}`);
|
|
174
|
+
}
|
|
175
|
+
total += blocks.at(-1).length;
|
|
176
|
+
if (total >= MAX_CONTEXT_CHARS)
|
|
177
|
+
break;
|
|
178
|
+
}
|
|
179
|
+
return blocks.reverse().join('\n\n').slice(-MAX_CONTEXT_CHARS);
|
|
180
|
+
}
|
|
181
|
+
function clip(text, max) {
|
|
182
|
+
return text.length <= max ? text : `${text.slice(0, max)}…`;
|
|
183
|
+
}
|
|
184
|
+
//# sourceMappingURL=delegate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delegate.js","sourceRoot":"","sources":["../../src/core/delegate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
export const EFFORT_LEVELS = ['low', 'medium', 'high'];
|
|
2
|
+
export const EFFORT_SETTINGS = ['auto', ...EFFORT_LEVELS];
|
|
3
|
+
const ANTHROPIC_BUDGETS = {
|
|
4
|
+
low: 2_048,
|
|
5
|
+
medium: 8_192,
|
|
6
|
+
high: 16_384
|
|
7
|
+
};
|
|
8
|
+
const GOOGLE_BUDGETS = {
|
|
9
|
+
low: 1_024,
|
|
10
|
+
medium: 8_192,
|
|
11
|
+
high: 24_576
|
|
12
|
+
};
|
|
13
|
+
export const EFFORT_GUIDANCE = {
|
|
14
|
+
low: 'Answer directly. Spend little time deliberating and keep tool use to the minimum needed.',
|
|
15
|
+
medium: 'Balance speed and depth. Reason through the problem, then act.',
|
|
16
|
+
high: 'Think carefully. Explore alternatives, verify assumptions, and check your work before answering.'
|
|
17
|
+
};
|
|
18
|
+
export function parseEffort(value) {
|
|
19
|
+
const normalized = value.trim().toLowerCase();
|
|
20
|
+
return EFFORT_SETTINGS.includes(normalized)
|
|
21
|
+
? normalized
|
|
22
|
+
: undefined;
|
|
23
|
+
}
|
|
24
|
+
export function activeEffort(value) {
|
|
25
|
+
return value && value !== 'auto' ? value : undefined;
|
|
26
|
+
}
|
|
27
|
+
export function effortLabel(value) {
|
|
28
|
+
return !value || value === 'auto' ? 'auto (provider default)' : value;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Extended-thinking budget for Anthropic. The API requires room for both the
|
|
32
|
+
* thinking block and the final answer, so leave at least 1k tokens for text.
|
|
33
|
+
*/
|
|
34
|
+
export function anthropicThinkingBudget(effort, maxTokens) {
|
|
35
|
+
const available = maxTokens - 1_024;
|
|
36
|
+
if (available < 1_024)
|
|
37
|
+
return undefined;
|
|
38
|
+
return Math.min(ANTHROPIC_BUDGETS[effort], available);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Gemini counts thinking tokens inside maxOutputTokens. Keep a small reserve
|
|
42
|
+
* so a small output limit cannot make the request invalid.
|
|
43
|
+
*/
|
|
44
|
+
export function googleThinkingBudget(effort, maxTokens) {
|
|
45
|
+
const available = maxTokens - 512;
|
|
46
|
+
if (available < 1)
|
|
47
|
+
return undefined;
|
|
48
|
+
return Math.min(GOOGLE_BUDGETS[effort], available);
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Gemini 3 and newer take `thinkingLevel`; Gemini 2.5 takes `thinkingBudget`.
|
|
52
|
+
* Flash-Lite models get `minimal` for low effort, which is their true
|
|
53
|
+
* "no thinking" setting. Gemini 2.5 Flash/Flash-Lite accept a zero budget.
|
|
54
|
+
* Pro models cannot fully disable thinking, so low stays at a small budget.
|
|
55
|
+
*/
|
|
56
|
+
export function googleThinkingControl(modelId, effort, maxTokens) {
|
|
57
|
+
const id = modelId.toLowerCase();
|
|
58
|
+
const match = /gemini-(\d+)(?:\.(\d+))?/.exec(id);
|
|
59
|
+
const major = match ? Number(match[1]) : 0;
|
|
60
|
+
const minor = match?.[2] ? Number(match[2]) : 0;
|
|
61
|
+
const lite = /flash[-_.]?lite|lite/.test(id);
|
|
62
|
+
const pro = /(?:^|[-_/])pro(?:$|[-_/])/.test(id);
|
|
63
|
+
if (major >= 3) {
|
|
64
|
+
const low = lite ? 'minimal' : 'low';
|
|
65
|
+
return { thinkingLevel: effort === 'low' ? low : effort };
|
|
66
|
+
}
|
|
67
|
+
if (major === 2 && minor >= 5) {
|
|
68
|
+
if (effort === 'low' && !pro)
|
|
69
|
+
return { thinkingBudget: 0 };
|
|
70
|
+
const budget = googleThinkingBudget(effort, maxTokens);
|
|
71
|
+
return budget === undefined ? undefined : { thinkingBudget: budget };
|
|
72
|
+
}
|
|
73
|
+
const budget = googleThinkingBudget(effort, maxTokens);
|
|
74
|
+
return budget === undefined ? undefined : { thinkingBudget: budget };
|
|
75
|
+
}
|
|
76
|
+
/** Providers whose OpenAI-compatible endpoint understands `reasoning_effort`. */
|
|
77
|
+
export function supportsOpenAiEffort(providerId) {
|
|
78
|
+
return new Set(['openai', 'azure', 'groq', 'cerebras', 'openrouter']).has(providerId);
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=effort.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"effort.js","sourceRoot":"","sources":["../../src/core/effort.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export class SurfError extends Error {
|
|
2
|
+
hint;
|
|
3
|
+
exitCode;
|
|
4
|
+
status;
|
|
5
|
+
retryable;
|
|
6
|
+
constructor(message, options = {}) {
|
|
7
|
+
super(message, { cause: options.cause });
|
|
8
|
+
this.name = 'SurfError';
|
|
9
|
+
this.hint = options.hint;
|
|
10
|
+
this.exitCode = options.exitCode ?? 1;
|
|
11
|
+
this.status = options.status;
|
|
12
|
+
this.retryable = options.retryable;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
export function errorMessage(error) {
|
|
16
|
+
if (error instanceof Error)
|
|
17
|
+
return error.message;
|
|
18
|
+
return String(error);
|
|
19
|
+
}
|
|
20
|
+
export function isAbortError(error) {
|
|
21
|
+
if (!(error instanceof Error))
|
|
22
|
+
return false;
|
|
23
|
+
// AbortSignal.timeout() uses TimeoutError, which is retryable. It must not
|
|
24
|
+
// be mistaken for a user cancellation just because its message says
|
|
25
|
+
// "aborted due to timeout".
|
|
26
|
+
if (error.name === 'TimeoutError')
|
|
27
|
+
return false;
|
|
28
|
+
if (error.name === 'AbortError')
|
|
29
|
+
return true;
|
|
30
|
+
return /(?:request|operation|signal) aborted/i.test(error.message) && !/timeout/i.test(error.message);
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/core/errors.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,SAAU,SAAQ,KAAK;IACzB,IAAI,CAAU;IACd,QAAQ,CAAS;IACjB,MAAM,CAAU;IAChB,SAAS,CAAW;IAE7B,YACE,OAAe,EACf,UAMI,EAAE;QAEN,KAAK,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;QACzC,IAAI,CAAC,IAAI,GAAG,WAAW,CAAC;QACxB,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;QACzB,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,CAAC,CAAC;QACtC,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;QAC7B,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC;IACrC,CAAC;CACF;AAED,MAAM,UAAU,YAAY,CAAC,KAAc;IACzC,IAAI,KAAK,YAAY,KAAK;QAAE,OAAO,KAAK,CAAC,OAAO,CAAC;IACjD,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,KAAc;IACzC,IAAI,CAAC,CAAC,KAAK,YAAY,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAC5C,2EAA2E;IAC3E,oEAAoE;IACpE,4BAA4B;IAC5B,IAAI,KAAK,CAAC,IAAI,KAAK,cAAc;QAAE,OAAO,KAAK,CAAC;IAChD,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY;QAAE,OAAO,IAAI,CAAC;IAC7C,OAAO,uCAAuC,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;AACxG,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Providers with a permanent no-cost API tier.
|
|
3
|
+
*
|
|
4
|
+
* A badge means the provider itself offers free, rate-limited inference; it
|
|
5
|
+
* does not mean every model is free. Trial credits and one-off promotions are
|
|
6
|
+
* deliberately excluded because they expire. Local runtimes are already
|
|
7
|
+
* labelled separately in the UI.
|
|
8
|
+
*/
|
|
9
|
+
export const FREE_API_PROVIDERS = new Set([
|
|
10
|
+
'google',
|
|
11
|
+
'groq',
|
|
12
|
+
'mistral',
|
|
13
|
+
'openrouter',
|
|
14
|
+
'cloudflare-workers-ai'
|
|
15
|
+
]);
|
|
16
|
+
export function hasFreeApi(providerId) {
|
|
17
|
+
return FREE_API_PROVIDERS.has(providerId);
|
|
18
|
+
}
|
|
19
|
+
export const FREE_API_LABEL = '[FREE API]';
|
|
20
|
+
export const FREE_API_HINT = 'free tier · rate-limited';
|
|
21
|
+
//# sourceMappingURL=free.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"free.js","sourceRoot":"","sources":["../../src/core/free.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,IAAI,GAAG,CAAC;IACxC,QAAQ;IACR,MAAM;IACN,SAAS;IACT,YAAY;IACZ,uBAAuB;CACxB,CAAC,CAAC;AAEH,MAAM,UAAU,UAAU,CAAC,UAAkB;IAC3C,OAAO,kBAAkB,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;AAC5C,CAAC;AAED,MAAM,CAAC,MAAM,cAAc,GAAG,YAAY,CAAC;AAC3C,MAAM,CAAC,MAAM,aAAa,GAAG,0BAA0B,CAAC"}
|