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.
Files changed (43) hide show
  1. package/package.json +3 -3
  2. package/src/agent/agent.test.ts +31 -24
  3. package/src/agent/index.ts +8 -2
  4. package/src/agent/loop.ts +303 -346
  5. package/src/agent/service.ts +252 -233
  6. package/src/agent/types.ts +2 -2
  7. package/src/collections/index.ts +2 -1
  8. package/src/collections/service.ts +352 -345
  9. package/src/config/config.test.ts +3 -1
  10. package/src/config/index.ts +615 -727
  11. package/src/config/remote.ts +214 -369
  12. package/src/context/index.ts +6 -12
  13. package/src/context/transaction.ts +23 -30
  14. package/src/effect/errors.ts +45 -0
  15. package/src/effect/layers.ts +26 -0
  16. package/src/effect/runtime.ts +19 -0
  17. package/src/effect/services.ts +154 -0
  18. package/src/index.ts +291 -369
  19. package/src/metrics/index.ts +46 -46
  20. package/src/pricing/models-dev.ts +104 -106
  21. package/src/providers/auth.ts +159 -200
  22. package/src/providers/index.ts +19 -2
  23. package/src/providers/model.ts +115 -135
  24. package/src/providers/openai.ts +3 -3
  25. package/src/resources/impls/git.ts +123 -146
  26. package/src/resources/impls/npm.test.ts +16 -5
  27. package/src/resources/impls/npm.ts +66 -75
  28. package/src/resources/index.ts +6 -1
  29. package/src/resources/schema.ts +7 -6
  30. package/src/resources/service.test.ts +13 -12
  31. package/src/resources/service.ts +153 -112
  32. package/src/stream/index.ts +1 -1
  33. package/src/stream/service.test.ts +5 -5
  34. package/src/stream/service.ts +282 -293
  35. package/src/tools/glob.ts +126 -141
  36. package/src/tools/grep.ts +205 -210
  37. package/src/tools/index.ts +8 -4
  38. package/src/tools/list.ts +118 -140
  39. package/src/tools/read.ts +209 -235
  40. package/src/tools/virtual-sandbox.ts +91 -83
  41. package/src/validation/index.ts +18 -22
  42. package/src/vfs/virtual-fs.test.ts +37 -25
  43. package/src/vfs/virtual-fs.ts +218 -216
