btca-server 1.0.962 → 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
|
@@ -1,33 +1,26 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { metricsError, metricsErrorInfo, metricsInfo } from '../metrics/index.ts';
|
|
2
|
+
import { requireContext } from './index.ts';
|
|
2
3
|
|
|
3
|
-
|
|
4
|
-
|
|
4
|
+
export const runTransaction = async <T>(name: string, fn: () => Promise<T>): Promise<T> => {
|
|
5
|
+
const store = requireContext();
|
|
6
|
+
const depth = store.txDepth;
|
|
7
|
+
store.txDepth = depth + 1;
|
|
5
8
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
ok: (value) => {
|
|
19
|
-
Metrics.info('tx.commit', { name, depth, ms: Math.round(performance.now() - start) });
|
|
20
|
-
return value;
|
|
21
|
-
},
|
|
22
|
-
err: (cause) => {
|
|
23
|
-
Metrics.error('tx.rollback', {
|
|
24
|
-
name,
|
|
25
|
-
depth,
|
|
26
|
-
ms: Math.round(performance.now() - start),
|
|
27
|
-
error: Metrics.errorInfo(cause)
|
|
28
|
-
});
|
|
29
|
-
throw cause;
|
|
30
|
-
}
|
|
9
|
+
const start = performance.now();
|
|
10
|
+
metricsInfo('tx.start', { name, depth });
|
|
11
|
+
try {
|
|
12
|
+
const value = await fn();
|
|
13
|
+
metricsInfo('tx.commit', { name, depth, ms: Math.round(performance.now() - start) });
|
|
14
|
+
return value;
|
|
15
|
+
} catch (cause) {
|
|
16
|
+
metricsError('tx.rollback', {
|
|
17
|
+
name,
|
|
18
|
+
depth,
|
|
19
|
+
ms: Math.round(performance.now() - start),
|
|
20
|
+
error: metricsErrorInfo(cause)
|
|
31
21
|
});
|
|
32
|
-
|
|
33
|
-
}
|
|
22
|
+
throw cause;
|
|
23
|
+
} finally {
|
|
24
|
+
store.txDepth = depth;
|
|
25
|
+
}
|
|
26
|
+
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { Data } from 'effect';
|
|
2
|
+
import { getErrorHint, getErrorMessage, getErrorTag } from '../errors.ts';
|
|
3
|
+
|
|
4
|
+
export class ServerError extends Data.TaggedError('ServerError')<{
|
|
5
|
+
readonly message: string;
|
|
6
|
+
readonly hint?: string;
|
|
7
|
+
readonly cause?: unknown;
|
|
8
|
+
}> {}
|
|
9
|
+
|
|
10
|
+
export interface HttpErrorPayload {
|
|
11
|
+
readonly error: string;
|
|
12
|
+
readonly tag: string;
|
|
13
|
+
readonly hint?: string;
|
|
14
|
+
readonly status: number;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const getHttpStatusFromErrorTag = (tag: string) => {
|
|
18
|
+
if (
|
|
19
|
+
tag === 'RequestError' ||
|
|
20
|
+
tag === 'CollectionError' ||
|
|
21
|
+
tag === 'ResourceError' ||
|
|
22
|
+
tag === 'ConfigError' ||
|
|
23
|
+
tag === 'InvalidProviderError' ||
|
|
24
|
+
tag === 'InvalidModelError' ||
|
|
25
|
+
tag === 'ProviderNotAuthenticatedError' ||
|
|
26
|
+
tag === 'ProviderAuthTypeError' ||
|
|
27
|
+
tag === 'ProviderNotFoundError' ||
|
|
28
|
+
tag === 'ProviderNotConnectedError' ||
|
|
29
|
+
tag === 'ProviderOptionsError'
|
|
30
|
+
) {
|
|
31
|
+
return 400;
|
|
32
|
+
}
|
|
33
|
+
if (tag === 'RouteNotFound') return 404;
|
|
34
|
+
return 500;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export const toHttpErrorPayload = (error: unknown): HttpErrorPayload => {
|
|
38
|
+
const tag = getErrorTag(error);
|
|
39
|
+
return {
|
|
40
|
+
error: getErrorMessage(error),
|
|
41
|
+
tag,
|
|
42
|
+
hint: getErrorHint(error),
|
|
43
|
+
status: getHttpStatusFromErrorTag(tag)
|
|
44
|
+
};
|
|
45
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Layer, ServiceMap, pipe } from 'effect';
|
|
2
|
+
import type { AgentService as AgentServiceShape } from '../agent/service.ts';
|
|
3
|
+
import type { CollectionsService as CollectionsServiceShape } from '../collections/service.ts';
|
|
4
|
+
import type { ConfigService as ConfigServiceShape } from '../config/index.ts';
|
|
5
|
+
import { AgentService, CollectionsService, ConfigService } from './services.ts';
|
|
6
|
+
|
|
7
|
+
export type ServerLayerDependencies = {
|
|
8
|
+
config: ConfigServiceShape;
|
|
9
|
+
collections: CollectionsServiceShape;
|
|
10
|
+
agent: AgentServiceShape;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export const makeServerLayer = (dependencies: ServerLayerDependencies) =>
|
|
14
|
+
Layer.mergeAll(
|
|
15
|
+
Layer.succeed(ConfigService, dependencies.config),
|
|
16
|
+
Layer.succeed(CollectionsService, dependencies.collections),
|
|
17
|
+
Layer.succeed(AgentService, dependencies.agent)
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
export const makeServerServiceMap = (dependencies: ServerLayerDependencies) =>
|
|
21
|
+
pipe(
|
|
22
|
+
ServiceMap.empty(),
|
|
23
|
+
ServiceMap.add(ConfigService, dependencies.config),
|
|
24
|
+
ServiceMap.add(CollectionsService, dependencies.collections),
|
|
25
|
+
ServiceMap.add(AgentService, dependencies.agent)
|
|
26
|
+
);
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Effect, Exit, ManagedRuntime } from 'effect';
|
|
2
|
+
import { makeServerLayer, makeServerServiceMap, type ServerLayerDependencies } from './layers.ts';
|
|
3
|
+
|
|
4
|
+
export interface ServerRuntime {
|
|
5
|
+
runPromise: <A, E>(effect: Effect.Effect<A, E>) => Promise<A>;
|
|
6
|
+
runPromiseExit: <A, E>(effect: Effect.Effect<A, E>) => Promise<Exit.Exit<A, E>>;
|
|
7
|
+
services: () => Promise<ReturnType<typeof makeServerServiceMap>>;
|
|
8
|
+
dispose: () => Promise<void>;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const createServerRuntime = (dependencies: ServerLayerDependencies): ServerRuntime => {
|
|
12
|
+
const runtime = ManagedRuntime.make(makeServerLayer(dependencies));
|
|
13
|
+
return {
|
|
14
|
+
runPromise: (effect) => runtime.runPromise(effect),
|
|
15
|
+
runPromiseExit: (effect) => runtime.runPromiseExit(effect),
|
|
16
|
+
services: () => runtime.services(),
|
|
17
|
+
dispose: () => runtime.dispose()
|
|
18
|
+
};
|
|
19
|
+
};
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { Effect, ServiceMap } from 'effect';
|
|
2
|
+
import type { AgentService as AgentServiceShape } from '../agent/service.ts';
|
|
3
|
+
import type { CollectionsService as CollectionsServiceShape } from '../collections/service.ts';
|
|
4
|
+
import { getCollectionKey } from '../collections/types.ts';
|
|
5
|
+
import type { ConfigService as ConfigServiceShape } from '../config/index.ts';
|
|
6
|
+
import type { ResourceDefinition } from '../resources/schema.ts';
|
|
7
|
+
|
|
8
|
+
export class ConfigService extends ServiceMap.Service<ConfigService, ConfigServiceShape>()(
|
|
9
|
+
'btca-server/effect/ConfigService'
|
|
10
|
+
) {}
|
|
11
|
+
|
|
12
|
+
export class CollectionsService extends ServiceMap.Service<
|
|
13
|
+
CollectionsService,
|
|
14
|
+
CollectionsServiceShape
|
|
15
|
+
>()('btca-server/effect/CollectionsService') {}
|
|
16
|
+
|
|
17
|
+
export class AgentService extends ServiceMap.Service<AgentService, AgentServiceShape>()(
|
|
18
|
+
'btca-server/effect/AgentService'
|
|
19
|
+
) {}
|
|
20
|
+
|
|
21
|
+
const configService = Effect.service(ConfigService);
|
|
22
|
+
const collectionsService = Effect.service(CollectionsService);
|
|
23
|
+
const agentService = Effect.service(AgentService);
|
|
24
|
+
|
|
25
|
+
export type ConfigSnapshot = {
|
|
26
|
+
provider: string;
|
|
27
|
+
model: string;
|
|
28
|
+
providerTimeoutMs: number | null;
|
|
29
|
+
maxSteps: number;
|
|
30
|
+
resourcesDirectory: string;
|
|
31
|
+
resourceCount: number;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export type ResourcesSnapshot = {
|
|
35
|
+
resources: Array<{
|
|
36
|
+
name: string;
|
|
37
|
+
type: 'git' | 'local' | 'npm';
|
|
38
|
+
url?: string;
|
|
39
|
+
branch?: string;
|
|
40
|
+
path?: string;
|
|
41
|
+
package?: string;
|
|
42
|
+
version?: string | null;
|
|
43
|
+
searchPath?: string | null;
|
|
44
|
+
searchPaths?: string[] | null;
|
|
45
|
+
specialNotes?: string | null;
|
|
46
|
+
}>;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export const getConfigSnapshot: Effect.Effect<ConfigSnapshot, never, ConfigService> = Effect.map(
|
|
50
|
+
configService,
|
|
51
|
+
(config) => ({
|
|
52
|
+
provider: config.provider,
|
|
53
|
+
model: config.model,
|
|
54
|
+
providerTimeoutMs: config.providerTimeoutMs ?? null,
|
|
55
|
+
maxSteps: config.maxSteps,
|
|
56
|
+
resourcesDirectory: config.resourcesDirectory,
|
|
57
|
+
resourceCount: config.resources.length
|
|
58
|
+
})
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
export const getResourcesSnapshot: Effect.Effect<ResourcesSnapshot, never, ConfigService> =
|
|
62
|
+
Effect.map(configService, (config) => ({
|
|
63
|
+
resources: config.resources.map((resource) => {
|
|
64
|
+
if (resource.type === 'git') {
|
|
65
|
+
return {
|
|
66
|
+
name: resource.name,
|
|
67
|
+
type: resource.type,
|
|
68
|
+
url: resource.url,
|
|
69
|
+
branch: resource.branch,
|
|
70
|
+
searchPath: resource.searchPath ?? null,
|
|
71
|
+
searchPaths: resource.searchPaths ?? null,
|
|
72
|
+
specialNotes: resource.specialNotes ?? null
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
if (resource.type === 'local') {
|
|
76
|
+
return {
|
|
77
|
+
name: resource.name,
|
|
78
|
+
type: resource.type,
|
|
79
|
+
path: resource.path,
|
|
80
|
+
specialNotes: resource.specialNotes ?? null
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
return {
|
|
84
|
+
name: resource.name,
|
|
85
|
+
type: resource.type,
|
|
86
|
+
package: resource.package,
|
|
87
|
+
version: resource.version ?? null,
|
|
88
|
+
specialNotes: resource.specialNotes ?? null
|
|
89
|
+
};
|
|
90
|
+
})
|
|
91
|
+
}));
|
|
92
|
+
|
|
93
|
+
export const getDefaultResourceNames: Effect.Effect<string[], never, ConfigService> = Effect.map(
|
|
94
|
+
configService,
|
|
95
|
+
(config) => config.resources.map((resource) => resource.name)
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
export const reloadConfig: Effect.Effect<void, unknown, ConfigService> = Effect.flatMap(
|
|
99
|
+
configService,
|
|
100
|
+
(config) => config.reloadEffect()
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
export const listProviders: Effect.Effect<
|
|
104
|
+
Awaited<ReturnType<AgentServiceShape['listProviders']>>,
|
|
105
|
+
unknown,
|
|
106
|
+
AgentService
|
|
107
|
+
> = Effect.flatMap(agentService, (agent) => agent.listProvidersEffect());
|
|
108
|
+
|
|
109
|
+
export const loadCollection = (args: {
|
|
110
|
+
resourceNames: readonly string[];
|
|
111
|
+
quiet?: boolean;
|
|
112
|
+
}): Effect.Effect<
|
|
113
|
+
Awaited<ReturnType<CollectionsServiceShape['load']>>,
|
|
114
|
+
unknown,
|
|
115
|
+
CollectionsService
|
|
116
|
+
> => Effect.flatMap(collectionsService, (collections) => collections.loadEffect(args));
|
|
117
|
+
|
|
118
|
+
export const askQuestion = (args: {
|
|
119
|
+
collection: Awaited<ReturnType<CollectionsServiceShape['load']>>;
|
|
120
|
+
question: string;
|
|
121
|
+
}): Effect.Effect<Awaited<ReturnType<AgentServiceShape['ask']>>, unknown, AgentService> =>
|
|
122
|
+
Effect.flatMap(agentService, (agent) => agent.askEffect(args));
|
|
123
|
+
|
|
124
|
+
export const askQuestionStream = (args: {
|
|
125
|
+
collection: Awaited<ReturnType<CollectionsServiceShape['load']>>;
|
|
126
|
+
question: string;
|
|
127
|
+
}): Effect.Effect<Awaited<ReturnType<AgentServiceShape['askStream']>>, unknown, AgentService> =>
|
|
128
|
+
Effect.flatMap(agentService, (agent) => agent.askStreamEffect(args));
|
|
129
|
+
|
|
130
|
+
export const updateModelConfig = (args: {
|
|
131
|
+
provider: string;
|
|
132
|
+
model: string;
|
|
133
|
+
providerOptions?: Parameters<ConfigServiceShape['updateModel']>[2];
|
|
134
|
+
}): Effect.Effect<Awaited<ReturnType<ConfigServiceShape['updateModel']>>, unknown, ConfigService> =>
|
|
135
|
+
Effect.flatMap(configService, (config) =>
|
|
136
|
+
config.updateModelEffect(args.provider, args.model, args.providerOptions)
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
export const addConfigResource = (
|
|
140
|
+
resource: ResourceDefinition
|
|
141
|
+
): Effect.Effect<ResourceDefinition, unknown, ConfigService> =>
|
|
142
|
+
Effect.flatMap(configService, (config) => config.addResourceEffect(resource));
|
|
143
|
+
|
|
144
|
+
export const removeConfigResource = (name: string): Effect.Effect<void, unknown, ConfigService> =>
|
|
145
|
+
Effect.flatMap(configService, (config) => config.removeResourceEffect(name));
|
|
146
|
+
|
|
147
|
+
export const clearConfigResources: Effect.Effect<
|
|
148
|
+
Awaited<ReturnType<ConfigServiceShape['clearResources']>>,
|
|
149
|
+
unknown,
|
|
150
|
+
ConfigService
|
|
151
|
+
> = Effect.flatMap(configService, (config) => config.clearResourcesEffect());
|
|
152
|
+
|
|
153
|
+
export const loadedResourceCollectionKey = (resourceNames: readonly string[]) =>
|
|
154
|
+
getCollectionKey(resourceNames);
|