btca-server 1.0.932 → 1.0.950

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "btca-server",
3
- "version": "1.0.932",
3
+ "version": "1.0.950",
4
4
  "description": "BTCA server for answering questions about your codebase using OpenCode AI",
5
5
  "author": "Ben Davis",
6
6
  "license": "MIT",
@@ -149,6 +149,7 @@ export namespace Agent {
149
149
  const stream = AgentLoop.stream({
150
150
  providerId: config.provider,
151
151
  modelId: config.model,
152
+ maxSteps: config.maxSteps,
152
153
  collectionPath: collection.path,
153
154
  vfsId: collection.vfsId,
154
155
  agentInstructions: collection.agentInstructions,
@@ -207,6 +208,7 @@ export namespace Agent {
207
208
  AgentLoop.run({
208
209
  providerId: config.provider,
209
210
  modelId: config.model,
211
+ maxSteps: config.maxSteps,
210
212
  collectionPath: collection.path,
211
213
  vfsId: collection.vfsId,
212
214
  agentInstructions: collection.agentInstructions,
@@ -3,7 +3,13 @@ import { promises as fs } from 'node:fs';
3
3
  import path from 'node:path';
4
4
  import os from 'node:os';
5
5
 
6
- import { Config, DEFAULT_MODEL, DEFAULT_PROVIDER, DEFAULT_RESOURCES } from './index.ts';
6
+ import {
7
+ Config,
8
+ DEFAULT_MAX_STEPS,
9
+ DEFAULT_MODEL,
10
+ DEFAULT_PROVIDER,
11
+ DEFAULT_RESOURCES
12
+ } from './index.ts';
7
13
 
8
14
  describe('Config', () => {
9
15
  let testDir: string;
@@ -32,6 +38,7 @@ describe('Config', () => {
32
38
 
33
39
  expect(config.provider).toBe(DEFAULT_PROVIDER);
34
40
  expect(config.model).toBe(DEFAULT_MODEL);
41
+ expect(config.maxSteps).toBe(DEFAULT_MAX_STEPS);
35
42
  expect(config.resources.length).toBe(DEFAULT_RESOURCES.length);
36
43
  expect(config.getResource('svelte')).toBeDefined();
37
44
  });
@@ -121,6 +128,30 @@ describe('Config', () => {
121
128
  expect(config.model).toBe('commented-model');
122
129
  });
123
130
 
131
+ it('loads maxSteps when provided in config', async () => {
132
+ const projectConfig = {
133
+ $schema: 'https://btca.dev/btca.schema.json',
134
+ provider: 'test-provider',
135
+ model: 'test-model',
136
+ maxSteps: 80,
137
+ resources: [
138
+ {
139
+ name: 'test-resource',
140
+ type: 'git',
141
+ url: 'https://github.com/test/repo',
142
+ branch: 'main'
143
+ }
144
+ ]
145
+ };
146
+
147
+ await fs.writeFile(path.join(testDir, 'btca.config.jsonc'), JSON.stringify(projectConfig));
148
+ process.chdir(testDir);
149
+
150
+ const config = await Config.load();
151
+
152
+ expect(config.maxSteps).toBe(80);
153
+ });
154
+
124
155
  it('getResource returns undefined for unknown resource', async () => {
125
156
  process.chdir(testDir);
126
157
 
@@ -148,6 +179,28 @@ describe('Config', () => {
148
179
  expect(Config.load()).rejects.toThrow('Invalid config');
149
180
  });
150
181
 
182
+ it('throws ConfigError for invalid maxSteps', async () => {
183
+ const invalidConfig = {
184
+ $schema: 'https://btca.dev/btca.schema.json',
185
+ provider: 'test-provider',
186
+ model: 'test-model',
187
+ maxSteps: 0,
188
+ resources: [
189
+ {
190
+ name: 'test-resource',
191
+ type: 'git',
192
+ url: 'https://github.com/test/repo',
193
+ branch: 'main'
194
+ }
195
+ ]
196
+ };
197
+
198
+ await fs.writeFile(path.join(testDir, 'btca.config.jsonc'), JSON.stringify(invalidConfig));
199
+ process.chdir(testDir);
200
+
201
+ expect(Config.load()).rejects.toThrow('Invalid config');
202
+ });
203
+
151
204
  it('merges project config with global config (project takes priority)', async () => {
152
205
  // Create global config with some resources
153
206
  const globalConfigDir = path.join(testDir, '.config', 'btca');
@@ -19,6 +19,7 @@ export const CONFIG_SCHEMA_URL = 'https://btca.dev/btca.schema.json';
19
19
  export const DEFAULT_MODEL = 'claude-haiku-4-5';
20
20
  export const DEFAULT_PROVIDER = 'opencode';
21
21
  export const DEFAULT_PROVIDER_TIMEOUT_MS = 300_000;
22
+ export const DEFAULT_MAX_STEPS = 40;
22
23
 
23
24
  export const DEFAULT_RESOURCES: ResourceDefinition[] = [
24
25
  {
@@ -61,6 +62,7 @@ const StoredConfigSchema = z.object({
61
62
  $schema: z.string().optional(),
62
63
  dataDirectory: z.string().optional(),
63
64
  providerTimeoutMs: z.number().int().positive().optional(),
65
+ maxSteps: z.number().int().positive().optional(),
64
66
  resources: z.array(ResourceDefinitionSchema),
65
67
  // Provider and model are optional - defaults are applied when loading
66
68
  model: z.string().optional(),
@@ -131,6 +133,7 @@ export namespace Config {
131
133
  model: string;
132
134
  provider: string;
133
135
  providerTimeoutMs?: number;
136
+ maxSteps: number;
134
137
  configPath: string;
135
138
  getProviderOptions: (providerId: string) => ProviderOptionsConfig | undefined;
136
139
  getResource: (name: string) => ResourceDefinition | undefined;
@@ -507,7 +510,8 @@ export namespace Config {
507
510
  resources: DEFAULT_RESOURCES,
508
511
  model: DEFAULT_MODEL,
509
512
  provider: DEFAULT_PROVIDER,
510
- providerTimeoutMs: DEFAULT_PROVIDER_TIMEOUT_MS
513
+ providerTimeoutMs: DEFAULT_PROVIDER_TIMEOUT_MS,
514
+ maxSteps: DEFAULT_MAX_STEPS
511
515
  };
512
516
 
513
517
  const result = await Result.gen(async function* () {
@@ -640,6 +644,9 @@ export namespace Config {
640
644
  get providerTimeoutMs() {
641
645
  return getActiveConfig().providerTimeoutMs;
642
646
  },
647
+ get maxSteps() {
648
+ return getActiveConfig().maxSteps ?? DEFAULT_MAX_STEPS;
649
+ },
643
650
  getProviderOptions: (providerId: string) => getMergedProviderOptions()[providerId],
644
651
  getResource: (name: string) => getMergedResources().find((r) => r.name === name),
645
652
 
package/src/index.ts CHANGED
@@ -283,6 +283,7 @@ const createApp = (deps: {
283
283
  provider: config.provider,
284
284
  model: config.model,
285
285
  providerTimeoutMs: config.providerTimeoutMs ?? null,
286
+ maxSteps: config.maxSteps,
286
287
  resourcesDirectory: config.resourcesDirectory,
287
288
  resourceCount: config.resources.length
288
289
  });
@@ -534,6 +535,7 @@ export const startServer = async (options: StartServerOptions = {}): Promise<Ser
534
535
  Metrics.info('config.ready', {
535
536
  provider: config.provider,
536
537
  model: config.model,
538
+ maxSteps: config.maxSteps,
537
539
  resources: config.resources.map((r) => r.name),
538
540
  resourcesDirectory: config.resourcesDirectory
539
541
  });