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/agent/service.ts
CHANGED
|
@@ -2,210 +2,172 @@
|
|
|
2
2
|
* Agent Service
|
|
3
3
|
* Refactored to use custom AI SDK loop instead of spawning OpenCode instances
|
|
4
4
|
*/
|
|
5
|
-
import {
|
|
5
|
+
import { Effect } from 'effect';
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import type { ConfigService as ConfigServiceShape } from '../config/index.ts';
|
|
8
8
|
import { getErrorHint, getErrorMessage, type TaggedErrorOptions } from '../errors.ts';
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
9
|
+
import { metricsError, metricsErrorInfo, metricsInfo } from '../metrics/index.ts';
|
|
10
|
+
import {
|
|
11
|
+
getAuthenticatedProviders,
|
|
12
|
+
getProviderAuthHint,
|
|
13
|
+
getSupportedProviders,
|
|
14
|
+
isAuthenticated
|
|
15
|
+
} from '../providers/index.ts';
|
|
11
16
|
import type { CollectionResult } from '../collections/types.ts';
|
|
12
17
|
import { clearVirtualCollectionMetadata } from '../collections/virtual-metadata.ts';
|
|
13
|
-
import {
|
|
18
|
+
import { disposeVirtualFs } from '../vfs/virtual-fs.ts';
|
|
14
19
|
import type { AgentResult } from './types.ts';
|
|
15
|
-
import {
|
|
20
|
+
import { runAgentLoop, streamAgentLoop, type AgentEvent } from './loop.ts';
|
|
16
21
|
|
|
17
|
-
export
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
22
|
+
export class AgentError extends Error {
|
|
23
|
+
readonly _tag = 'AgentError';
|
|
24
|
+
override readonly cause?: unknown;
|
|
25
|
+
readonly hint?: string;
|
|
21
26
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
constructor(args: TaggedErrorOptions) {
|
|
28
|
-
super(args.message);
|
|
29
|
-
this.cause = args.cause;
|
|
30
|
-
this.hint = args.hint;
|
|
31
|
-
}
|
|
27
|
+
constructor(args: TaggedErrorOptions) {
|
|
28
|
+
super(args.message);
|
|
29
|
+
this.cause = args.cause;
|
|
30
|
+
this.hint = args.hint;
|
|
32
31
|
}
|
|
32
|
+
}
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
}
|
|
34
|
+
export class InvalidProviderError extends Error {
|
|
35
|
+
readonly _tag = 'InvalidProviderError';
|
|
36
|
+
readonly providerId: string;
|
|
37
|
+
readonly availableProviders: string[];
|
|
38
|
+
readonly hint: string;
|
|
39
|
+
|
|
40
|
+
constructor(args: { providerId: string; availableProviders: string[] }) {
|
|
41
|
+
super(`Invalid provider: "${args.providerId}"`);
|
|
42
|
+
this.providerId = args.providerId;
|
|
43
|
+
this.availableProviders = args.availableProviders;
|
|
44
|
+
this.hint = `Available providers: ${args.availableProviders.join(
|
|
45
|
+
', '
|
|
46
|
+
)}. Update your config with a valid provider. Open an issue to request this provider: https://github.com/davis7dotsh/better-context/issues.`;
|
|
48
47
|
}
|
|
48
|
+
}
|
|
49
49
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
}
|
|
50
|
+
export class InvalidModelError extends Error {
|
|
51
|
+
readonly _tag = 'InvalidModelError';
|
|
52
|
+
readonly providerId: string;
|
|
53
|
+
readonly modelId: string;
|
|
54
|
+
readonly availableModels: string[];
|
|
55
|
+
readonly hint: string;
|
|
56
|
+
|
|
57
|
+
constructor(args: { providerId: string; modelId: string; availableModels: string[] }) {
|
|
58
|
+
super(`Invalid model "${args.modelId}" for provider "${args.providerId}"`);
|
|
59
|
+
this.providerId = args.providerId;
|
|
60
|
+
this.modelId = args.modelId;
|
|
61
|
+
this.availableModels = args.availableModels;
|
|
62
|
+
const modelList =
|
|
63
|
+
args.availableModels.length <= 5
|
|
64
|
+
? args.availableModels.join(', ')
|
|
65
|
+
: `${args.availableModels.slice(0, 5).join(', ')}... (${args.availableModels.length} total)`;
|
|
66
|
+
this.hint = `Available models for ${args.providerId}: ${modelList}. Update your config with a valid model.`;
|
|
68
67
|
}
|
|
68
|
+
}
|
|
69
69
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
}
|
|
70
|
+
export class ProviderNotConnectedError extends Error {
|
|
71
|
+
readonly _tag = 'ProviderNotConnectedError';
|
|
72
|
+
readonly providerId: string;
|
|
73
|
+
readonly connectedProviders: string[];
|
|
74
|
+
readonly hint: string;
|
|
75
|
+
|
|
76
|
+
constructor(args: { providerId: string; connectedProviders: string[] }) {
|
|
77
|
+
super(`Provider "${args.providerId}" is not connected`);
|
|
78
|
+
this.providerId = args.providerId;
|
|
79
|
+
this.connectedProviders = args.connectedProviders;
|
|
80
|
+
const baseHint = getProviderAuthHint(args.providerId);
|
|
81
|
+
if (args.connectedProviders.length > 0) {
|
|
82
|
+
this.hint = `${baseHint} Connected providers: ${args.connectedProviders.join(', ')}.`;
|
|
83
|
+
} else {
|
|
84
|
+
this.hint = `${baseHint} No providers are currently connected.`;
|
|
86
85
|
}
|
|
87
86
|
}
|
|
87
|
+
}
|
|
88
88
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
89
|
+
export type AgentService = {
|
|
90
|
+
askStream: (args: { collection: CollectionResult; question: string }) => Promise<{
|
|
91
|
+
stream: AsyncIterable<AgentEvent>;
|
|
92
|
+
model: { provider: string; model: string };
|
|
93
|
+
}>;
|
|
94
|
+
askStreamEffect: (args: { collection: CollectionResult; question: string }) => Effect.Effect<
|
|
95
|
+
{
|
|
96
|
+
stream: AsyncIterable<AgentEvent>;
|
|
96
97
|
model: { provider: string; model: string };
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
98
|
+
},
|
|
99
|
+
unknown
|
|
100
|
+
>;
|
|
101
|
+
|
|
102
|
+
ask: (args: { collection: CollectionResult; question: string }) => Promise<AgentResult>;
|
|
103
|
+
askEffect: (args: {
|
|
104
|
+
collection: CollectionResult;
|
|
105
|
+
question: string;
|
|
106
|
+
}) => Effect.Effect<AgentResult, unknown>;
|
|
107
|
+
|
|
108
|
+
listProviders: () => Promise<{
|
|
109
|
+
all: { id: string; models: Record<string, unknown> }[];
|
|
110
|
+
connected: string[];
|
|
111
|
+
}>;
|
|
112
|
+
listProvidersEffect: () => Effect.Effect<
|
|
113
|
+
{
|
|
102
114
|
all: { id: string; models: Record<string, unknown> }[];
|
|
103
115
|
connected: string[];
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
provider: config.provider,
|
|
118
|
-
model: config.model,
|
|
119
|
-
questionLength: question.length
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
const cleanup = async () => {
|
|
123
|
-
if (collection.vfsId) {
|
|
124
|
-
VirtualFs.dispose(collection.vfsId);
|
|
125
|
-
clearVirtualCollectionMetadata(collection.vfsId);
|
|
126
|
-
}
|
|
127
|
-
try {
|
|
128
|
-
await collection.cleanup?.();
|
|
129
|
-
} catch {
|
|
130
|
-
// cleanup should never fail user-visible operations
|
|
131
|
-
}
|
|
132
|
-
};
|
|
133
|
-
|
|
134
|
-
// Validate provider is authenticated
|
|
135
|
-
const isAuthed = await Auth.isAuthenticated(config.provider);
|
|
136
|
-
const requiresAuth = config.provider !== 'opencode' && config.provider !== 'openai-compat';
|
|
137
|
-
if (!isAuthed && requiresAuth) {
|
|
138
|
-
const authenticated = await Auth.getAuthenticatedProviders();
|
|
139
|
-
await cleanup();
|
|
140
|
-
throw new ProviderNotConnectedError({
|
|
141
|
-
providerId: config.provider,
|
|
142
|
-
connectedProviders: authenticated
|
|
143
|
-
});
|
|
116
|
+
},
|
|
117
|
+
unknown
|
|
118
|
+
>;
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
export type Service = AgentService;
|
|
122
|
+
|
|
123
|
+
export const createAgentService = (config: ConfigServiceShape): AgentService => {
|
|
124
|
+
const cleanupCollection = (collection: CollectionResult) =>
|
|
125
|
+
Effect.promise(async () => {
|
|
126
|
+
if (collection.vfsId) {
|
|
127
|
+
disposeVirtualFs(collection.vfsId);
|
|
128
|
+
clearVirtualCollectionMetadata(collection.vfsId);
|
|
144
129
|
}
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
const stream = AgentLoop.stream({
|
|
150
|
-
providerId: config.provider,
|
|
151
|
-
modelId: config.model,
|
|
152
|
-
maxSteps: config.maxSteps,
|
|
153
|
-
collectionPath: collection.path,
|
|
154
|
-
vfsId: collection.vfsId,
|
|
155
|
-
agentInstructions: collection.agentInstructions,
|
|
156
|
-
question,
|
|
157
|
-
providerOptions: config.getProviderOptions(config.provider)
|
|
158
|
-
});
|
|
159
|
-
for await (const event of stream) {
|
|
160
|
-
yield event;
|
|
161
|
-
}
|
|
162
|
-
} finally {
|
|
163
|
-
await cleanup();
|
|
164
|
-
}
|
|
165
|
-
})();
|
|
166
|
-
|
|
167
|
-
return {
|
|
168
|
-
stream: eventGenerator,
|
|
169
|
-
model: { provider: config.provider, model: config.model }
|
|
170
|
-
};
|
|
171
|
-
};
|
|
172
|
-
|
|
173
|
-
/**
|
|
174
|
-
* Ask a question and return the complete response
|
|
175
|
-
*/
|
|
176
|
-
const ask: Service['ask'] = async ({ collection, question }) => {
|
|
177
|
-
Metrics.info('agent.ask.start', {
|
|
178
|
-
provider: config.provider,
|
|
179
|
-
model: config.model,
|
|
180
|
-
questionLength: question.length
|
|
181
|
-
});
|
|
182
|
-
|
|
183
|
-
const cleanup = async () => {
|
|
184
|
-
if (collection.vfsId) {
|
|
185
|
-
VirtualFs.dispose(collection.vfsId);
|
|
186
|
-
clearVirtualCollectionMetadata(collection.vfsId);
|
|
187
|
-
}
|
|
188
|
-
try {
|
|
189
|
-
await collection.cleanup?.();
|
|
190
|
-
} catch {
|
|
191
|
-
// cleanup should never fail user-visible operations
|
|
192
|
-
}
|
|
193
|
-
};
|
|
194
|
-
|
|
195
|
-
// Validate provider is authenticated
|
|
196
|
-
const isAuthed = await Auth.isAuthenticated(config.provider);
|
|
197
|
-
const requiresAuth = config.provider !== 'opencode' && config.provider !== 'openai-compat';
|
|
198
|
-
if (!isAuthed && requiresAuth) {
|
|
199
|
-
const authenticated = await Auth.getAuthenticatedProviders();
|
|
200
|
-
await cleanup();
|
|
201
|
-
throw new ProviderNotConnectedError({
|
|
202
|
-
providerId: config.provider,
|
|
203
|
-
connectedProviders: authenticated
|
|
204
|
-
});
|
|
130
|
+
try {
|
|
131
|
+
await collection.cleanup?.();
|
|
132
|
+
} catch {
|
|
133
|
+
return;
|
|
205
134
|
}
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
const ensureProviderConnected = Effect.fn(function* () {
|
|
138
|
+
const isAuthed = yield* Effect.tryPromise(() => isAuthenticated(config.provider));
|
|
139
|
+
const requiresAuth = config.provider !== 'opencode' && config.provider !== 'openai-compat';
|
|
140
|
+
if (isAuthed || !requiresAuth) return;
|
|
141
|
+
const authenticated = yield* Effect.tryPromise(() => getAuthenticatedProviders());
|
|
142
|
+
yield* Effect.fail(
|
|
143
|
+
new ProviderNotConnectedError({
|
|
144
|
+
providerId: config.provider,
|
|
145
|
+
connectedProviders: authenticated
|
|
146
|
+
})
|
|
147
|
+
);
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Ask a question and stream the response using the new AI SDK loop
|
|
152
|
+
*/
|
|
153
|
+
const askStream: AgentService['askStream'] = async ({ collection, question }) => {
|
|
154
|
+
metricsInfo('agent.ask.start', {
|
|
155
|
+
provider: config.provider,
|
|
156
|
+
model: config.model,
|
|
157
|
+
questionLength: question.length
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
try {
|
|
161
|
+
await Effect.runPromise(ensureProviderConnected());
|
|
162
|
+
} catch (error) {
|
|
163
|
+
await Effect.runPromise(cleanupCollection(collection));
|
|
164
|
+
throw error;
|
|
165
|
+
}
|
|
206
166
|
|
|
207
|
-
|
|
208
|
-
|
|
167
|
+
// Create a generator that wraps the AgentLoop stream
|
|
168
|
+
const eventGenerator = (async function* () {
|
|
169
|
+
try {
|
|
170
|
+
const stream = streamAgentLoop({
|
|
209
171
|
providerId: config.provider,
|
|
210
172
|
modelId: config.model,
|
|
211
173
|
maxSteps: config.maxSteps,
|
|
@@ -214,64 +176,121 @@ export namespace Agent {
|
|
|
214
176
|
agentInstructions: collection.agentInstructions,
|
|
215
177
|
question,
|
|
216
178
|
providerOptions: config.getProviderOptions(config.provider)
|
|
217
|
-
})
|
|
218
|
-
);
|
|
219
|
-
|
|
220
|
-
await cleanup();
|
|
221
|
-
|
|
222
|
-
if (!Result.isOk(runResult)) {
|
|
223
|
-
const cause = runResult.error;
|
|
224
|
-
Metrics.error('agent.ask.error', { error: Metrics.errorInfo(cause) });
|
|
225
|
-
throw new AgentError({
|
|
226
|
-
message: getErrorMessage(cause),
|
|
227
|
-
hint:
|
|
228
|
-
getErrorHint(cause) ?? 'This may be a temporary issue. Try running the command again.',
|
|
229
|
-
cause
|
|
230
179
|
});
|
|
180
|
+
for await (const event of stream) {
|
|
181
|
+
yield event;
|
|
182
|
+
}
|
|
183
|
+
} finally {
|
|
184
|
+
await Effect.runPromise(cleanupCollection(collection));
|
|
231
185
|
}
|
|
186
|
+
})();
|
|
232
187
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
model: config.model,
|
|
237
|
-
answerLength: result.answer.length,
|
|
238
|
-
eventCount: result.events.length
|
|
239
|
-
});
|
|
240
|
-
|
|
241
|
-
return {
|
|
242
|
-
answer: result.answer,
|
|
243
|
-
model: result.model,
|
|
244
|
-
events: result.events
|
|
245
|
-
};
|
|
188
|
+
return {
|
|
189
|
+
stream: eventGenerator,
|
|
190
|
+
model: { provider: config.provider, model: config.model }
|
|
246
191
|
};
|
|
192
|
+
};
|
|
247
193
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
194
|
+
/**
|
|
195
|
+
* Ask a question and return the complete response
|
|
196
|
+
*/
|
|
197
|
+
const ask: AgentService['ask'] = async ({ collection, question }) => {
|
|
198
|
+
return Effect.runPromise(
|
|
199
|
+
Effect.gen(function* () {
|
|
200
|
+
metricsInfo('agent.ask.start', {
|
|
201
|
+
provider: config.provider,
|
|
202
|
+
model: config.model,
|
|
203
|
+
questionLength: question.length
|
|
204
|
+
});
|
|
254
205
|
|
|
255
|
-
|
|
256
|
-
|
|
206
|
+
yield* ensureProviderConnected();
|
|
207
|
+
|
|
208
|
+
const result = yield* Effect.tryPromise({
|
|
209
|
+
try: () =>
|
|
210
|
+
runAgentLoop({
|
|
211
|
+
providerId: config.provider,
|
|
212
|
+
modelId: config.model,
|
|
213
|
+
maxSteps: config.maxSteps,
|
|
214
|
+
collectionPath: collection.path,
|
|
215
|
+
vfsId: collection.vfsId,
|
|
216
|
+
agentInstructions: collection.agentInstructions,
|
|
217
|
+
question,
|
|
218
|
+
providerOptions: config.getProviderOptions(config.provider)
|
|
219
|
+
}),
|
|
220
|
+
catch: (cause) =>
|
|
221
|
+
new AgentError({
|
|
222
|
+
message: getErrorMessage(cause),
|
|
223
|
+
hint:
|
|
224
|
+
getErrorHint(cause) ??
|
|
225
|
+
'This may be a temporary issue. Try running the command again.',
|
|
226
|
+
cause
|
|
227
|
+
})
|
|
228
|
+
});
|
|
257
229
|
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
230
|
+
metricsInfo('agent.ask.complete', {
|
|
231
|
+
provider: config.provider,
|
|
232
|
+
model: config.model,
|
|
233
|
+
answerLength: result.answer.length,
|
|
234
|
+
eventCount: result.events.length
|
|
235
|
+
});
|
|
264
236
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
237
|
+
return {
|
|
238
|
+
answer: result.answer,
|
|
239
|
+
model: result.model,
|
|
240
|
+
events: result.events
|
|
241
|
+
};
|
|
242
|
+
}).pipe(
|
|
243
|
+
Effect.tapError((error) =>
|
|
244
|
+
Effect.sync(() => metricsError('agent.ask.error', { error: metricsErrorInfo(error) }))
|
|
245
|
+
),
|
|
246
|
+
Effect.ensuring(cleanupCollection(collection))
|
|
247
|
+
)
|
|
248
|
+
);
|
|
249
|
+
};
|
|
270
250
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
251
|
+
/**
|
|
252
|
+
* List available providers using local auth data
|
|
253
|
+
*/
|
|
254
|
+
const listProviders: AgentService['listProviders'] = async () => {
|
|
255
|
+
return Effect.runPromise(
|
|
256
|
+
Effect.gen(function* () {
|
|
257
|
+
const supportedProviders = getSupportedProviders();
|
|
258
|
+
const authenticatedProviders = yield* Effect.tryPromise(() => getAuthenticatedProviders());
|
|
259
|
+
const all = supportedProviders.map((id) => ({
|
|
260
|
+
id,
|
|
261
|
+
models: {} as Record<string, unknown>
|
|
262
|
+
}));
|
|
263
|
+
|
|
264
|
+
return {
|
|
265
|
+
all,
|
|
266
|
+
connected: authenticatedProviders
|
|
267
|
+
};
|
|
268
|
+
})
|
|
269
|
+
);
|
|
276
270
|
};
|
|
277
|
-
|
|
271
|
+
|
|
272
|
+
const askStreamEffect: AgentService['askStreamEffect'] = (args) =>
|
|
273
|
+
Effect.tryPromise({
|
|
274
|
+
try: () => askStream(args),
|
|
275
|
+
catch: (cause) => cause
|
|
276
|
+
});
|
|
277
|
+
const askEffect: AgentService['askEffect'] = (args) =>
|
|
278
|
+
Effect.tryPromise({
|
|
279
|
+
try: () => ask(args),
|
|
280
|
+
catch: (cause) => cause
|
|
281
|
+
});
|
|
282
|
+
const listProvidersEffect: AgentService['listProvidersEffect'] = () =>
|
|
283
|
+
Effect.tryPromise({
|
|
284
|
+
try: () => listProviders(),
|
|
285
|
+
catch: (cause) => cause
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
return {
|
|
289
|
+
askStream,
|
|
290
|
+
ask,
|
|
291
|
+
listProviders,
|
|
292
|
+
askStreamEffect,
|
|
293
|
+
askEffect,
|
|
294
|
+
listProvidersEffect
|
|
295
|
+
};
|
|
296
|
+
};
|
package/src/agent/types.ts
CHANGED
package/src/collections/index.ts
CHANGED