@ottocode/server 0.1.257 → 0.1.258

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": "@ottocode/server",
3
- "version": "0.1.257",
3
+ "version": "0.1.258",
4
4
  "description": "HTTP API server for ottocode",
5
5
  "type": "module",
6
6
  "main": "./src/index.ts",
@@ -61,8 +61,8 @@
61
61
  "typecheck": "tsc --noEmit"
62
62
  },
63
63
  "dependencies": {
64
- "@ottocode/database": "0.1.257",
65
- "@ottocode/sdk": "0.1.257",
64
+ "@ottocode/database": "0.1.258",
65
+ "@ottocode/sdk": "0.1.258",
66
66
  "ai-sdk-ollama": "^3.8.3",
67
67
  "drizzle-orm": "^0.44.5",
68
68
  "hono": "^4.9.9",
@@ -6,14 +6,11 @@ import {
6
6
  getProviderSettings,
7
7
  type ProviderId,
8
8
  isProviderAuthorized,
9
- getGlobalAgentsDir,
10
9
  getAuth,
11
10
  } from '@ottocode/sdk';
12
- import { readdir } from 'node:fs/promises';
13
- import { join } from 'node:path';
14
11
  import type { EmbeddedAppConfig } from '../../index.ts';
15
12
  import type { OttoConfig } from '@ottocode/sdk';
16
- import { loadAgentsConfig } from '../../runtime/agent/registry.ts';
13
+ export { discoverAllAgents } from '../../runtime/agent/registry.ts';
17
14
 
18
15
  export type ProviderDetail = {
19
16
  id: string;
@@ -138,47 +135,3 @@ export async function getAuthTypeForProvider(
138
135
  const auth = await getAuth(provider, projectRoot);
139
136
  return auth?.type as 'api' | 'oauth' | 'wallet' | undefined;
140
137
  }
141
-
142
- export async function discoverAllAgents(
143
- projectRoot: string,
144
- ): Promise<string[]> {
145
- const builtInAgents = ['general', 'build', 'plan', 'init'];
146
- const agentSet = new Set<string>(builtInAgents);
147
-
148
- try {
149
- const agentsJson = await loadAgentsConfig(projectRoot);
150
- for (const agentName of Object.keys(agentsJson)) {
151
- if (agentName.trim()) {
152
- agentSet.add(agentName);
153
- }
154
- }
155
- } catch {}
156
-
157
- try {
158
- const localAgentsPath = join(projectRoot, '.otto', 'agents');
159
- const localFiles = await readdir(localAgentsPath).catch(() => []);
160
- for (const file of localFiles) {
161
- if (file.endsWith('.txt') || file.endsWith('.md')) {
162
- const agentName = file.replace(/\.(txt|md)$/, '');
163
- if (agentName.trim()) {
164
- agentSet.add(agentName);
165
- }
166
- }
167
- }
168
- } catch {}
169
-
170
- try {
171
- const globalAgentsPath = getGlobalAgentsDir();
172
- const globalFiles = await readdir(globalAgentsPath).catch(() => []);
173
- for (const file of globalFiles) {
174
- if (file.endsWith('.txt') || file.endsWith('.md')) {
175
- const agentName = file.replace(/\.(txt|md)$/, '');
176
- if (agentName.trim()) {
177
- agentSet.add(agentName);
178
- }
179
- }
180
- }
181
- } catch {}
182
-
183
- return Array.from(agentSet).sort();
184
- }
@@ -1,6 +1,8 @@
1
1
  import { getGlobalAgentsJsonPath, getGlobalAgentsDir } from '@ottocode/sdk';
2
2
  import type { ProviderName } from '@ottocode/sdk';
3
3
  import { catalog } from '@ottocode/sdk';
4
+ import { readdir } from 'node:fs/promises';
5
+ import { join } from 'node:path';
4
6
  // Embed default agent prompts; only user overrides read from disk.
5
7
  // eslint-disable-next-line @typescript-eslint/consistent-type-imports
6
8
  import AGENT_BUILD from '@ottocode/sdk/prompts/agents/build.txt' with {
@@ -40,6 +42,8 @@ export type AgentConfigEntry = {
40
42
 
41
43
  type AgentsJson = Record<string, AgentConfigEntry>;
42
44
 
45
+ const BUILTIN_AGENT_NAMES = ['build', 'plan', 'general', 'init', 'research'];
46
+
43
47
  function normalizeStringList(value: unknown): string[] {
44
48
  if (!Array.isArray(value)) return [];
45
49
  const seen = new Set<string>();
@@ -221,6 +225,49 @@ export async function loadAgentsConfig(
221
225
  return merged;
222
226
  }
223
227
 
228
+ export async function discoverAllAgents(
229
+ projectRoot: string,
230
+ ): Promise<string[]> {
231
+ const agentSet = new Set<string>(BUILTIN_AGENT_NAMES);
232
+
233
+ try {
234
+ const agentsJson = await loadAgentsConfig(projectRoot);
235
+ for (const agentName of Object.keys(agentsJson)) {
236
+ if (agentName.trim()) {
237
+ agentSet.add(agentName);
238
+ }
239
+ }
240
+ } catch {}
241
+
242
+ try {
243
+ const localAgentsPath = join(projectRoot, '.otto', 'agents');
244
+ const localFiles = await readdir(localAgentsPath).catch(() => []);
245
+ for (const file of localFiles) {
246
+ if (file.endsWith('.txt') || file.endsWith('.md')) {
247
+ const agentName = file.replace(/\.(txt|md)$/, '');
248
+ if (agentName.trim()) {
249
+ agentSet.add(agentName);
250
+ }
251
+ }
252
+ }
253
+ } catch {}
254
+
255
+ try {
256
+ const globalAgentsPath = getGlobalAgentsDir();
257
+ const globalFiles = await readdir(globalAgentsPath).catch(() => []);
258
+ for (const file of globalFiles) {
259
+ if (file.endsWith('.txt') || file.endsWith('.md')) {
260
+ const agentName = file.replace(/\.(txt|md)$/, '');
261
+ if (agentName.trim()) {
262
+ agentSet.add(agentName);
263
+ }
264
+ }
265
+ }
266
+ } catch {}
267
+
268
+ return Array.from(agentSet).sort();
269
+ }
270
+
224
271
  export async function resolveAgentConfig(
225
272
  projectRoot: string,
226
273
  name: string,
@@ -1,5 +1,6 @@
1
1
  // Barrel export for backwards compatibility with @ottocode/server/runtime/agent-registry
2
2
  export {
3
+ discoverAllAgents,
3
4
  resolveAgentConfig,
4
5
  defaultToolsForAgent,
5
6
  type AgentConfigEntry,
@@ -73,6 +73,7 @@ export type AskServerRequest = {
73
73
  credentials?: InjectableCredentials;
74
74
  agentPrompt?: string;
75
75
  tools?: string[];
76
+ images?: Array<{ data: string; mediaType: string }>;
76
77
  };
77
78
 
78
79
  export type AskServerResponse = {
@@ -305,7 +306,9 @@ async function processAskRequest(
305
306
  } as SessionRow;
306
307
  }
307
308
 
308
- validateProviderModel(providerForMessage, modelForMessage, cfg);
309
+ validateProviderModel(providerForMessage, modelForMessage, cfg, {
310
+ wantsVision: Boolean(request.images?.length),
311
+ });
309
312
 
310
313
  if (!request.skipFileConfig && !request.config && !request.credentials) {
311
314
  await ensureProviderEnv(cfg, providerForMessage);
@@ -327,6 +330,7 @@ async function processAskRequest(
327
330
  oneShot: !request.sessionId && !request.last,
328
331
  reasoningText,
329
332
  reasoningLevel,
333
+ images: request.images,
330
334
  });
331
335
 
332
336
  const headerAgent = session.agent ?? agentName;