@ottocode/server 0.1.234 → 0.1.236
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/openapi/paths/config.ts +94 -0
- package/src/routes/config/debug.ts +39 -0
- package/src/routes/config/index.ts +2 -0
- package/src/routes/config/utils.ts +3 -16
- package/src/routes/git/commit.ts +0 -3
- package/src/routes/terminals.ts +0 -21
- package/src/routes/tunnel.ts +0 -5
- package/src/runtime/agent/mcp-prepare-step.ts +1 -7
- package/src/runtime/agent/registry.ts +1 -8
- package/src/runtime/agent/runner-setup.ts +73 -49
- package/src/runtime/agent/runner.ts +20 -194
- package/src/runtime/debug/index.ts +3 -91
- package/src/runtime/debug/state.ts +5 -61
- package/src/runtime/debug/turn-dump.ts +0 -4
- package/src/runtime/message/compaction-auto.ts +1 -21
- package/src/runtime/message/compaction-mark.ts +75 -27
- package/src/runtime/message/compaction-prune.ts +0 -3
- package/src/runtime/message/history-builder.ts +2 -23
- package/src/runtime/message/service.ts +22 -64
- package/src/runtime/message/tool-history-tracker.ts +0 -3
- package/src/runtime/prompt/builder.ts +0 -2
- package/src/runtime/provider/oauth-adapter.ts +5 -5
- package/src/runtime/stream/error-handler.ts +1 -31
- package/src/runtime/stream/finish-handler.ts +3 -20
- package/src/runtime/stream/step-finish.ts +5 -26
- package/src/runtime/tools/approval.ts +0 -18
- package/src/runtime/utils/token.ts +1 -10
- package/src/tools/adapter.ts +23 -22
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ottocode/server",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.236",
|
|
4
4
|
"description": "HTTP API server for ottocode",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.ts",
|
|
@@ -49,8 +49,8 @@
|
|
|
49
49
|
"typecheck": "tsc --noEmit"
|
|
50
50
|
},
|
|
51
51
|
"dependencies": {
|
|
52
|
-
"@ottocode/sdk": "0.1.
|
|
53
|
-
"@ottocode/database": "0.1.
|
|
52
|
+
"@ottocode/sdk": "0.1.236",
|
|
53
|
+
"@ottocode/database": "0.1.236",
|
|
54
54
|
"drizzle-orm": "^0.44.5",
|
|
55
55
|
"hono": "^4.9.9",
|
|
56
56
|
"zod": "^4.3.6"
|
|
@@ -234,6 +234,100 @@ export const configPaths = {
|
|
|
234
234
|
},
|
|
235
235
|
},
|
|
236
236
|
},
|
|
237
|
+
'/v1/config/debug': {
|
|
238
|
+
get: {
|
|
239
|
+
tags: ['config'],
|
|
240
|
+
operationId: 'getDebugConfig',
|
|
241
|
+
summary: 'Get debug configuration',
|
|
242
|
+
responses: {
|
|
243
|
+
200: {
|
|
244
|
+
description: 'OK',
|
|
245
|
+
content: {
|
|
246
|
+
'application/json': {
|
|
247
|
+
schema: {
|
|
248
|
+
type: 'object',
|
|
249
|
+
properties: {
|
|
250
|
+
enabled: { type: 'boolean' },
|
|
251
|
+
scopes: {
|
|
252
|
+
type: 'array',
|
|
253
|
+
items: { type: 'string' },
|
|
254
|
+
},
|
|
255
|
+
logPath: { type: 'string' },
|
|
256
|
+
sessionsDir: { type: 'string' },
|
|
257
|
+
debugDir: { type: 'string' },
|
|
258
|
+
},
|
|
259
|
+
required: [
|
|
260
|
+
'enabled',
|
|
261
|
+
'scopes',
|
|
262
|
+
'logPath',
|
|
263
|
+
'sessionsDir',
|
|
264
|
+
'debugDir',
|
|
265
|
+
],
|
|
266
|
+
},
|
|
267
|
+
},
|
|
268
|
+
},
|
|
269
|
+
},
|
|
270
|
+
},
|
|
271
|
+
},
|
|
272
|
+
patch: {
|
|
273
|
+
tags: ['config'],
|
|
274
|
+
operationId: 'updateDebugConfig',
|
|
275
|
+
summary: 'Update debug configuration',
|
|
276
|
+
requestBody: {
|
|
277
|
+
required: true,
|
|
278
|
+
content: {
|
|
279
|
+
'application/json': {
|
|
280
|
+
schema: {
|
|
281
|
+
type: 'object',
|
|
282
|
+
properties: {
|
|
283
|
+
enabled: { type: 'boolean' },
|
|
284
|
+
scopes: {
|
|
285
|
+
type: 'array',
|
|
286
|
+
items: { type: 'string' },
|
|
287
|
+
},
|
|
288
|
+
},
|
|
289
|
+
},
|
|
290
|
+
},
|
|
291
|
+
},
|
|
292
|
+
},
|
|
293
|
+
responses: {
|
|
294
|
+
200: {
|
|
295
|
+
description: 'OK',
|
|
296
|
+
content: {
|
|
297
|
+
'application/json': {
|
|
298
|
+
schema: {
|
|
299
|
+
type: 'object',
|
|
300
|
+
properties: {
|
|
301
|
+
success: { type: 'boolean' },
|
|
302
|
+
debug: {
|
|
303
|
+
type: 'object',
|
|
304
|
+
properties: {
|
|
305
|
+
enabled: { type: 'boolean' },
|
|
306
|
+
scopes: {
|
|
307
|
+
type: 'array',
|
|
308
|
+
items: { type: 'string' },
|
|
309
|
+
},
|
|
310
|
+
logPath: { type: 'string' },
|
|
311
|
+
sessionsDir: { type: 'string' },
|
|
312
|
+
debugDir: { type: 'string' },
|
|
313
|
+
},
|
|
314
|
+
required: [
|
|
315
|
+
'enabled',
|
|
316
|
+
'scopes',
|
|
317
|
+
'logPath',
|
|
318
|
+
'sessionsDir',
|
|
319
|
+
'debugDir',
|
|
320
|
+
],
|
|
321
|
+
},
|
|
322
|
+
},
|
|
323
|
+
required: ['success', 'debug'],
|
|
324
|
+
},
|
|
325
|
+
},
|
|
326
|
+
},
|
|
327
|
+
},
|
|
328
|
+
},
|
|
329
|
+
},
|
|
330
|
+
},
|
|
237
331
|
'/v1/config/models': {
|
|
238
332
|
get: {
|
|
239
333
|
tags: ['config'],
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { Hono } from 'hono';
|
|
2
|
+
import { logger, readDebugConfig, writeDebugConfig } from '@ottocode/sdk';
|
|
3
|
+
import { serializeError } from '../../runtime/errors/api-error.ts';
|
|
4
|
+
|
|
5
|
+
export function registerDebugConfigRoute(app: Hono) {
|
|
6
|
+
app.get('/v1/config/debug', async (c) => {
|
|
7
|
+
try {
|
|
8
|
+
const debug = await readDebugConfig();
|
|
9
|
+
return c.json(debug);
|
|
10
|
+
} catch (error) {
|
|
11
|
+
logger.error('Failed to load debug config', error);
|
|
12
|
+
const errorResponse = serializeError(error);
|
|
13
|
+
return c.json(errorResponse, errorResponse.error.status || 500);
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
app.patch('/v1/config/debug', async (c) => {
|
|
18
|
+
try {
|
|
19
|
+
const body = await c.req.json<{
|
|
20
|
+
enabled?: boolean;
|
|
21
|
+
scopes?: string[];
|
|
22
|
+
}>();
|
|
23
|
+
|
|
24
|
+
await writeDebugConfig({
|
|
25
|
+
enabled: body.enabled,
|
|
26
|
+
scopes: Array.isArray(body.scopes)
|
|
27
|
+
? body.scopes.map((scope) => scope.trim()).filter(Boolean)
|
|
28
|
+
: body.scopes,
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
const debug = await readDebugConfig();
|
|
32
|
+
return c.json({ success: true, debug });
|
|
33
|
+
} catch (error) {
|
|
34
|
+
logger.error('Failed to update debug config', error);
|
|
35
|
+
const errorResponse = serializeError(error);
|
|
36
|
+
return c.json(errorResponse, errorResponse.error.status || 500);
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
}
|
|
@@ -5,6 +5,7 @@ import { registerAgentsRoute } from './agents.ts';
|
|
|
5
5
|
import { registerProvidersRoute } from './providers.ts';
|
|
6
6
|
import { registerModelsRoutes } from './models.ts';
|
|
7
7
|
import { registerDefaultsRoute } from './defaults.ts';
|
|
8
|
+
import { registerDebugConfigRoute } from './debug.ts';
|
|
8
9
|
|
|
9
10
|
export function registerConfigRoutes(app: Hono) {
|
|
10
11
|
registerCwdRoute(app);
|
|
@@ -13,4 +14,5 @@ export function registerConfigRoutes(app: Hono) {
|
|
|
13
14
|
registerProvidersRoute(app);
|
|
14
15
|
registerModelsRoutes(app);
|
|
15
16
|
registerDefaultsRoute(app);
|
|
17
|
+
registerDebugConfigRoute(app);
|
|
16
18
|
}
|
|
@@ -9,7 +9,6 @@ import { readdir } from 'node:fs/promises';
|
|
|
9
9
|
import { join } from 'node:path';
|
|
10
10
|
import type { EmbeddedAppConfig } from '../../index.ts';
|
|
11
11
|
import type { OttoConfig } from '@ottocode/sdk';
|
|
12
|
-
import { logger } from '@ottocode/sdk';
|
|
13
12
|
import { loadAgentsConfig } from '../../runtime/agent/registry.ts';
|
|
14
13
|
|
|
15
14
|
export async function isProviderAuthorizedHybrid(
|
|
@@ -83,11 +82,7 @@ export async function discoverAllAgents(
|
|
|
83
82
|
agentSet.add(agentName);
|
|
84
83
|
}
|
|
85
84
|
}
|
|
86
|
-
} catch
|
|
87
|
-
logger.debug('Failed to load agents.json', {
|
|
88
|
-
error: err instanceof Error ? err.message : String(err),
|
|
89
|
-
});
|
|
90
|
-
}
|
|
85
|
+
} catch {}
|
|
91
86
|
|
|
92
87
|
try {
|
|
93
88
|
const localAgentsPath = join(projectRoot, '.otto', 'agents');
|
|
@@ -100,11 +95,7 @@ export async function discoverAllAgents(
|
|
|
100
95
|
}
|
|
101
96
|
}
|
|
102
97
|
}
|
|
103
|
-
} catch
|
|
104
|
-
logger.debug('Failed to read local agents directory', {
|
|
105
|
-
error: err instanceof Error ? err.message : String(err),
|
|
106
|
-
});
|
|
107
|
-
}
|
|
98
|
+
} catch {}
|
|
108
99
|
|
|
109
100
|
try {
|
|
110
101
|
const globalAgentsPath = getGlobalAgentsDir();
|
|
@@ -117,11 +108,7 @@ export async function discoverAllAgents(
|
|
|
117
108
|
}
|
|
118
109
|
}
|
|
119
110
|
}
|
|
120
|
-
} catch
|
|
121
|
-
logger.debug('Failed to read global agents directory', {
|
|
122
|
-
error: err instanceof Error ? err.message : String(err),
|
|
123
|
-
});
|
|
124
|
-
}
|
|
111
|
+
} catch {}
|
|
125
112
|
|
|
126
113
|
return Array.from(agentSet).sort();
|
|
127
114
|
}
|
package/src/routes/git/commit.ts
CHANGED
|
@@ -10,7 +10,6 @@ import { sessions } from '@ottocode/database/schema';
|
|
|
10
10
|
import { gitCommitSchema, gitGenerateCommitMessageSchema } from './schemas.ts';
|
|
11
11
|
import { validateAndGetGitRoot, parseGitStatus } from './utils.ts';
|
|
12
12
|
import { resolveModel } from '../../runtime/provider/index.ts';
|
|
13
|
-
import { debugLog } from '../../runtime/debug/index.ts';
|
|
14
13
|
import {
|
|
15
14
|
detectOAuth,
|
|
16
15
|
adaptSimpleCall,
|
|
@@ -168,7 +167,6 @@ Commit message:`;
|
|
|
168
167
|
});
|
|
169
168
|
|
|
170
169
|
if (adapted.forceStream) {
|
|
171
|
-
debugLog('[COMMIT] Using streamText for OpenAI OAuth');
|
|
172
170
|
const result = streamText({
|
|
173
171
|
model,
|
|
174
172
|
system: adapted.system,
|
|
@@ -180,7 +178,6 @@ Commit message:`;
|
|
|
180
178
|
text += chunk;
|
|
181
179
|
}
|
|
182
180
|
const message = text.trim();
|
|
183
|
-
debugLog(`[COMMIT] OAuth result: "${message.slice(0, 80)}..."`);
|
|
184
181
|
return c.json({ status: 'ok', data: { message } });
|
|
185
182
|
}
|
|
186
183
|
|
package/src/routes/terminals.ts
CHANGED
|
@@ -18,9 +18,7 @@ export function registerTerminalsRoutes(
|
|
|
18
18
|
|
|
19
19
|
app.post('/v1/terminals', async (c) => {
|
|
20
20
|
try {
|
|
21
|
-
logger.debug('POST /v1/terminals called');
|
|
22
21
|
const body = await c.req.json();
|
|
23
|
-
logger.debug('Creating terminal request received', body);
|
|
24
22
|
const { command, args, purpose, cwd, title } = body;
|
|
25
23
|
|
|
26
24
|
if (!command || !purpose) {
|
|
@@ -36,13 +34,6 @@ export function registerTerminalsRoutes(
|
|
|
36
34
|
}
|
|
37
35
|
const resolvedCwd = cwd || process.cwd();
|
|
38
36
|
|
|
39
|
-
logger.debug('Creating terminal', {
|
|
40
|
-
command: resolvedCommand,
|
|
41
|
-
args,
|
|
42
|
-
purpose,
|
|
43
|
-
cwd: resolvedCwd,
|
|
44
|
-
});
|
|
45
|
-
|
|
46
37
|
const terminal = terminalManager.create({
|
|
47
38
|
command: resolvedCommand,
|
|
48
39
|
args: args || [],
|
|
@@ -52,8 +43,6 @@ export function registerTerminalsRoutes(
|
|
|
52
43
|
title,
|
|
53
44
|
});
|
|
54
45
|
|
|
55
|
-
logger.debug('Terminal created successfully', { id: terminal.id });
|
|
56
|
-
|
|
57
46
|
return c.json({
|
|
58
47
|
terminalId: terminal.id,
|
|
59
48
|
pid: terminal.pid,
|
|
@@ -80,25 +69,18 @@ export function registerTerminalsRoutes(
|
|
|
80
69
|
|
|
81
70
|
const handleTerminalOutput = async (c: Context) => {
|
|
82
71
|
const id = c.req.param('id');
|
|
83
|
-
logger.debug('SSE client connecting to terminal', { id });
|
|
84
72
|
const terminal = terminalManager.get(id);
|
|
85
73
|
|
|
86
74
|
if (!terminal) {
|
|
87
|
-
logger.debug('SSE terminal not found', { id });
|
|
88
75
|
return c.json({ error: 'Terminal not found' }, 404);
|
|
89
76
|
}
|
|
90
77
|
|
|
91
78
|
const activeTerminal = terminal;
|
|
92
79
|
|
|
93
80
|
return streamSSE(c, async (stream) => {
|
|
94
|
-
logger.debug('SSE stream started for terminal', { id });
|
|
95
81
|
const skipHistory = c.req.query('skipHistory') === 'true';
|
|
96
82
|
if (!skipHistory) {
|
|
97
83
|
const history = activeTerminal.read();
|
|
98
|
-
logger.debug('SSE sending terminal history', {
|
|
99
|
-
id,
|
|
100
|
-
lines: history.length,
|
|
101
|
-
});
|
|
102
84
|
for (const line of history) {
|
|
103
85
|
await stream.write(
|
|
104
86
|
`data: ${JSON.stringify({ type: 'data', line })}\n\n`,
|
|
@@ -155,9 +137,6 @@ export function registerTerminalsRoutes(
|
|
|
155
137
|
}
|
|
156
138
|
|
|
157
139
|
function onAbort() {
|
|
158
|
-
logger.debug('SSE client disconnected from terminal', {
|
|
159
|
-
id: activeTerminal.id,
|
|
160
|
-
});
|
|
161
140
|
stream.close();
|
|
162
141
|
finish();
|
|
163
142
|
}
|
package/src/routes/tunnel.ts
CHANGED
|
@@ -47,8 +47,6 @@ export function registerTunnelRoutes(app: Hono) {
|
|
|
47
47
|
port = getServerPort() || 9100;
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
logger.debug('Starting tunnel on port:', port);
|
|
51
|
-
|
|
52
50
|
// Kill any stale tunnel processes first
|
|
53
51
|
await killStaleTunnels();
|
|
54
52
|
|
|
@@ -60,7 +58,6 @@ export function registerTunnelRoutes(app: Hono) {
|
|
|
60
58
|
|
|
61
59
|
const url = await activeTunnel.start(port, (msg) => {
|
|
62
60
|
progressMessage = msg;
|
|
63
|
-
logger.debug('Tunnel progress', { message: msg });
|
|
64
61
|
});
|
|
65
62
|
|
|
66
63
|
tunnelUrl = url;
|
|
@@ -109,8 +106,6 @@ export function registerTunnelRoutes(app: Hono) {
|
|
|
109
106
|
tunnelError = null;
|
|
110
107
|
progressMessage = null;
|
|
111
108
|
|
|
112
|
-
logger.debug('External tunnel registered:', url);
|
|
113
|
-
|
|
114
109
|
return c.json({
|
|
115
110
|
ok: true,
|
|
116
111
|
url: tunnelUrl,
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type { Tool } from 'ai';
|
|
2
|
-
import { debugLog } from '../debug/index.ts';
|
|
3
2
|
|
|
4
3
|
export interface MCPPrepareStepState {
|
|
5
4
|
mcpToolsRecord: Record<string, Tool>;
|
|
@@ -57,12 +56,7 @@ export function buildPrepareStep(state: MCPPrepareStepState) {
|
|
|
57
56
|
}
|
|
58
57
|
|
|
59
58
|
const activeTools = [...state.baseToolNames, ...state.loadedMCPTools];
|
|
60
|
-
|
|
61
|
-
if (state.loadedMCPTools.size > 0) {
|
|
62
|
-
debugLog(
|
|
63
|
-
`[MCP prepareStep] step=${stepNumber}, active MCP tools: ${[...state.loadedMCPTools].join(', ')}`,
|
|
64
|
-
);
|
|
65
|
-
}
|
|
59
|
+
void stepNumber;
|
|
66
60
|
|
|
67
61
|
return { activeTools };
|
|
68
62
|
};
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { getGlobalAgentsJsonPath, getGlobalAgentsDir } from '@ottocode/sdk';
|
|
2
|
-
import { debugLog } from '../debug/index.ts';
|
|
3
2
|
import type { ProviderName } from '@ottocode/sdk';
|
|
4
3
|
import { catalog } from '@ottocode/sdk';
|
|
5
4
|
// Embed default agent prompts; only user overrides read from disk.
|
|
@@ -334,13 +333,7 @@ export async function resolveAgentConfig(
|
|
|
334
333
|
const deduped = Array.from(new Set([...tools, ...baseToolSet]));
|
|
335
334
|
const provider = normalizeProvider(entry?.provider);
|
|
336
335
|
const model = normalizeModel(entry?.model);
|
|
337
|
-
|
|
338
|
-
debugLog(
|
|
339
|
-
`[agent] ${name} prompt summary: ${JSON.stringify({
|
|
340
|
-
length: prompt.length,
|
|
341
|
-
lines: prompt.split('\n').length,
|
|
342
|
-
})}`,
|
|
343
|
-
);
|
|
336
|
+
void promptSource;
|
|
344
337
|
return {
|
|
345
338
|
name,
|
|
346
339
|
prompt,
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
import { loadConfig } from '@ottocode/sdk';
|
|
1
|
+
import { loadConfig, logger, getSessionSystemPromptPath } from '@ottocode/sdk';
|
|
2
2
|
import { wrapLanguageModel } from 'ai';
|
|
3
3
|
import { devToolsMiddleware } from '@ai-sdk/devtools';
|
|
4
4
|
import { getDb } from '@ottocode/database';
|
|
5
5
|
import { sessions } from '@ottocode/database/schema';
|
|
6
6
|
import { eq } from 'drizzle-orm';
|
|
7
|
+
import { mkdir } from 'node:fs/promises';
|
|
8
|
+
import { dirname } from 'node:path';
|
|
7
9
|
import { resolveModel } from '../provider/index.ts';
|
|
8
10
|
import { resolveAgentConfig } from './registry.ts';
|
|
9
11
|
import { composeSystemPrompt } from '../prompt/builder.ts';
|
|
@@ -11,7 +13,7 @@ import { discoverProjectTools } from '@ottocode/sdk';
|
|
|
11
13
|
import type { Tool } from 'ai';
|
|
12
14
|
import { adaptTools } from '../../tools/adapter.ts';
|
|
13
15
|
import { buildDatabaseTools } from '../../tools/database/index.ts';
|
|
14
|
-
import {
|
|
16
|
+
import { time } from '../debug/index.ts';
|
|
15
17
|
import { isDevtoolsEnabled } from '../debug/state.ts';
|
|
16
18
|
import { buildHistoryMessages } from '../message/history-builder.ts';
|
|
17
19
|
import { getMaxOutputTokens } from '../utils/token.ts';
|
|
@@ -87,7 +89,6 @@ export async function setupRunner(opts: RunOpts): Promise<SetupResult> {
|
|
|
87
89
|
const historyTimer = time('runner:buildHistory');
|
|
88
90
|
let history: Awaited<ReturnType<typeof buildHistoryMessages>>;
|
|
89
91
|
if (opts.isCompactCommand && opts.compactionContext) {
|
|
90
|
-
debugLog('[RUNNER] Using minimal history for /compact command');
|
|
91
92
|
history = [];
|
|
92
93
|
} else {
|
|
93
94
|
history = await buildHistoryMessages(
|
|
@@ -104,34 +105,14 @@ export async function setupRunner(opts: RunOpts): Promise<SetupResult> {
|
|
|
104
105
|
.where(eq(sessions.id, opts.sessionId))
|
|
105
106
|
.limit(1);
|
|
106
107
|
const contextSummary = sessionRows[0]?.contextSummary ?? undefined;
|
|
107
|
-
if (contextSummary) {
|
|
108
|
-
debugLog(
|
|
109
|
-
`[RUNNER] Using context summary from compaction (${contextSummary.length} chars)`,
|
|
110
|
-
);
|
|
111
|
-
}
|
|
112
108
|
|
|
113
109
|
const isFirstMessage = !history.some((m) => m.role === 'assistant');
|
|
114
110
|
|
|
115
|
-
debugLog(`[RUNNER] isFirstMessage: ${isFirstMessage}`);
|
|
116
|
-
debugLog(`[RUNNER] userContext provided: ${opts.userContext ? 'YES' : 'NO'}`);
|
|
117
|
-
if (opts.userContext) {
|
|
118
|
-
debugLog(
|
|
119
|
-
`[RUNNER] userContext value: ${opts.userContext.substring(0, 100)}${opts.userContext.length > 100 ? '...' : ''}`,
|
|
120
|
-
);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
111
|
const systemTimer = time('runner:composeSystemPrompt');
|
|
124
112
|
const { getAuth } = await import('@ottocode/sdk');
|
|
125
113
|
const auth = await getAuth(opts.provider, cfg.projectRoot);
|
|
126
114
|
const oauth = detectOAuth(opts.provider, auth);
|
|
127
115
|
|
|
128
|
-
debugLog(
|
|
129
|
-
`[RUNNER] needsSpoof (OAuth): ${oauth.needsSpoof}, isOpenAIOAuth: ${oauth.isOpenAIOAuth}`,
|
|
130
|
-
);
|
|
131
|
-
debugLog(
|
|
132
|
-
`[RUNNER] spoofPrompt: ${oauth.spoofPrompt ? `present (${opts.provider})` : 'none'}`,
|
|
133
|
-
);
|
|
134
|
-
|
|
135
116
|
const composed = await composeSystemPrompt({
|
|
136
117
|
provider: opts.provider,
|
|
137
118
|
model: opts.model,
|
|
@@ -154,16 +135,78 @@ export async function setupRunner(opts: RunOpts): Promise<SetupResult> {
|
|
|
154
135
|
|
|
155
136
|
const { system } = adapted;
|
|
156
137
|
const { systemComponents, additionalSystemMessages } = adapted;
|
|
138
|
+
const openAIProviderOptions = adapted.providerOptions.openai as
|
|
139
|
+
| Record<string, unknown>
|
|
140
|
+
| undefined;
|
|
141
|
+
const openAIInstructions =
|
|
142
|
+
typeof openAIProviderOptions?.instructions === 'string'
|
|
143
|
+
? openAIProviderOptions.instructions
|
|
144
|
+
: '';
|
|
145
|
+
const effectiveSystemPrompt = system || openAIInstructions || composed.prompt;
|
|
146
|
+
const promptMode = oauth.isOpenAIOAuth
|
|
147
|
+
? 'openai-oauth'
|
|
148
|
+
: oauth.needsSpoof
|
|
149
|
+
? 'spoof'
|
|
150
|
+
: 'standard';
|
|
157
151
|
systemTimer.end();
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
152
|
+
logger.debug('[prompt] system prompt assembled', {
|
|
153
|
+
sessionId: opts.sessionId,
|
|
154
|
+
messageId: opts.assistantMessageId,
|
|
155
|
+
agent: opts.agent,
|
|
156
|
+
provider: opts.provider,
|
|
157
|
+
model: opts.model,
|
|
158
|
+
promptMode,
|
|
159
|
+
components: systemComponents,
|
|
160
|
+
systemLength: effectiveSystemPrompt.length,
|
|
161
|
+
historyMessages: history.length,
|
|
162
|
+
additionalSystemMessages: additionalSystemMessages.length,
|
|
163
|
+
isFirstMessage,
|
|
164
|
+
isOpenAIOAuth: oauth.isOpenAIOAuth,
|
|
165
|
+
needsSpoof: oauth.needsSpoof,
|
|
166
|
+
});
|
|
167
|
+
logger.debug('[prompt] detailed prompt context', {
|
|
168
|
+
sessionId: opts.sessionId,
|
|
169
|
+
messageId: opts.assistantMessageId,
|
|
170
|
+
debugDetail: true,
|
|
171
|
+
agentPromptLength: agentPrompt.length,
|
|
172
|
+
contextSummaryLength: contextSummary?.length ?? 0,
|
|
173
|
+
userContextLength: opts.userContext?.length ?? 0,
|
|
174
|
+
oneShot: Boolean(opts.oneShot),
|
|
175
|
+
guidedMode: Boolean(cfg.defaults.guidedMode),
|
|
176
|
+
isOpenAIOAuth: oauth.isOpenAIOAuth,
|
|
177
|
+
needsSpoof: oauth.needsSpoof,
|
|
178
|
+
promptMode,
|
|
179
|
+
rawSystemLength: system.length,
|
|
180
|
+
openAIInstructionsLength: openAIInstructions.length,
|
|
181
|
+
effectiveSystemPromptLength: effectiveSystemPrompt.length,
|
|
182
|
+
systemComponents,
|
|
183
|
+
additionalSystemMessageRoles: additionalSystemMessages.map(
|
|
184
|
+
(message) => message.role,
|
|
185
|
+
),
|
|
186
|
+
});
|
|
187
|
+
if (effectiveSystemPrompt) {
|
|
188
|
+
const systemPromptPath = getSessionSystemPromptPath(opts.sessionId);
|
|
189
|
+
try {
|
|
190
|
+
await mkdir(dirname(systemPromptPath), { recursive: true });
|
|
191
|
+
await Bun.write(systemPromptPath, effectiveSystemPrompt);
|
|
192
|
+
logger.debug('[prompt] wrote system prompt file', {
|
|
193
|
+
sessionId: opts.sessionId,
|
|
194
|
+
messageId: opts.assistantMessageId,
|
|
195
|
+
path: systemPromptPath,
|
|
196
|
+
debugDetail: true,
|
|
197
|
+
promptMode,
|
|
198
|
+
effectiveSystemPromptLength: effectiveSystemPrompt.length,
|
|
199
|
+
});
|
|
200
|
+
} catch (error) {
|
|
201
|
+
logger.warn('[prompt] failed to write system prompt file', {
|
|
202
|
+
sessionId: opts.sessionId,
|
|
203
|
+
messageId: opts.assistantMessageId,
|
|
204
|
+
error: error instanceof Error ? error.message : String(error),
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
}
|
|
164
208
|
|
|
165
209
|
if (opts.isCompactCommand && opts.compactionContext) {
|
|
166
|
-
debugLog('[RUNNER] Injecting compaction context for /compact command');
|
|
167
210
|
const compactPrompt = getCompactionSystemPrompt();
|
|
168
211
|
additionalSystemMessages.push({
|
|
169
212
|
role: 'system',
|
|
@@ -188,9 +231,6 @@ export async function setupRunner(opts: RunOpts): Promise<SetupResult> {
|
|
|
188
231
|
for (const dt of dbTools) {
|
|
189
232
|
discovered.tools.push(dt);
|
|
190
233
|
}
|
|
191
|
-
debugLog(
|
|
192
|
-
`[tools] Added ${dbTools.length} database tools for research agent (parent: ${parentSessionId ?? 'none'})`,
|
|
193
|
-
);
|
|
194
234
|
}
|
|
195
235
|
|
|
196
236
|
toolsTimer.end({
|
|
@@ -200,12 +240,6 @@ export async function setupRunner(opts: RunOpts): Promise<SetupResult> {
|
|
|
200
240
|
const gated = allTools.filter(
|
|
201
241
|
(tool) => allowedNames.has(tool.name) || tool.name === 'load_mcp_tools',
|
|
202
242
|
);
|
|
203
|
-
debugLog(
|
|
204
|
-
`[tools] ${gated.length} gated tools, ${Object.keys(mcpToolsRecord).length} lazy MCP tools`,
|
|
205
|
-
);
|
|
206
|
-
|
|
207
|
-
debugLog(`[RUNNER] About to create model with provider: ${opts.provider}`);
|
|
208
|
-
debugLog(`[RUNNER] About to create model ID: ${opts.model}`);
|
|
209
243
|
|
|
210
244
|
const model = await resolveModel(opts.provider, opts.model, cfg, {
|
|
211
245
|
sessionId: opts.sessionId,
|
|
@@ -218,12 +252,8 @@ export async function setupRunner(opts: RunOpts): Promise<SetupResult> {
|
|
|
218
252
|
middleware: devToolsMiddleware(),
|
|
219
253
|
})
|
|
220
254
|
: model;
|
|
221
|
-
debugLog(
|
|
222
|
-
`[RUNNER] Model created: ${JSON.stringify({ id: model.modelId, provider: model.provider })}`,
|
|
223
|
-
);
|
|
224
255
|
|
|
225
256
|
const maxOutputTokens = adapted.maxOutputTokens;
|
|
226
|
-
debugLog(`[RUNNER] maxOutputTokens for ${opts.model}: ${maxOutputTokens}`);
|
|
227
257
|
|
|
228
258
|
const { sharedCtx, firstToolTimer, firstToolSeen } = await setupToolContext(
|
|
229
259
|
opts,
|
|
@@ -253,12 +283,6 @@ export async function setupRunner(opts: RunOpts): Promise<SetupResult> {
|
|
|
253
283
|
});
|
|
254
284
|
mergeProviderOptions(providerOptions, reasoningConfig.providerOptions);
|
|
255
285
|
effectiveMaxOutputTokens = reasoningConfig.effectiveMaxOutputTokens;
|
|
256
|
-
debugLog(
|
|
257
|
-
`[RUNNER] reasoning enabled for ${opts.provider}/${opts.model}: ${reasoningConfig.enabled}, level: ${opts.reasoningLevel ?? 'default'}`,
|
|
258
|
-
);
|
|
259
|
-
debugLog(
|
|
260
|
-
`[RUNNER] final providerOptions: ${JSON.stringify(providerOptions)}`,
|
|
261
|
-
);
|
|
262
286
|
|
|
263
287
|
return {
|
|
264
288
|
cfg,
|