btca-server 1.0.961 → 2.0.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/package.json +3 -3
- package/src/agent/agent.test.ts +31 -24
- package/src/agent/index.ts +8 -2
- package/src/agent/loop.ts +303 -346
- package/src/agent/service.ts +252 -233
- package/src/agent/types.ts +2 -2
- package/src/collections/index.ts +2 -1
- package/src/collections/service.ts +352 -345
- package/src/config/config.test.ts +3 -1
- package/src/config/index.ts +615 -727
- package/src/config/remote.ts +214 -369
- package/src/context/index.ts +6 -12
- package/src/context/transaction.ts +23 -30
- package/src/effect/errors.ts +45 -0
- package/src/effect/layers.ts +26 -0
- package/src/effect/runtime.ts +19 -0
- package/src/effect/services.ts +154 -0
- package/src/index.ts +291 -369
- package/src/metrics/index.ts +46 -46
- package/src/pricing/models-dev.ts +104 -106
- package/src/providers/auth.ts +159 -200
- package/src/providers/index.ts +19 -2
- package/src/providers/model.ts +115 -135
- package/src/providers/openai.ts +3 -3
- package/src/resources/impls/git.ts +123 -146
- package/src/resources/impls/npm.test.ts +16 -5
- package/src/resources/impls/npm.ts +66 -75
- package/src/resources/index.ts +6 -1
- package/src/resources/schema.ts +7 -6
- package/src/resources/service.test.ts +13 -12
- package/src/resources/service.ts +153 -112
- package/src/stream/index.ts +1 -1
- package/src/stream/service.test.ts +5 -5
- package/src/stream/service.ts +282 -293
- package/src/tools/glob.ts +126 -141
- package/src/tools/grep.ts +205 -210
- package/src/tools/index.ts +8 -4
- package/src/tools/list.ts +118 -140
- package/src/tools/read.ts +209 -235
- package/src/tools/virtual-sandbox.ts +91 -83
- package/src/validation/index.ts +18 -22
- package/src/vfs/virtual-fs.test.ts +37 -25
- package/src/vfs/virtual-fs.ts +218 -216
package/src/metrics/index.ts
CHANGED
|
@@ -1,57 +1,57 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
import { Context } from '../context/index.ts';
|
|
1
|
+
import { requestId } from '../context/index.ts';
|
|
4
2
|
import { getErrorMessage, getErrorTag } from '../errors.ts';
|
|
5
3
|
|
|
6
4
|
type LogLevel = 'info' | 'error';
|
|
7
5
|
|
|
8
6
|
let quietMode = false;
|
|
9
7
|
|
|
10
|
-
export
|
|
11
|
-
export type Fields = Record<string, unknown>;
|
|
8
|
+
export type MetricsFields = Record<string, unknown>;
|
|
12
9
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
10
|
+
export const setQuietMetrics = (quiet: boolean) => {
|
|
11
|
+
quietMode = quiet;
|
|
12
|
+
};
|
|
16
13
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
export const errorInfo = (cause: unknown) => ({
|
|
20
|
-
tag: getErrorTag(cause),
|
|
21
|
-
message: getErrorMessage(cause)
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
const emit = (level: LogLevel, event: string, fields?: Fields) => {
|
|
25
|
-
if (quietMode) return;
|
|
26
|
-
|
|
27
|
-
const payload = {
|
|
28
|
-
ts: new Date().toISOString(),
|
|
29
|
-
level,
|
|
30
|
-
event,
|
|
31
|
-
requestId: Context.requestId(),
|
|
32
|
-
...fields
|
|
33
|
-
};
|
|
34
|
-
const line = JSON.stringify(payload);
|
|
35
|
-
if (level === 'error') console.error(line);
|
|
36
|
-
else console.log(line);
|
|
37
|
-
};
|
|
14
|
+
export const isMetricsQuiet = () => quietMode;
|
|
38
15
|
|
|
39
|
-
|
|
40
|
-
|
|
16
|
+
export const metricsErrorInfo = (cause: unknown) => ({
|
|
17
|
+
tag: getErrorTag(cause),
|
|
18
|
+
message: getErrorMessage(cause)
|
|
19
|
+
});
|
|
41
20
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
error('span.err', { name, ms, ...fields, error: errorInfo(result.error) });
|
|
52
|
-
throw result.error;
|
|
53
|
-
}
|
|
54
|
-
info('span.ok', { name, ms, ...fields });
|
|
55
|
-
return result.value;
|
|
21
|
+
const emitMetrics = (level: LogLevel, event: string, fields?: MetricsFields) => {
|
|
22
|
+
if (quietMode) return;
|
|
23
|
+
|
|
24
|
+
const payload = {
|
|
25
|
+
ts: new Date().toISOString(),
|
|
26
|
+
level,
|
|
27
|
+
event,
|
|
28
|
+
requestId: requestId(),
|
|
29
|
+
...fields
|
|
56
30
|
};
|
|
57
|
-
|
|
31
|
+
const line = JSON.stringify(payload);
|
|
32
|
+
if (level === 'error') console.error(line);
|
|
33
|
+
else console.log(line);
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export const metricsInfo = (event: string, fields?: MetricsFields) =>
|
|
37
|
+
emitMetrics('info', event, fields);
|
|
38
|
+
export const metricsError = (event: string, fields?: MetricsFields) =>
|
|
39
|
+
emitMetrics('error', event, fields);
|
|
40
|
+
|
|
41
|
+
export const withMetricsSpan = async <T>(
|
|
42
|
+
name: string,
|
|
43
|
+
fn: () => Promise<T>,
|
|
44
|
+
fields?: MetricsFields
|
|
45
|
+
): Promise<T> => {
|
|
46
|
+
const start = performance.now();
|
|
47
|
+
try {
|
|
48
|
+
const value = await fn();
|
|
49
|
+
const ms = Math.round(performance.now() - start);
|
|
50
|
+
metricsInfo('span.ok', { name, ms, ...fields });
|
|
51
|
+
return value;
|
|
52
|
+
} catch (errorCause) {
|
|
53
|
+
const ms = Math.round(performance.now() - start);
|
|
54
|
+
metricsError('span.err', { name, ms, ...fields, error: metricsErrorInfo(errorCause) });
|
|
55
|
+
throw errorCause;
|
|
56
|
+
}
|
|
57
|
+
};
|
|
@@ -43,128 +43,126 @@ const hasAnyRate = (rates: ReturnType<typeof toRates>) =>
|
|
|
43
43
|
rates.cacheRead != null ||
|
|
44
44
|
rates.cacheWrite != null;
|
|
45
45
|
|
|
46
|
-
export
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
};
|
|
46
|
+
export type RatesUsdPerMTokens = {
|
|
47
|
+
input?: number;
|
|
48
|
+
output?: number;
|
|
49
|
+
reasoning?: number;
|
|
50
|
+
cacheRead?: number;
|
|
51
|
+
cacheWrite?: number;
|
|
52
|
+
};
|
|
54
53
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
54
|
+
export type Pricing = {
|
|
55
|
+
source: 'models.dev';
|
|
56
|
+
modelKey: string;
|
|
57
|
+
ratesUsdPerMTokens: RatesUsdPerMTokens;
|
|
58
|
+
};
|
|
60
59
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
60
|
+
export type ModelsDevPricingService = {
|
|
61
|
+
prefetch: () => void;
|
|
62
|
+
lookup: (args: {
|
|
63
|
+
providerId: string;
|
|
64
|
+
modelId: string;
|
|
65
|
+
timeoutMs?: number;
|
|
66
|
+
}) => Promise<Pricing | null>;
|
|
67
|
+
};
|
|
69
68
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
69
|
+
type PricingIndex = {
|
|
70
|
+
byProviderAndModel: Map<string, Pricing>;
|
|
71
|
+
byId: Map<string, Pricing>;
|
|
72
|
+
};
|
|
74
73
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
}
|
|
99
|
-
if (!byId.has(`${providerKey}/${modelKey}`))
|
|
100
|
-
byId.set(`${providerKey}/${modelKey}`, pricing);
|
|
74
|
+
const buildPricingIndex = (api: ModelsDevApi): PricingIndex => {
|
|
75
|
+
const byProviderAndModel = new Map<string, Pricing>();
|
|
76
|
+
const byId = new Map<string, Pricing>();
|
|
77
|
+
|
|
78
|
+
for (const [providerKey, provider] of Object.entries(api)) {
|
|
79
|
+
const models = provider.models ?? {};
|
|
80
|
+
for (const [modelKey, model] of Object.entries(models)) {
|
|
81
|
+
const ratesUsdPerMTokens = toRates(model.cost);
|
|
82
|
+
if (!hasAnyRate(ratesUsdPerMTokens)) continue;
|
|
83
|
+
|
|
84
|
+
const pricing: Pricing = {
|
|
85
|
+
source: 'models.dev',
|
|
86
|
+
modelKey: (typeof model.id === 'string' && model.id.trim().length > 0
|
|
87
|
+
? model.id
|
|
88
|
+
: modelKey
|
|
89
|
+
).trim(),
|
|
90
|
+
ratesUsdPerMTokens
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
byProviderAndModel.set(`${providerKey}\0${modelKey}`, pricing);
|
|
94
|
+
if (!byId.has(modelKey)) byId.set(modelKey, pricing);
|
|
95
|
+
if (typeof model.id === 'string' && model.id.trim().length > 0 && !byId.has(model.id)) {
|
|
96
|
+
byId.set(model.id, pricing);
|
|
101
97
|
}
|
|
98
|
+
if (!byId.has(`${providerKey}/${modelKey}`)) byId.set(`${providerKey}/${modelKey}`, pricing);
|
|
102
99
|
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return { byProviderAndModel, byId };
|
|
103
|
+
};
|
|
103
104
|
|
|
104
|
-
|
|
105
|
+
export const createModelsDevPricing = (
|
|
106
|
+
args: { ttlMs?: number; url?: string } = {}
|
|
107
|
+
): ModelsDevPricingService => {
|
|
108
|
+
const ttlMs = args.ttlMs ?? 60 * 60 * 1000;
|
|
109
|
+
const url = args.url ?? MODELS_DEV_URL;
|
|
110
|
+
|
|
111
|
+
let cached:
|
|
112
|
+
| {
|
|
113
|
+
fetchedAtMs: number;
|
|
114
|
+
index: PricingIndex;
|
|
115
|
+
}
|
|
116
|
+
| undefined;
|
|
117
|
+
|
|
118
|
+
let inFlight: Promise<PricingIndex> | undefined;
|
|
119
|
+
|
|
120
|
+
const fetchIndex = async () => {
|
|
121
|
+
const res = await fetch(url);
|
|
122
|
+
if (!res.ok) throw new Error(`models.dev fetch failed: ${res.status}`);
|
|
123
|
+
const json = (await res.json()) as ModelsDevApi;
|
|
124
|
+
return buildPricingIndex(json);
|
|
105
125
|
};
|
|
106
126
|
|
|
107
|
-
|
|
108
|
-
const
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
let cached:
|
|
112
|
-
| {
|
|
113
|
-
fetchedAtMs: number;
|
|
114
|
-
index: Index;
|
|
115
|
-
}
|
|
116
|
-
| undefined;
|
|
117
|
-
|
|
118
|
-
let inFlight: Promise<Index> | undefined;
|
|
119
|
-
|
|
120
|
-
const fetchIndex = async () => {
|
|
121
|
-
const res = await fetch(url);
|
|
122
|
-
if (!res.ok) throw new Error(`models.dev fetch failed: ${res.status}`);
|
|
123
|
-
const json = (await res.json()) as ModelsDevApi;
|
|
124
|
-
return buildIndex(json);
|
|
125
|
-
};
|
|
126
|
-
|
|
127
|
-
const getIndex = async () => {
|
|
128
|
-
const now = Date.now();
|
|
129
|
-
if (cached && now - cached.fetchedAtMs < ttlMs) return cached.index;
|
|
130
|
-
|
|
131
|
-
if (!inFlight) {
|
|
132
|
-
inFlight = fetchIndex().finally(() => {
|
|
133
|
-
inFlight = undefined;
|
|
134
|
-
});
|
|
135
|
-
}
|
|
127
|
+
const getIndex = async () => {
|
|
128
|
+
const now = Date.now();
|
|
129
|
+
if (cached && now - cached.fetchedAtMs < ttlMs) return cached.index;
|
|
136
130
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
131
|
+
if (!inFlight) {
|
|
132
|
+
inFlight = fetchIndex().finally(() => {
|
|
133
|
+
inFlight = undefined;
|
|
134
|
+
});
|
|
135
|
+
}
|
|
141
136
|
|
|
142
|
-
const
|
|
143
|
-
|
|
144
|
-
|
|
137
|
+
const index = await inFlight;
|
|
138
|
+
cached = { fetchedAtMs: now, index };
|
|
139
|
+
return index;
|
|
140
|
+
};
|
|
145
141
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
);
|
|
149
|
-
if (!index) return null;
|
|
142
|
+
const lookup: ModelsDevPricingService['lookup'] = async ({ providerId, modelId, timeoutMs }) => {
|
|
143
|
+
if (!providerId || !modelId) return null;
|
|
150
144
|
|
|
151
|
-
|
|
152
|
-
|
|
145
|
+
const index = await (timeoutMs ? withTimeout(getIndex(), timeoutMs) : getIndex()).catch(
|
|
146
|
+
() => null
|
|
147
|
+
);
|
|
148
|
+
if (!index) return null;
|
|
153
149
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
if (exact) return exact;
|
|
150
|
+
const direct = index.byProviderAndModel.get(`${providerId}\0${modelId}`);
|
|
151
|
+
if (direct) return direct;
|
|
157
152
|
|
|
158
|
-
|
|
159
|
-
|
|
153
|
+
const byId = index.byId;
|
|
154
|
+
const exact = byId.get(modelId);
|
|
155
|
+
if (exact) return exact;
|
|
160
156
|
|
|
161
|
-
|
|
162
|
-
|
|
157
|
+
const combined = byId.get(`${providerId}/${modelId}`);
|
|
158
|
+
if (combined) return combined;
|
|
163
159
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
};
|
|
160
|
+
return null;
|
|
161
|
+
};
|
|
167
162
|
|
|
168
|
-
|
|
163
|
+
const prefetch = () => {
|
|
164
|
+
void getIndex().catch(() => undefined);
|
|
169
165
|
};
|
|
170
|
-
|
|
166
|
+
|
|
167
|
+
return { prefetch, lookup };
|
|
168
|
+
};
|