@@ -1,57 +1,57 @@
1
- import { Result } from 'better-result';
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 namespace Metrics {
11
- export type Fields = Record<string, unknown>;
8
+ export type MetricsFields = Record<string, unknown>;
12
9
 
13
- export const setQuiet = (quiet: boolean) => {
14
- quietMode = quiet;
15
- };
10
+ export const setQuietMetrics = (quiet: boolean) => {
11
+ quietMode = quiet;
12
+ };
16
13
 
17
- export const isQuiet = () => quietMode;
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
- export const info = (event: string, fields?: Fields) => emit('info', event, fields);
40
- export const error = (event: string, fields?: Fields) => emit('error', event, fields);
16
+ export const metricsErrorInfo = (cause: unknown) => ({
17
+ tag: getErrorTag(cause),
18
+ message: getErrorMessage(cause)
19
+ });
41
20
 
42
- export const span = async <T>(
43
- name: string,
44
- fn: () => Promise<T>,
45
- fields?: Fields
46
- ): Promise<T> => {
47
- const start = performance.now();
48
- const result = await Result.tryPromise(fn);
49
- const ms = Math.round(performance.now() - start);
50
- if (!Result.isOk(result)) {
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 namespace ModelsDevPricing {
47
- export type RatesUsdPerMTokens = {
48
- input?: number;
49
- output?: number;
50
- reasoning?: number;
51
- cacheRead?: number;
52
- cacheWrite?: number;
53
- };
46
+ export type RatesUsdPerMTokens = {
47
+ input?: number;
48
+ output?: number;
49
+ reasoning?: number;
50
+ cacheRead?: number;
51
+ cacheWrite?: number;
52
+ };
54
53
 
55
- export type Pricing = {
56
- source: 'models.dev';
57
- modelKey: string;
58
- ratesUsdPerMTokens: RatesUsdPerMTokens;
59
- };
54
+ export type Pricing = {
55
+ source: 'models.dev';
56
+ modelKey: string;
57
+ ratesUsdPerMTokens: RatesUsdPerMTokens;
58
+ };
60
59
 
61
- export type Service = {
62
- prefetch: () => void;
63
- lookup: (args: {
64
- providerId: string;
65
- modelId: string;
66
- timeoutMs?: number;
67
- }) => Promise<Pricing | null>;
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
- type Index = {
71
- byProviderAndModel: Map<string, Pricing>;
72
- byId: Map<string, Pricing>;
73
- };
69
+ type PricingIndex = {
70
+ byProviderAndModel: Map<string, Pricing>;
71
+ byId: Map<string, Pricing>;
72
+ };
74
73
 
75
- const buildIndex = (api: ModelsDevApi): Index => {
76
- const byProviderAndModel = new Map<string, Pricing>();
77
- const byId = new Map<string, Pricing>();
78
-
79
- for (const [providerKey, provider] of Object.entries(api)) {
80
- const models = provider.models ?? {};
81
- for (const [modelKey, model] of Object.entries(models)) {
82
- const ratesUsdPerMTokens = toRates(model.cost);
83
- if (!hasAnyRate(ratesUsdPerMTokens)) continue;
84
-
85
- const pricing: Pricing = {
86
- source: 'models.dev',
87
- modelKey: (typeof model.id === 'string' && model.id.trim().length > 0
88
- ? model.id
89
- : modelKey
90
- ).trim(),
91
- ratesUsdPerMTokens
92
- };
93
-
94
- byProviderAndModel.set(`${providerKey}\0${modelKey}`, pricing);
95
- if (!byId.has(modelKey)) byId.set(modelKey, pricing);
96
- if (typeof model.id === 'string' && model.id.trim().length > 0 && !byId.has(model.id)) {
97
- byId.set(model.id, pricing);
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
- return { byProviderAndModel, byId };
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
- export const create = (args: { ttlMs?: number; url?: string } = {}): Service => {
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: 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
- const index = await inFlight;
138
- cached = { fetchedAtMs: now, index };
139
- return index;
140
- };
131
+ if (!inFlight) {
132
+ inFlight = fetchIndex().finally(() => {
133
+ inFlight = undefined;
134
+ });
135
+ }
141
136
 
142
- const lookup: Service['lookup'] = async ({ providerId, modelId, timeoutMs }) => {
143
- // Pricing is best-effort: no pricing for unknown/mapped providers.
144
- if (!providerId || !modelId) return null;
137
+ const index = await inFlight;
138
+ cached = { fetchedAtMs: now, index };
139
+ return index;
140
+ };
145
141
 
146
- const index = await (timeoutMs ? withTimeout(getIndex(), timeoutMs) : getIndex()).catch(
147
- () => null
148
- );
149
- if (!index) return null;
142
+ const lookup: ModelsDevPricingService['lookup'] = async ({ providerId, modelId, timeoutMs }) => {
143
+ if (!providerId || !modelId) return null;
150
144
 
151
- const direct = index.byProviderAndModel.get(`${providerId}\0${modelId}`);
152
- if (direct) return direct;
145
+ const index = await (timeoutMs ? withTimeout(getIndex(), timeoutMs) : getIndex()).catch(
146
+ () => null
147
+ );
148
+ if (!index) return null;
153
149
 
154
- const byId = index.byId;
155
- const exact = byId.get(modelId);
156
- if (exact) return exact;
150
+ const direct = index.byProviderAndModel.get(`${providerId}\0${modelId}`);
151
+ if (direct) return direct;
157
152
 
158
- const combined = byId.get(`${providerId}/${modelId}`);
159
- if (combined) return combined;
153
+ const byId = index.byId;
154
+ const exact = byId.get(modelId);
155
+ if (exact) return exact;
160
156
 
161
- return null;
162
- };
157
+ const combined = byId.get(`${providerId}/${modelId}`);
158
+ if (combined) return combined;
163
159
 
164
- const prefetch = () => {
165
- void getIndex().catch(() => undefined);
166
- };
160
+ return null;
161
+ };
167
162
 
168
- return { prefetch, lookup };
163
+ const prefetch = () => {
164
+ void getIndex().catch(() => undefined);
169
165
  };
170
- }
166
+
167
+ return { prefetch, lookup };
168
+ };